1use std::cmp::Ordering;
4
5use rupg_common::{Error, Result, SqlState};
6use rupg_pgcatalog::builtin::{self, ProcRow};
7use rupg_types::{
8 Array, DATE_INFINITY, DATE_NEGATIVE_INFINITY, POSTGRES_EPOCH_JDATE, Record, RegKind,
9 TIMESTAMP_INFINITY, TIMESTAMP_NEGATIVE_INFINITY, UNIX_TO_POSTGRES_USECS, USECS_PER_DAY,
10 USECS_PER_SEC, Value, format_type, oid,
11};
12
13use crate::cast::{TIMESTAMP_END_JULIAN, infinite, valid_timestamp};
14use crate::io::base_type;
15use crate::{Call, Kernel, bad_value, multirange, range};
16
17#[derive(Clone, Copy, Debug, PartialEq, Eq)]
19enum Family {
20 Integer,
21 Float,
22 Numeric,
23 Text,
24 Bool,
25 Char,
26 Oid,
27 Bytea,
28 Uuid,
29 Network,
30 Date,
31 Time,
32 TimeTz,
33 Timestamp,
34 TimestampTz,
35 Interval,
36 Array,
37 Money,
38 Tid,
39 Xid8,
41 Oid8,
42 Macaddr,
43 Macaddr8,
45 PgLsn,
47 Bit,
49 Range,
51 Multirange,
53 TsVector,
55 TsQuery,
57 Record,
59 Enum,
61}
62
63fn family(ty: u32) -> Option<Family> {
65 let ty = base_type(ty);
66 Some(match ty {
67 oid::INT2 | oid::INT4 | oid::INT8 => Family::Integer,
68 oid::FLOAT4 | oid::FLOAT8 => Family::Float,
69 oid::NUMERIC => Family::Numeric,
70 oid::TEXT | oid::NAME | oid::VARCHAR | oid::BPCHAR => Family::Text,
71 oid::BOOL => Family::Bool,
72 oid::CHAR => Family::Char,
73 oid::OID => Family::Oid,
74 ty if RegKind::from_oid(ty).is_some() => Family::Oid,
75 oid::BYTEA => Family::Bytea,
76 oid::UUID => Family::Uuid,
77 oid::INET | oid::CIDR => Family::Network,
78 oid::DATE => Family::Date,
79 oid::TIME => Family::Time,
80 oid::TIMETZ => Family::TimeTz,
81 oid::TIMESTAMP => Family::Timestamp,
82 oid::TIMESTAMPTZ => Family::TimestampTz,
83 oid::INTERVAL => Family::Interval,
84 oid::ANYARRAY | oid::INT2VECTOR | oid::OIDVECTOR => Family::Array,
85 oid::MONEY => Family::Money,
86 oid::TID => Family::Tid,
87 oid::XID8 => Family::Xid8,
88 oid::OID8 => Family::Oid8,
89 oid::MACADDR => Family::Macaddr,
90 oid::MACADDR8 => Family::Macaddr8,
91 oid::PG_LSN => Family::PgLsn,
92 oid::BIT | oid::VARBIT => Family::Bit,
93 oid::ANYRANGE => Family::Range,
94 ty if builtin::range_subtype(ty).is_some() => Family::Range,
95 oid::ANYMULTIRANGE => Family::Multirange,
96 ty if builtin::multirange_range(ty).is_some() => Family::Multirange,
97 oid::TSVECTOR => Family::TsVector,
98 oid::TSQUERY => Family::TsQuery,
99 oid::RECORD => Family::Record,
100 oid::ANYENUM => Family::Enum,
101 _ => match builtin::type_by_oid(ty) {
102 Some(row) if row.category == b'A' && row.elem != 0 => Family::Array,
103 Some(row) if row.kind == b'e' => Family::Enum,
104 _ => return None,
105 },
106 })
107}
108
109fn is_enum_pair(left: u32, right: u32) -> bool {
111 family(left) == Some(Family::Enum) || family(right) == Some(Family::Enum)
112}
113
114fn enum_order(x: u32, y: u32) -> Ordering {
116 match (builtin::enum_label_place(x), builtin::enum_label_place(y)) {
117 (Some(a), Some(b)) => a.cmp(&b),
118 _ => x.cmp(&y),
119 }
120}
121
122fn element(ty: u32) -> u32 {
124 builtin::type_by_oid(base_type(ty)).map_or(0, |row| row.elem)
125}
126
127pub fn compare(left: u32, a: &Value, right: u32, b: &Value) -> Result<Ordering> {
133 let trim = |ty: u32, s: &'_ str| -> usize {
134 if base_type(ty) == oid::BPCHAR { s.trim_end_matches(' ').len() } else { s.len() }
135 };
136 let unsigned =
137 |ty: u32| matches!(base_type(ty), oid::XID8 | oid::OID8 | oid::MACADDR8 | oid::PG_LSN);
138 Ok(match (a, b) {
139 (Value::Int8(x), Value::Int8(y)) if unsigned(left) && unsigned(right) => {
140 x.cast_unsigned().cmp(&y.cast_unsigned())
141 }
142 (Value::Int2(_) | Value::Int4(_) | Value::Int8(_), _) => {
143 let (Some(x), Some(y)) = (a.as_i64(), b.as_i64()) else { return Err(bad_value()) };
144 x.cmp(&y)
145 }
146 (Value::Float4(_) | Value::Float8(_), _) => {
147 let (Some(x), Some(y)) = (float(a), float(b)) else { return Err(bad_value()) };
148 float_order(x, y)
149 }
150 (Value::Numeric(x), Value::Numeric(y)) => x.compare(y),
151 (Value::Text(x), Value::Text(y)) => {
152 x.as_bytes()[..trim(left, x)].cmp(&y.as_bytes()[..trim(right, y)])
153 }
154 (Value::Bool(x), Value::Bool(y)) => x.cmp(y),
155 (Value::Char(x), Value::Char(y)) => x.cmp(y),
156 (Value::Oid(x), Value::Oid(y)) if (x | y) & 1 == 1 && is_enum_pair(left, right) => {
157 enum_order(*x, *y)
158 }
159 (Value::Oid(x), Value::Oid(y)) => x.cmp(y),
160 (Value::Bytea(x), Value::Bytea(y)) => x.cmp(y),
161 (Value::Uuid(x), Value::Uuid(y)) => x.cmp(y),
162 (Value::Inet(x), Value::Inet(y)) => rupg_types::network_cmp(x, y).cmp(&0),
163 (Value::Date(x), Value::Date(y)) => x.cmp(y),
164 (Value::Time(x), Value::Time(y))
165 | (Value::Timestamp(x), Value::Timestamp(y))
166 | (Value::TimestampTz(x), Value::TimestampTz(y)) => x.cmp(y),
167 (Value::TimeTz(t1, z1), Value::TimeTz(t2, z2)) => {
168 let utc1 = i128::from(*t1) + i128::from(*z1) * i128::from(USECS_PER_SEC);
169 let utc2 = i128::from(*t2) + i128::from(*z2) * i128::from(USECS_PER_SEC);
170 utc1.cmp(&utc2).then(z1.cmp(z2))
171 }
172 (Value::Interval(x), Value::Interval(y)) => span(x).cmp(&span(y)),
173 (Value::Array(x), Value::Array(y)) => array_order(element(left), x, element(right), y)?,
174 (Value::Range(x), Value::Range(y)) => {
175 let sub = match range::subtype(left) {
176 0 => range::subtype(right),
177 sub => sub,
178 };
179 range::range_order(sub, x, y)?
180 }
181 (Value::Multirange(x), Value::Multirange(y)) => {
182 let sub = match range::subtype(multirange::range_of(left)) {
183 0 => range::subtype(multirange::range_of(right)),
184 sub => sub,
185 };
186 multirange::multirange_order(sub, x, y)?
187 }
188 (Value::TsVector(x), Value::TsVector(y)) => rupg_types::tsvector_cmp(x, y).cmp(&0),
189 (Value::TsQuery(x), Value::TsQuery(y)) => rupg_types::tsquery_cmp(x, y).cmp(&0),
190 (Value::Record(x), Value::Record(y)) => record_order(x, y, false)?,
191 _ => return Err(bad_value()),
192 })
193}
194
195fn record_order(a: &Record, b: &Record, equality: bool) -> Result<Ordering> {
197 let columns = a.types.iter().zip(&a.values).zip(b.types.iter().zip(&b.values));
198 for (n, ((&left, x), (&right, y))) in columns.enumerate() {
199 if left != right {
200 return Err(Error::new(
201 SqlState::DATATYPE_MISMATCH,
202 format!(
203 "cannot compare dissimilar column types {} and {} at record column {}",
204 format_type(left),
205 format_type(right),
206 n + 1
207 ),
208 ));
209 }
210 if family(left).is_none() && !matches!(x, Value::Record(_)) {
211 let message = if equality {
212 format!("could not identify an equality operator for type {}", format_type(left))
213 } else {
214 format!("could not identify a comparison function for type {}", format_type(left))
215 };
216 return Err(Error::new(SqlState::UNDEFINED_FUNCTION, message));
217 }
218 let order = match (x.is_null(), y.is_null()) {
219 (true, true) => Ordering::Equal,
220 (true, false) => Ordering::Greater,
221 (false, true) => Ordering::Less,
222 (false, false) => compare(left, x, right, y)?,
223 };
224 if order.is_ne() {
225 return Ok(order);
226 }
227 }
228 if a.values.len() != b.values.len() {
229 return Err(Error::new(
230 SqlState::DATATYPE_MISMATCH,
231 "cannot compare record types with different numbers of columns",
232 ));
233 }
234 Ok(Ordering::Equal)
235}
236
237fn record_equal(args: &[Value]) -> Result<bool> {
239 let [Value::Record(a), Value::Record(b)] = args else { return Err(bad_value()) };
240 Ok(record_order(a, b, true)?.is_eq())
241}
242
243pub fn equal(left: u32, a: &Value, right: u32, b: &Value) -> Result<bool> {
249 Ok(compare(left, a, right, b)?.is_eq())
250}
251
252pub(crate) fn float(v: &Value) -> Option<f64> {
254 match v {
255 Value::Float4(x) => Some(f64::from(*x)),
256 Value::Float8(x) => Some(*x),
257 _ => None,
258 }
259}
260
261fn float_order(x: f64, y: f64) -> Ordering {
263 match (x.is_nan(), y.is_nan()) {
264 (true, true) => Ordering::Equal,
265 (true, false) => Ordering::Greater,
266 (false, true) => Ordering::Less,
267 (false, false) => x.partial_cmp(&y).unwrap_or(Ordering::Equal),
268 }
269}
270
271pub(crate) fn span(period: &rupg_types::Interval) -> i128 {
273 let days = i128::from(period.month) * 30 + i128::from(period.day);
274 i128::from(period.time) + days * i128::from(USECS_PER_DAY)
275}
276
277fn array_order(left: u32, a: &Array<Value>, right: u32, b: &Array<Value>) -> Result<Ordering> {
279 for (x, y) in a.values.iter().zip(&b.values) {
280 let order = match (x, y) {
281 (None, None) => Ordering::Equal,
282 (None, Some(_)) => Ordering::Greater,
283 (Some(_), None) => Ordering::Less,
284 (Some(x), Some(y)) => compare(left, x, right, y)?,
285 };
286 if order.is_ne() {
287 return Ok(order);
288 }
289 }
290 let lens = |arr: &Array<Value>| arr.dims.iter().map(|d| d.len).collect::<Vec<_>>();
291 let lowers = |arr: &Array<Value>| arr.dims.iter().map(|d| d.lower).collect::<Vec<_>>();
292 Ok(a.values
293 .len()
294 .cmp(&b.values.len())
295 .then(a.dims.len().cmp(&b.dims.len()))
296 .then_with(|| lens(a).cmp(&lens(b)))
297 .then_with(|| lowers(a).cmp(&lowers(b))))
298}
299
300fn order(call: &Call<'_>, args: &[Value]) -> Result<Ordering> {
302 let [a, b] = args else { return Err(bad_value()) };
303 if let Some(order) = mixed_datetime(call, a, b)? {
304 return Ok(order);
305 }
306 let left = call.args.first().copied().unwrap_or(0);
307 let right = call.args.get(1).copied().unwrap_or(0);
308 if family(left) == Some(Family::Array)
309 && family(right) == Some(Family::Array)
310 && base_type(element(left)) != base_type(element(right))
311 {
312 return Err(Error::new(
313 SqlState::DATATYPE_MISMATCH,
314 "cannot compare arrays of different element types",
315 ));
316 }
317 compare(left, a, right, b)
318}
319
320fn eq(call: &Call<'_>, args: &[Value]) -> Result<Value> {
321 Ok(Value::Bool(order(call, args)?.is_eq()))
322}
323
324fn ne(call: &Call<'_>, args: &[Value]) -> Result<Value> {
325 Ok(Value::Bool(order(call, args)?.is_ne()))
326}
327
328fn lt(call: &Call<'_>, args: &[Value]) -> Result<Value> {
329 Ok(Value::Bool(order(call, args)?.is_lt()))
330}
331
332fn le(call: &Call<'_>, args: &[Value]) -> Result<Value> {
333 Ok(Value::Bool(order(call, args)?.is_le()))
334}
335
336fn gt(call: &Call<'_>, args: &[Value]) -> Result<Value> {
337 Ok(Value::Bool(order(call, args)?.is_gt()))
338}
339
340fn ge(call: &Call<'_>, args: &[Value]) -> Result<Value> {
341 Ok(Value::Bool(order(call, args)?.is_ge()))
342}
343
344fn larger(call: &Call<'_>, args: &[Value]) -> Result<Value> {
346 let pick = !order(call, args)?.is_gt();
347 Ok(args[usize::from(pick)].clone())
348}
349
350fn smaller(call: &Call<'_>, args: &[Value]) -> Result<Value> {
352 let pick = !order(call, args)?.is_lt();
353 Ok(args[usize::from(pick)].clone())
354}
355
356fn larger_or_first(call: &Call<'_>, args: &[Value]) -> Result<Value> {
358 let pick = order(call, args)?.is_lt();
359 Ok(args[usize::from(pick)].clone())
360}
361
362fn smaller_or_first(call: &Call<'_>, args: &[Value]) -> Result<Value> {
364 let pick = order(call, args)?.is_gt();
365 Ok(args[usize::from(pick)].clone())
366}
367
368fn cmp(call: &Call<'_>, args: &[Value]) -> Result<Value> {
370 Ok(Value::Int4(match order(call, args)? {
371 Ordering::Less => -1,
372 Ordering::Equal => 0,
373 Ordering::Greater => 1,
374 }))
375}
376
377fn oidvector_order(args: &[Value]) -> Result<Ordering> {
379 let [Value::Array(a), Value::Array(b)] = args else { return Err(bad_value()) };
380 let mut order = a.values.len().cmp(&b.values.len());
381 for (x, y) in a.values.iter().zip(&b.values) {
382 if order.is_ne() {
383 break;
384 }
385 let (Some(Value::Oid(x)), Some(Value::Oid(y))) = (x, y) else { return Err(bad_value()) };
386 order = x.cmp(y);
387 }
388 Ok(order)
389}
390
391fn oidvector_eq(_: &Call<'_>, args: &[Value]) -> Result<Value> {
392 Ok(Value::Bool(oidvector_order(args)?.is_eq()))
393}
394
395fn oidvector_ne(_: &Call<'_>, args: &[Value]) -> Result<Value> {
396 Ok(Value::Bool(oidvector_order(args)?.is_ne()))
397}
398
399fn oidvector_lt(_: &Call<'_>, args: &[Value]) -> Result<Value> {
400 Ok(Value::Bool(oidvector_order(args)?.is_lt()))
401}
402
403fn oidvector_le(_: &Call<'_>, args: &[Value]) -> Result<Value> {
404 Ok(Value::Bool(oidvector_order(args)?.is_le()))
405}
406
407fn oidvector_gt(_: &Call<'_>, args: &[Value]) -> Result<Value> {
408 Ok(Value::Bool(oidvector_order(args)?.is_gt()))
409}
410
411fn oidvector_ge(_: &Call<'_>, args: &[Value]) -> Result<Value> {
412 Ok(Value::Bool(oidvector_order(args)?.is_ge()))
413}
414
415fn oidvector_cmp(_: &Call<'_>, args: &[Value]) -> Result<Value> {
416 Ok(Value::Int4(match oidvector_order(args)? {
417 Ordering::Less => -1,
418 Ordering::Equal => 0,
419 Ordering::Greater => 1,
420 }))
421}
422
423fn oidvector_by_src(src: &str) -> Option<Kernel> {
425 Some(match src {
426 "oidvectoreq" => oidvector_eq,
427 "oidvectorne" => oidvector_ne,
428 "oidvectorlt" => oidvector_lt,
429 "oidvectorle" => oidvector_le,
430 "oidvectorgt" => oidvector_gt,
431 "oidvectorge" => oidvector_ge,
432 "btoidvectorcmp" => oidvector_cmp,
433 _ => return None,
434 })
435}
436
437fn comparable(left: u32, right: u32) -> bool {
439 let (left, right) = (family(left), family(right));
440 left.is_some() && (left == right || datetime(left) && datetime(right))
441}
442
443fn datetime(family: Option<Family>) -> bool {
445 matches!(family, Some(Family::Date | Family::Timestamp | Family::TimestampTz))
446}
447
448fn datetime_rank(value: &Value) -> Option<u8> {
450 match value {
451 Value::Date(_) => Some(0),
452 Value::Timestamp(_) => Some(1),
453 Value::TimestampTz(_) => Some(2),
454 _ => None,
455 }
456}
457
458fn promote(call: &Call<'_>, value: &Value, rank: u8) -> Result<i128> {
460 let above = 2 * i128::from(TIMESTAMP_INFINITY) - 1;
461 let below = 2 * i128::from(TIMESTAMP_NEGATIVE_INFINITY) + 1;
462 let ts = match *value {
463 Value::Date(DATE_NEGATIVE_INFINITY) => TIMESTAMP_NEGATIVE_INFINITY,
464 Value::Date(DATE_INFINITY) => TIMESTAMP_INFINITY,
465 Value::Date(d) if d >= TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE => return Ok(above),
466 Value::Date(d) => i64::from(d) * USECS_PER_DAY,
467 Value::Timestamp(t) | Value::TimestampTz(t) => t,
468 _ => return Err(bad_value()),
469 };
470 if infinite(ts) || rank < 2 || matches!(value, Value::TimestampTz(_)) {
471 return Ok(2 * i128::from(ts));
472 }
473 let zone = call.session.zone()?;
474 let seconds = ts.div_euclid(USECS_PER_SEC) - UNIX_TO_POSTGRES_USECS / USECS_PER_SEC;
475 let (west, _) = rupg_types::local_offset(seconds, zone.as_ref());
476 let utc = ts + i64::from(west) * USECS_PER_SEC;
477 Ok(if valid_timestamp(utc) {
478 2 * i128::from(utc)
479 } else if ts < 0 {
480 below
481 } else {
482 above
483 })
484}
485
486fn mixed_datetime(call: &Call<'_>, a: &Value, b: &Value) -> Result<Option<Ordering>> {
488 let (Some(x), Some(y)) = (datetime_rank(a), datetime_rank(b)) else { return Ok(None) };
489 if x == y {
490 return Ok(None);
491 }
492 let rank = x.max(y);
493 Ok(Some(promote(call, a, rank)?.cmp(&promote(call, b, rank)?)))
494}
495
496pub(crate) fn datetime_order(call: &Call<'_>, a: &Value, b: &Value) -> Result<Ordering> {
498 match mixed_datetime(call, a, b)? {
499 Some(order) => Ok(order),
500 None => compare(0, a, 0, b),
501 }
502}
503
504pub(crate) fn by_operator(name: &str, left: u32, right: u32) -> Option<Kernel> {
506 if !comparable(left, right) {
507 return None;
508 }
509 Some(match name {
510 "=" => eq,
511 "<>" => ne,
512 "<" => lt,
513 "<=" => le,
514 ">" => gt,
515 ">=" => ge,
516 _ => return None,
517 })
518}
519
520fn xid_number(value: &Value) -> Result<u32> {
522 match value {
523 Value::Oid(n) => Ok(*n),
524 Value::Int4(n) => Ok(n.cast_unsigned()),
525 _ => Err(bad_value()),
526 }
527}
528
529fn xid_eq(_: &Call<'_>, args: &[Value]) -> Result<Value> {
531 let [a, b] = args else { return Err(bad_value()) };
532 Ok(Value::Bool(xid_number(a)? == xid_number(b)?))
533}
534
535fn xid_ne(_: &Call<'_>, args: &[Value]) -> Result<Value> {
536 let [a, b] = args else { return Err(bad_value()) };
537 Ok(Value::Bool(xid_number(a)? != xid_number(b)?))
538}
539
540pub(crate) fn by_src(src: &str, proc: &ProcRow) -> Option<Kernel> {
542 let [left, right] = proc.argtypes else { return None };
543 match src {
545 "xideq" | "cideq" => return Some(xid_eq),
546 "xidneq" => return Some(xid_ne),
547 "record_eq" => return Some(|_, args| record_equal(args).map(Value::Bool)),
548 "record_ne" => return Some(|_, args| record_equal(args).map(|eq| Value::Bool(!eq))),
549 _ => {}
550 }
551 if !comparable(*left, *right) {
552 return None;
553 }
554 match src {
556 "text_pattern_lt" | "bpchar_pattern_lt" => return Some(lt),
557 "text_pattern_le" | "bpchar_pattern_le" => return Some(le),
558 "text_pattern_ge" | "bpchar_pattern_ge" => return Some(ge),
559 "text_pattern_gt" | "bpchar_pattern_gt" => return Some(gt),
560 _ => {}
561 }
562 if let Some(kernel) = oidvector_by_src(src) {
563 Some(kernel)
564 } else if src == "bpchar_larger" || src == "tidlarger" {
565 Some(larger_or_first)
566 } else if src == "bpchar_smaller" || src == "tidsmaller" {
567 Some(smaller_or_first)
568 } else if src.ends_with("larger") {
569 Some(larger)
570 } else if src.ends_with("smaller") {
571 Some(smaller)
572 } else if src.starts_with("bt") && src.ends_with("cmp")
573 || matches!(
574 src,
575 "array_cmp"
576 | "cash_cmp"
577 | "xid8cmp"
578 | "macaddr_cmp"
579 | "macaddr8_cmp"
580 | "pg_lsn_cmp"
581 | "range_cmp"
582 | "multirange_cmp"
583 | "bpcharcmp"
584 | "enum_cmp"
585 | "byteacmp"
586 | "date_cmp"
587 | "date_cmp_timestamp"
588 | "date_cmp_timestamptz"
589 | "interval_cmp"
590 | "numeric_cmp"
591 | "time_cmp"
592 | "timestamp_cmp"
593 | "timestamp_cmp_date"
594 | "timestamp_cmp_timestamptz"
595 | "timestamptz_cmp_date"
596 | "timestamptz_cmp_timestamp"
597 | "timetz_cmp"
598 | "uuid_cmp"
599 )
600 {
601 Some(cmp)
602 } else {
603 None
604 }
605}