1use std::cmp::Ordering;
4
5use rupg_common::{Error, Result, SqlState};
6use rupg_pgcatalog::builtin;
7use rupg_types::{RANGE_LB_INC, RANGE_LB_INF, RANGE_UB_INC, RANGE_UB_INF, Range, Value};
8
9use crate::io::base_type;
10use crate::range::{
11 Bound, adjacent, before, bounds, bounds_adjacent, cmp_bounds, contains, contains_elem,
12 intersect, make_range, minus, over_left, overlaps, range_order, split, subtype, union,
13};
14use crate::{Call, Kernel, bad_value};
15
16pub(crate) fn range_of(multirange: u32) -> u32 {
18 builtin::multirange_range(base_type(multirange)).unwrap_or(0)
19}
20
21pub(crate) fn make_multirange(range: u32, mut ranges: Vec<Range>) -> Result<Vec<Range>> {
27 let sub = subtype(range);
28 let mut failed = None;
29 ranges.sort_by(|a, b| {
30 range_order(sub, a, b).unwrap_or_else(|error| {
31 failed.get_or_insert(error);
32 Ordering::Equal
33 })
34 });
35 if let Some(error) = failed {
36 return Err(error);
37 }
38 let mut out: Vec<Range> = Vec::with_capacity(ranges.len());
39 for current in ranges {
40 if current.is_empty() {
41 continue;
42 }
43 let Some(last) = out.last_mut() else {
44 out.push(current);
45 continue;
46 };
47 if adjacent(range, last, ¤t)? {
48 *last = union(range, last, ¤t, false)?;
49 } else if before(range, last, ¤t)? {
50 out.push(current);
51 } else {
52 *last = union(range, last, ¤t, true)?;
53 }
54 }
55 Ok(out)
56}
57
58pub fn range_agg(multirange: u32, ranges: Vec<Range>) -> Result<Value> {
64 if ranges.is_empty() {
65 return Ok(Value::Null);
66 }
67 Ok(Value::Multirange(make_multirange(range_of(multirange), ranges)?))
68}
69
70pub(crate) fn multirange_order(sub: u32, a: &[Range], b: &[Range]) -> Result<Ordering> {
72 for (x, y) in a.iter().zip(b) {
73 let order = range_order(sub, x, y)?;
74 if order.is_ne() {
75 return Ok(order);
76 }
77 }
78 Ok(a.len().cmp(&b.len()))
79}
80
81fn arg(args: &[Value]) -> Result<&[Range]> {
83 match args.first() {
84 Some(Value::Multirange(ranges)) => Ok(ranges),
85 _ => Err(bad_value()),
86 }
87}
88
89fn constructor0(_: &Call<'_>, _: &[Value]) -> Result<Value> {
91 Ok(Value::Multirange(Vec::new()))
92}
93
94fn constructor1(call: &Call<'_>, args: &[Value]) -> Result<Value> {
96 let [Value::Range(range)] = args else { return Err(bad_value()) };
97 Ok(Value::Multirange(make_multirange(range_of(call.ret), vec![(**range).clone()])?))
98}
99
100fn constructor2(call: &Call<'_>, args: &[Value]) -> Result<Value> {
102 let [Value::Array(array)] = args else { return Err(bad_value()) };
103 if array.dims.len() > 1 {
104 return Err(Error::new(
105 SqlState::CARDINALITY_VIOLATION,
106 "multiranges cannot be constructed from multidimensional arrays",
107 ));
108 }
109 let ranges = array
110 .values
111 .iter()
112 .map(|value| match value {
113 Some(Value::Range(range)) => Ok((**range).clone()),
114 Some(_) => Err(bad_value()),
115 None => Err(Error::new(
116 SqlState::NULL_VALUE_NOT_ALLOWED,
117 "multirange values cannot contain null members",
118 )),
119 })
120 .collect::<Result<Vec<_>>>()?;
121 Ok(Value::Multirange(make_multirange(range_of(call.ret), ranges)?))
122}
123
124fn lower(_: &Call<'_>, args: &[Value]) -> Result<Value> {
126 Ok(arg(args)?.first().map_or(Value::Null, |range| range.lower.clone()))
127}
128
129fn upper(_: &Call<'_>, args: &[Value]) -> Result<Value> {
131 Ok(arg(args)?.last().map_or(Value::Null, |range| range.upper.clone()))
132}
133
134fn is_empty(_: &Call<'_>, args: &[Value]) -> Result<Value> {
136 Ok(Value::Bool(arg(args)?.is_empty()))
137}
138
139macro_rules! flag_test {
141 ($name:ident, $end:ident, $flag:expr, $doc:literal) => {
142 #[doc = $doc]
143 fn $name(_: &Call<'_>, args: &[Value]) -> Result<Value> {
144 Ok(Value::Bool(arg(args)?.$end().is_some_and(|range| range.flags & $flag != 0)))
145 }
146 };
147}
148
149flag_test!(
150 lower_inc,
151 first,
152 RANGE_LB_INC,
153 "`multirange_lower_inc`: true when the lower bound is part of the multirange."
154);
155flag_test!(
156 upper_inc,
157 last,
158 RANGE_UB_INC,
159 "`multirange_upper_inc`: true when the upper bound is part of the multirange."
160);
161flag_test!(
162 lower_inf,
163 first,
164 RANGE_LB_INF,
165 "`multirange_lower_inf`: true when the multirange has no lower bound."
166);
167flag_test!(
168 upper_inf,
169 last,
170 RANGE_UB_INF,
171 "`multirange_upper_inf`: true when the multirange has no upper bound."
172);
173
174fn merge(call: &Call<'_>, args: &[Value]) -> Result<Value> {
176 let ranges = arg(args)?;
177 let range = match ranges {
178 [] => Range::empty(),
179 [one] => one.clone(),
180 [first, .., last] => {
181 let flags = (first.flags & (RANGE_LB_INC | RANGE_LB_INF))
182 | (last.flags & (RANGE_UB_INC | RANGE_UB_INF));
183 make_range(call.ret, flags, first.lower.clone(), last.upper.clone())?
184 }
185 };
186 Ok(Value::Range(Box::new(range)))
187}
188
189pub(crate) fn unnest(_: &Call<'_>, args: &[Value]) -> Result<Vec<Vec<Value>>> {
191 Ok(arg(args)?.iter().map(|range| vec![Value::Range(Box::new(range.clone()))]).collect())
192}
193
194fn call_range(call: &Call<'_>) -> u32 {
196 let types = || call.args.iter().chain([&call.ret]).copied();
197 types()
198 .map(range_of)
199 .find(|&ty| ty != 0)
200 .or_else(|| types().find(|&ty| subtype(ty) != 0))
201 .unwrap_or(0)
202}
203
204fn ranges_of(value: &Value) -> Result<&[Range]> {
206 match value {
207 Value::Multirange(ranges) => Ok(ranges),
208 Value::Range(range) if range.is_empty() => Ok(&[]),
209 Value::Range(range) => Ok(std::slice::from_ref(&**range)),
210 _ => Err(bad_value()),
211 }
212}
213
214fn span(ranges: &[Range]) -> Option<(Bound<'_>, Bound<'_>)> {
216 let (first, last) = (ranges.first()?, ranges.last()?);
217 Some((bounds(first).0, bounds(last).1))
218}
219
220fn overlaps_all(range: u32, a: &[Range], b: &[Range]) -> Result<bool> {
222 let sub = subtype(range);
223 let (mut i, mut j) = (0, 0);
224 while let (Some(x), Some(y)) = (a.get(i), b.get(j)) {
225 if overlaps(range, x, y)? {
226 return Ok(true);
227 }
228 if cmp_bounds(sub, &bounds(x).1, &bounds(y).1)?.is_lt() {
229 i += 1;
230 } else {
231 j += 1;
232 }
233 }
234 Ok(false)
235}
236
237fn contains_all(range: u32, a: &[Range], b: &[Range]) -> Result<bool> {
239 let sub = subtype(range);
240 let mut i = 0;
241 for y in b {
242 let lower = bounds(y).0;
243 loop {
244 let Some(x) = a.get(i) else { return Ok(false) };
245 if cmp_bounds(sub, &bounds(x).1, &lower)?.is_ge() {
246 break;
247 }
248 i += 1;
249 }
250 if !contains(range, &a[i], y)? {
251 return Ok(false);
252 }
253 }
254 Ok(true)
255}
256
257macro_rules! position {
259 ($name:ident, $doc:literal, |$sub:pat, $range:ident, $a:ident, $b:ident| $test:expr) => {
260 #[doc = $doc]
261 fn $name(call: &Call<'_>, args: &[Value]) -> Result<Value> {
262 let [a, b] = args else { return Err(bad_value()) };
263 let $range = call_range(call);
264 let $sub = subtype($range);
265 let (Some($a), Some($b)) = (span(ranges_of(a)?), span(ranges_of(b)?)) else {
266 return Ok(Value::Bool(false));
267 };
268 Ok(Value::Bool($test))
269 }
270 };
271}
272
273position!(
274 before_op,
275 "`<<`: true when the upper bound of the left side is before the lower bound of the right side.",
276 |sub, range, a, b| cmp_bounds(sub, &a.1, &b.0)?.is_lt()
277);
278position!(
279 after_op,
280 "`>>`: true when the lower bound of the left side is after the upper bound of the right side.",
281 |sub, range, a, b| cmp_bounds(sub, &a.0, &b.1)?.is_gt()
282);
283position!(
284 over_left_op,
285 "`&<`: true when the left side does not go to the right of the right side.",
286 |sub, range, a, b| cmp_bounds(sub, &a.1, &b.1)?.is_le()
287);
288position!(
289 over_right_op,
290 "`&>`: true when the left side does not go to the left of the right side.",
291 |sub, range, a, b| cmp_bounds(sub, &a.0, &b.0)?.is_ge()
292);
293position!(
294 adjacent_op,
295 "`-|-`: true when the upper bound of one side touches the lower bound of the other side. Only the outer bounds count, as in PostgreSQL.",
296 |_, range, a, b| bounds_adjacent(range, &a.1, &b.0)? || bounds_adjacent(range, &b.1, &a.0)?
297);
298
299fn overlaps_op(call: &Call<'_>, args: &[Value]) -> Result<Value> {
301 let [a, b] = args else { return Err(bad_value()) };
302 Ok(Value::Bool(overlaps_all(call_range(call), ranges_of(a)?, ranges_of(b)?)?))
303}
304
305fn contains_op(call: &Call<'_>, args: &[Value]) -> Result<Value> {
307 let [a, b] = args else { return Err(bad_value()) };
308 Ok(Value::Bool(contains_all(call_range(call), ranges_of(a)?, ranges_of(b)?)?))
309}
310
311fn contained_by_op(call: &Call<'_>, args: &[Value]) -> Result<Value> {
313 let [a, b] = args else { return Err(bad_value()) };
314 Ok(Value::Bool(contains_all(call_range(call), ranges_of(b)?, ranges_of(a)?)?))
315}
316
317fn contains_value(range: u32, ranges: &[Range], value: &Value) -> Result<bool> {
319 let sub = subtype(range);
320 for x in ranges {
321 if contains_elem(sub, x, value)? {
322 return Ok(true);
323 }
324 }
325 Ok(false)
326}
327
328fn contains_elem_op(call: &Call<'_>, args: &[Value]) -> Result<Value> {
330 let [a, value] = args else { return Err(bad_value()) };
331 Ok(Value::Bool(contains_value(call_range(call), ranges_of(a)?, value)?))
332}
333
334fn elem_contained_op(call: &Call<'_>, args: &[Value]) -> Result<Value> {
336 let [value, a] = args else { return Err(bad_value()) };
337 Ok(Value::Bool(contains_value(call_range(call), ranges_of(a)?, value)?))
338}
339
340fn pair(args: &[Value]) -> Result<(&[Range], &[Range])> {
342 match args {
343 [Value::Multirange(a), Value::Multirange(b)] => Ok((a, b)),
344 _ => Err(bad_value()),
345 }
346}
347
348fn union_op(call: &Call<'_>, args: &[Value]) -> Result<Value> {
350 let (a, b) = pair(args)?;
351 if a.is_empty() || b.is_empty() {
352 return Ok(Value::Multirange(if a.is_empty() { b } else { a }.to_vec()));
353 }
354 Ok(Value::Multirange(make_multirange(call_range(call), [a, b].concat())?))
355}
356
357fn minus_all(range: u32, a: &[Range], b: &[Range]) -> Result<Vec<Range>> {
359 let mut out = Vec::with_capacity(a.len() + b.len());
360 let mut j = 0;
361 for x in a {
362 let mut x = x.clone();
363 while let Some(y) = b.get(j)
364 && before(range, y, &x)?
365 {
366 j += 1;
367 }
368 while let Some(y) = b.get(j) {
369 if let Some((left, right)) = split(range, &x, y)? {
370 out.push(left);
371 x = right;
372 j += 1;
373 } else if overlaps(range, &x, y)? {
374 x = minus(range, &x, y)?;
375 if x.is_empty() || before(range, &x, y)? {
376 break;
377 }
378 j += 1;
379 } else {
380 break;
381 }
382 }
383 out.push(x);
384 }
385 make_multirange(range, out)
386}
387
388fn minus_op(call: &Call<'_>, args: &[Value]) -> Result<Value> {
390 let (a, b) = pair(args)?;
391 if a.is_empty() || b.is_empty() {
392 return Ok(Value::Multirange(a.to_vec()));
393 }
394 Ok(Value::Multirange(minus_all(call_range(call), a, b)?))
395}
396
397pub(crate) fn minus_multi(call: &Call<'_>, args: &[Value]) -> Result<Vec<Vec<Value>>> {
399 let (a, b) = pair(args)?;
400 let out =
401 if a.is_empty() || b.is_empty() { a.to_vec() } else { minus_all(call_range(call), a, b)? };
402 Ok(if out.is_empty() { Vec::new() } else { vec![vec![Value::Multirange(out)]] })
403}
404
405fn intersect_all(range: u32, a: &[Range], b: &[Range]) -> Result<Vec<Range>> {
407 let mut out = Vec::new();
408 let mut j = 0;
409 for x in a {
410 while let Some(y) = b.get(j)
411 && before(range, y, x)?
412 {
413 j += 1;
414 }
415 while let Some(y) = b.get(j) {
416 if !overlaps(range, x, y)? {
417 break;
418 }
419 out.push(intersect(range, x, y)?);
420 if !over_left(range, y, x)? {
421 break;
422 }
423 j += 1;
424 }
425 if j >= b.len() {
426 break;
427 }
428 }
429 make_multirange(range, out)
430}
431
432fn intersect_op(call: &Call<'_>, args: &[Value]) -> Result<Value> {
434 let (a, b) = pair(args)?;
435 if a.is_empty() || b.is_empty() {
436 return Ok(Value::Multirange(Vec::new()));
437 }
438 Ok(Value::Multirange(intersect_all(call_range(call), a, b)?))
439}
440
441pub(crate) fn by_src(src: &str) -> Option<Kernel> {
443 Some(match src {
444 "multirange_constructor0" => constructor0,
445 "multirange_constructor1" => constructor1,
446 "multirange_constructor2" => constructor2,
447 "multirange_lower" => lower,
448 "multirange_upper" => upper,
449 "multirange_empty" => is_empty,
450 "multirange_lower_inc" => lower_inc,
451 "multirange_upper_inc" => upper_inc,
452 "multirange_lower_inf" => lower_inf,
453 "multirange_upper_inf" => upper_inf,
454 "range_merge_from_multirange" => merge,
455 "multirange_union" => union_op,
456 "multirange_minus" => minus_op,
457 "multirange_intersect" | "multirange_intersect_agg_transfn" => intersect_op,
458 "range_overlaps_multirange"
459 | "multirange_overlaps_range"
460 | "multirange_overlaps_multirange" => overlaps_op,
461 "multirange_contains_range"
462 | "range_contains_multirange"
463 | "multirange_contains_multirange" => contains_op,
464 "range_contained_by_multirange"
465 | "multirange_contained_by_range"
466 | "multirange_contained_by_multirange" => contained_by_op,
467 "multirange_contains_elem" => contains_elem_op,
468 "elem_contained_by_multirange" => elem_contained_op,
469 "range_before_multirange" | "multirange_before_range" | "multirange_before_multirange" => {
470 before_op
471 }
472 "range_after_multirange" | "multirange_after_range" | "multirange_after_multirange" => {
473 after_op
474 }
475 "range_overleft_multirange"
476 | "multirange_overleft_range"
477 | "multirange_overleft_multirange" => over_left_op,
478 "range_adjacent_multirange"
479 | "multirange_adjacent_range"
480 | "multirange_adjacent_multirange" => adjacent_op,
481 _ if src.contains("multirange") && src.contains(concat!("over", "right")) => over_right_op,
483 _ => return None,
484 })
485}
486
487#[cfg(test)]
488mod tests {
489 use rupg_types::oid;
490
491 use super::*;
492
493 fn int4(lower: i32, upper: i32) -> Range {
494 make_range(oid::INT4RANGE, RANGE_LB_INC, Value::Int4(lower), Value::Int4(upper)).unwrap()
495 }
496
497 #[test]
498 fn canonical() {
499 let ranges = vec![int4(8, 10), int4(1, 5), Range::empty(), int4(3, 7), int4(10, 12)];
500 let out = make_multirange(oid::INT4RANGE, ranges).unwrap();
501 assert_eq!(out, [int4(1, 7), int4(8, 12)]);
502 assert!(make_multirange(oid::INT4RANGE, vec![Range::empty()]).unwrap().is_empty());
503 }
504
505 #[test]
506 fn order() {
507 let one = [int4(1, 2)];
508 let two = [int4(1, 2), int4(3, 4)];
509 assert_eq!(multirange_order(oid::INT4, &one, &two).unwrap(), Ordering::Less);
510 assert_eq!(multirange_order(oid::INT4, &[], &[]).unwrap(), Ordering::Equal);
511 assert_eq!(multirange_order(oid::INT4, &[int4(2, 3)], &two).unwrap(), Ordering::Greater);
512 }
513
514 #[test]
515 fn operators() {
516 let r = oid::INT4RANGE;
517 let a = [int4(1, 5), int4(10, 20)];
518 let b = [int4(0, 2), int4(4, 11), int4(15, 16), int4(19, 30)];
519 assert_eq!(minus_all(r, &a, &b).unwrap(), [int4(2, 4), int4(11, 15), int4(16, 19)]);
520 assert_eq!(
521 intersect_all(r, &a, &b).unwrap(),
522 [int4(1, 2), int4(4, 5), int4(10, 11), int4(15, 16), int4(19, 20)]
523 );
524 assert!(overlaps_all(r, &a, &[int4(7, 12)]).unwrap());
525 assert!(!overlaps_all(r, &a, &[int4(5, 10)]).unwrap());
526 assert!(contains_all(r, &a, &[int4(2, 3), int4(12, 14)]).unwrap());
527 assert!(!contains_all(r, &a, &[int4(2, 11)]).unwrap());
528 assert!(contains_all(r, &[], &[]).unwrap());
529 }
530}