1use std::cmp::Ordering;
4use std::fmt;
5
6use crate::error::{HematiteError, Result};
7
8#[derive(Debug, Clone, PartialEq, Eq, Hash)]
9pub enum DataType {
10 Int8,
11 Int16,
12 Int,
13 Int64,
14 Int128,
15 UInt8,
16 UInt16,
17 UInt,
18 UInt64,
19 UInt128,
20 Text,
21 Char(u32),
22 VarChar(u32),
23 Binary(u32),
24 VarBinary(u32),
25 Enum(Vec<String>),
26 Boolean,
27 Float32,
28 Float,
29 Decimal {
30 precision: Option<u32>,
31 scale: Option<u32>,
32 },
33 Blob,
34 Date,
35 Time,
36 DateTime,
37 TimeWithTimeZone,
38 IntervalYearMonth,
39 IntervalDaySecond,
40}
41
42impl DataType {
43 pub fn size(&self) -> usize {
44 match self {
45 DataType::Int8 => 1,
46 DataType::Int16 => 2,
47 DataType::Int => 4,
48 DataType::Int64 => 8,
49 DataType::Int128 => 16,
50 DataType::UInt8 => 1,
51 DataType::UInt16 => 2,
52 DataType::UInt => 4,
53 DataType::UInt64 => 8,
54 DataType::UInt128 => 16,
55 DataType::Text => 255,
56 DataType::Char(length) | DataType::VarChar(length) => *length as usize,
57 DataType::Binary(length) | DataType::VarBinary(length) => *length as usize,
58 DataType::Enum(values) => values.iter().map(|value| value.len()).max().unwrap_or(0),
59 DataType::Boolean => 1,
60 DataType::Float32 => 4,
61 DataType::Float => 8,
62 DataType::Decimal { precision, .. } => precision.unwrap_or(32) as usize,
63 DataType::Blob => 4096,
64 DataType::Date => 4,
65 DataType::Time => 4,
66 DataType::DateTime => 8,
67 DataType::TimeWithTimeZone => 6,
68 DataType::IntervalYearMonth => 4,
69 DataType::IntervalDaySecond => 8,
70 }
71 }
72
73 pub fn name(&self) -> String {
74 match self {
75 DataType::Int8 => "INT8".to_string(),
76 DataType::Int16 => "INT16".to_string(),
77 DataType::Int => "INT".to_string(),
78 DataType::Int64 => "INT64".to_string(),
79 DataType::Int128 => "INT128".to_string(),
80 DataType::UInt8 => "UINT8".to_string(),
81 DataType::UInt16 => "UINT16".to_string(),
82 DataType::UInt => "UINT".to_string(),
83 DataType::UInt64 => "UINT64".to_string(),
84 DataType::UInt128 => "UINT128".to_string(),
85 DataType::Text => "TEXT".to_string(),
86 DataType::Char(length) => format!("CHAR({length})"),
87 DataType::VarChar(length) => format!("VARCHAR({length})"),
88 DataType::Binary(length) => format!("BINARY({length})"),
89 DataType::VarBinary(length) => format!("VARBINARY({length})"),
90 DataType::Enum(values) => format!(
91 "ENUM({})",
92 values
93 .iter()
94 .map(|value| format!("'{}'", value.replace('\'', "''")))
95 .collect::<Vec<_>>()
96 .join(", ")
97 ),
98 DataType::Boolean => "BOOLEAN".to_string(),
99 DataType::Float32 => "FLOAT32".to_string(),
100 DataType::Float => "FLOAT".to_string(),
101 DataType::Decimal { precision, scale } => {
102 format_numeric_type("DECIMAL", *precision, *scale)
103 }
104 DataType::Blob => "BLOB".to_string(),
105 DataType::Date => "DATE".to_string(),
106 DataType::Time => "TIME".to_string(),
107 DataType::DateTime => "DATETIME".to_string(),
108 DataType::TimeWithTimeZone => "TIME WITH TIME ZONE".to_string(),
109 DataType::IntervalYearMonth => "INTERVAL YEAR TO MONTH".to_string(),
110 DataType::IntervalDaySecond => "INTERVAL DAY TO SECOND".to_string(),
111 }
112 }
113
114 pub fn base_name(&self) -> &'static str {
115 match self {
116 DataType::Int8 => "INT8",
117 DataType::Int16 => "INT16",
118 DataType::Int => "INT",
119 DataType::Int64 => "INT64",
120 DataType::Int128 => "INT128",
121 DataType::UInt8 => "UINT8",
122 DataType::UInt16 => "UINT16",
123 DataType::UInt => "UINT",
124 DataType::UInt64 => "UINT64",
125 DataType::UInt128 => "UINT128",
126 DataType::Text => "TEXT",
127 DataType::Char(_) => "CHAR",
128 DataType::VarChar(_) => "VARCHAR",
129 DataType::Binary(_) => "BINARY",
130 DataType::VarBinary(_) => "VARBINARY",
131 DataType::Enum(_) => "ENUM",
132 DataType::Boolean => "BOOLEAN",
133 DataType::Float32 => "FLOAT32",
134 DataType::Float => "FLOAT",
135 DataType::Decimal { .. } => "DECIMAL",
136 DataType::Blob => "BLOB",
137 DataType::Date => "DATE",
138 DataType::Time => "TIME",
139 DataType::DateTime => "DATETIME",
140 DataType::TimeWithTimeZone => "TIME WITH TIME ZONE",
141 DataType::IntervalYearMonth => "INTERVAL YEAR TO MONTH",
142 DataType::IntervalDaySecond => "INTERVAL DAY TO SECOND",
143 }
144 }
145
146 pub fn decimal_constraints(&self) -> Option<(Option<u32>, Option<u32>)> {
147 match self {
148 DataType::Decimal { precision, scale } => Some((*precision, *scale)),
149 _ => None,
150 }
151 }
152}
153
154fn format_numeric_type(name: &str, precision: Option<u32>, scale: Option<u32>) -> String {
155 match (precision, scale) {
156 (Some(precision), Some(scale)) => format!("{name}({precision}, {scale})"),
157 (Some(precision), None) => format!("{name}({precision})"),
158 (None, _) => name.to_string(),
159 }
160}
161
162#[derive(Debug, Clone, Copy, PartialEq, Eq)]
163pub enum JournalMode {
164 Rollback,
165 Wal,
166}
167
168#[derive(Debug, Clone, PartialEq, Eq, Hash)]
169pub struct DecimalValue {
170 negative: bool,
171 digits: Vec<u8>,
172 scale: u32,
173}
174
175impl DecimalValue {
176 pub fn zero() -> Self {
177 Self {
178 negative: false,
179 digits: vec![0],
180 scale: 0,
181 }
182 }
183
184 pub fn parse(input: &str) -> Result<Self> {
185 let trimmed = input.trim();
186 if trimmed.is_empty() {
187 return Err(HematiteError::ParseError(
188 "Decimal value cannot be empty".to_string(),
189 ));
190 }
191
192 let (negative, digits) = match trimmed.as_bytes()[0] {
193 b'+' => (false, &trimmed[1..]),
194 b'-' => (true, &trimmed[1..]),
195 _ => (false, trimmed),
196 };
197
198 if digits.is_empty() {
199 return Err(HematiteError::ParseError(format!(
200 "Invalid decimal value '{}'",
201 input
202 )));
203 }
204
205 let mut parts = digits.split('.');
206 let integer = parts.next().unwrap_or_default();
207 let fraction = parts.next();
208 if parts.next().is_some()
209 || !integer.chars().all(|ch| ch.is_ascii_digit())
210 || fraction.is_some_and(|part| !part.chars().all(|ch| ch.is_ascii_digit()))
211 {
212 return Err(HematiteError::ParseError(format!(
213 "Invalid decimal value '{}'",
214 input
215 )));
216 }
217
218 let integer = integer.trim_start_matches('0');
219 let integer = if integer.is_empty() { "0" } else { integer };
220 let mut fraction = fraction.unwrap_or_default().to_string();
221 while fraction.ends_with('0') {
222 fraction.pop();
223 }
224
225 let mut combined = String::with_capacity(integer.len() + fraction.len());
226 combined.push_str(integer);
227 combined.push_str(&fraction);
228 let combined = combined.trim_start_matches('0');
229 let digits = if combined.is_empty() {
230 vec![0]
231 } else {
232 combined.bytes().map(|byte| byte - b'0').collect()
233 };
234
235 let negative = negative && !(digits.len() == 1 && digits[0] == 0);
236
237 Ok(Self {
238 negative,
239 digits,
240 scale: fraction.len() as u32,
241 })
242 }
243
244 pub fn from_i32(value: i32) -> Self {
245 Self::parse(&value.to_string()).expect("i32 string is always a valid decimal")
246 }
247
248 pub fn from_i64(value: i64) -> Self {
249 Self::parse(&value.to_string()).expect("i64 string is always a valid decimal")
250 }
251
252 pub fn from_i128(value: i128) -> Self {
253 Self::parse(&value.to_string()).expect("i128 string is always a valid decimal")
254 }
255
256 pub fn from_u32(value: u32) -> Self {
257 Self::parse(&value.to_string()).expect("u32 string is always a valid decimal")
258 }
259
260 pub fn from_u64(value: u64) -> Self {
261 Self::parse(&value.to_string()).expect("u64 string is always a valid decimal")
262 }
263
264 pub fn from_u128(value: u128) -> Self {
265 Self::parse(&value.to_string()).expect("u128 string is always a valid decimal")
266 }
267
268 pub fn from_f64(value: f64) -> Result<Self> {
269 if !value.is_finite() {
270 return Err(HematiteError::ParseError(
271 "Decimal value must be finite".to_string(),
272 ));
273 }
274 Self::parse(&value.to_string())
275 }
276
277 pub fn is_integral(&self) -> bool {
278 self.scale == 0
279 }
280
281 pub fn add(&self, other: &Self) -> Self {
282 let target_scale = self.scale.max(other.scale);
283 let left = scale_decimal_digits(&self.digits, self.scale, target_scale);
284 let right = scale_decimal_digits(&other.digits, other.scale, target_scale);
285
286 if self.negative == other.negative {
287 normalize_decimal_parts(
288 self.negative,
289 add_digit_vectors(&left, &right),
290 target_scale,
291 )
292 } else {
293 match compare_digit_vectors(&left, &right) {
294 Ordering::Greater => normalize_decimal_parts(
295 self.negative,
296 subtract_digit_vectors(&left, &right),
297 target_scale,
298 ),
299 Ordering::Less => normalize_decimal_parts(
300 other.negative,
301 subtract_digit_vectors(&right, &left),
302 target_scale,
303 ),
304 Ordering::Equal => Self::zero(),
305 }
306 }
307 }
308
309 pub fn subtract(&self, other: &Self) -> Self {
310 if other.is_zero() {
311 return self.clone();
312 }
313
314 let mut negated = other.clone();
315 negated.negative = !negated.negative;
316 self.add(&negated)
317 }
318
319 pub fn multiply(&self, other: &Self) -> Self {
320 normalize_decimal_parts(
321 self.negative ^ other.negative,
322 multiply_digit_vectors(&self.digits, &other.digits),
323 self.scale + other.scale,
324 )
325 }
326
327 pub fn divide(&self, other: &Self) -> Result<Self> {
328 if other.is_zero() {
329 return Err(HematiteError::ParseError("Division by zero".to_string()));
330 }
331
332 const DECIMAL_DIVISION_SCALE: u32 = 18;
333
334 let mut numerator = self.digits.clone();
335 numerator.resize(
336 numerator.len() + other.scale as usize + DECIMAL_DIVISION_SCALE as usize,
337 0,
338 );
339 let mut denominator = other.digits.clone();
340 denominator.resize(denominator.len() + self.scale as usize, 0);
341
342 let (mut quotient, remainder) = divide_digit_vectors(&numerator, &denominator);
343 if !is_zero_digit_vector(&remainder) {
344 let doubled_remainder = add_digit_vectors(&remainder, &remainder);
345 if compare_digit_vectors(&doubled_remainder, &denominator) != Ordering::Less {
346 quotient = increment_digit_vector("ient);
347 }
348 }
349
350 Ok(normalize_decimal_parts(
351 self.negative ^ other.negative,
352 quotient,
353 DECIMAL_DIVISION_SCALE,
354 ))
355 }
356
357 pub fn remainder(&self, other: &Self) -> Result<Self> {
358 if other.is_zero() {
359 return Err(HematiteError::ParseError("Division by zero".to_string()));
360 }
361
362 let target_scale = self.scale.max(other.scale);
363 let left = scale_decimal_digits(&self.digits, self.scale, target_scale);
364 let right = scale_decimal_digits(&other.digits, other.scale, target_scale);
365 let (_, remainder) = divide_digit_vectors(&left, &right);
366 Ok(normalize_decimal_parts(
367 self.negative,
368 remainder,
369 target_scale,
370 ))
371 }
372
373 pub fn negate(&self) -> Self {
374 if self.is_zero() {
375 Self::zero()
376 } else {
377 let mut negated = self.clone();
378 negated.negative = !negated.negative;
379 negated
380 }
381 }
382
383 pub fn precision(&self) -> u32 {
384 self.digits.len() as u32
385 }
386
387 pub fn scale(&self) -> u32 {
388 self.scale
389 }
390
391 pub fn is_zero(&self) -> bool {
392 self.digits.len() == 1 && self.digits[0] == 0
393 }
394
395 pub fn fits_precision_scale(&self, precision: Option<u32>, scale: Option<u32>) -> bool {
396 if let Some(scale) = scale {
397 if self.scale > scale {
398 return false;
399 }
400 }
401
402 if let Some(precision) = precision {
403 let max_digits = precision;
404 let digits = self.precision();
405 if digits > max_digits {
406 return false;
407 }
408 if let Some(scale) = scale {
409 let integer_digits = digits.saturating_sub(self.scale).max(1);
410 let max_integer_digits = precision.saturating_sub(scale).max(1);
411 if integer_digits > max_integer_digits {
412 return false;
413 }
414 }
415 }
416
417 true
418 }
419
420 pub fn digit_bytes(&self) -> &[u8] {
421 &self.digits
422 }
423
424 pub fn negative(&self) -> bool {
425 self.negative
426 }
427
428 pub fn to_f64(&self) -> Option<f64> {
429 self.to_string().parse::<f64>().ok()
430 }
431
432 pub fn to_integral_u128(&self) -> Option<u128> {
433 if !self.is_integral() || self.negative {
434 return None;
435 }
436
437 let mut value = 0u128;
438 for digit in &self.digits {
439 value = value.checked_mul(10)?.checked_add(*digit as u128)?;
440 }
441 Some(value)
442 }
443
444 pub fn to_integral_i128(&self) -> Option<i128> {
445 if !self.is_integral() {
446 return None;
447 }
448
449 let magnitude = self.to_integral_u128_abs()?;
450 if self.negative {
451 if magnitude == (i128::MAX as u128) + 1 {
452 Some(i128::MIN)
453 } else {
454 i128::try_from(magnitude).ok().map(|value| -value)
455 }
456 } else {
457 i128::try_from(magnitude).ok()
458 }
459 }
460
461 fn to_integral_u128_abs(&self) -> Option<u128> {
462 if !self.is_integral() {
463 return None;
464 }
465
466 let mut value = 0u128;
467 for digit in &self.digits {
468 value = value.checked_mul(10)?.checked_add(*digit as u128)?;
469 }
470 Some(value)
471 }
472}
473
474fn normalize_decimal_parts(negative: bool, mut digits: Vec<u8>, mut scale: u32) -> DecimalValue {
475 trim_leading_digit_zeros(&mut digits);
476 while scale > 0 && digits.len() > 1 && digits.last() == Some(&0) {
477 digits.pop();
478 scale -= 1;
479 }
480 trim_leading_digit_zeros(&mut digits);
481 if is_zero_digit_vector(&digits) {
482 return DecimalValue::zero();
483 }
484
485 DecimalValue {
486 negative,
487 digits,
488 scale,
489 }
490}
491
492fn scale_decimal_digits(digits: &[u8], scale: u32, target_scale: u32) -> Vec<u8> {
493 let mut scaled = digits.to_vec();
494 scaled.resize(
495 scaled.len() + target_scale.saturating_sub(scale) as usize,
496 0,
497 );
498 scaled
499}
500
501fn compare_digit_vectors(left: &[u8], right: &[u8]) -> Ordering {
502 left.len().cmp(&right.len()).then_with(|| left.cmp(right))
503}
504
505fn add_digit_vectors(left: &[u8], right: &[u8]) -> Vec<u8> {
506 let mut result = Vec::with_capacity(left.len().max(right.len()) + 1);
507 let mut carry = 0u8;
508 let mut left_index = left.len();
509 let mut right_index = right.len();
510
511 while left_index > 0 || right_index > 0 || carry > 0 {
512 let left_digit = if left_index > 0 {
513 left_index -= 1;
514 left[left_index]
515 } else {
516 0
517 };
518 let right_digit = if right_index > 0 {
519 right_index -= 1;
520 right[right_index]
521 } else {
522 0
523 };
524 let total = left_digit + right_digit + carry;
525 result.push(total % 10);
526 carry = total / 10;
527 }
528
529 result.reverse();
530 result
531}
532
533fn subtract_digit_vectors(left: &[u8], right: &[u8]) -> Vec<u8> {
534 let mut result = Vec::with_capacity(left.len());
535 let mut borrow = 0i16;
536 let mut left_index = left.len();
537 let mut right_index = right.len();
538
539 while left_index > 0 {
540 left_index -= 1;
541 let left_digit = left[left_index] as i16 - borrow;
542 let right_digit = if right_index > 0 {
543 right_index -= 1;
544 right[right_index] as i16
545 } else {
546 0
547 };
548 if left_digit < right_digit {
549 result.push((left_digit + 10 - right_digit) as u8);
550 borrow = 1;
551 } else {
552 result.push((left_digit - right_digit) as u8);
553 borrow = 0;
554 }
555 }
556
557 result.reverse();
558 trim_leading_digit_zeros(&mut result);
559 result
560}
561
562fn multiply_digit_vectors(left: &[u8], right: &[u8]) -> Vec<u8> {
563 if is_zero_digit_vector(left) || is_zero_digit_vector(right) {
564 return vec![0];
565 }
566
567 let mut result = vec![0u32; left.len() + right.len()];
568 for (left_index, left_digit) in left.iter().enumerate().rev() {
569 for (right_index, right_digit) in right.iter().enumerate().rev() {
570 let slot = left_index + right_index + 1;
571 result[slot] += (*left_digit as u32) * (*right_digit as u32);
572 }
573 }
574
575 for index in (1..result.len()).rev() {
576 let carry = result[index] / 10;
577 result[index] %= 10;
578 result[index - 1] += carry;
579 }
580
581 let mut digits = result
582 .into_iter()
583 .map(|digit| digit as u8)
584 .collect::<Vec<_>>();
585 trim_leading_digit_zeros(&mut digits);
586 digits
587}
588
589fn divide_digit_vectors(numerator: &[u8], denominator: &[u8]) -> (Vec<u8>, Vec<u8>) {
590 debug_assert!(!is_zero_digit_vector(denominator));
591
592 let mut quotient = Vec::with_capacity(numerator.len().max(1));
593 let mut remainder = vec![0];
594
595 for digit in numerator {
596 if is_zero_digit_vector(&remainder) {
597 remainder[0] = *digit;
598 } else {
599 remainder.push(*digit);
600 }
601 trim_leading_digit_zeros(&mut remainder);
602
603 let mut quotient_digit = 0u8;
604 while compare_digit_vectors(&remainder, denominator) != Ordering::Less {
605 remainder = subtract_digit_vectors(&remainder, denominator);
606 quotient_digit += 1;
607 }
608 quotient.push(quotient_digit);
609 }
610
611 trim_leading_digit_zeros(&mut quotient);
612 trim_leading_digit_zeros(&mut remainder);
613 (quotient, remainder)
614}
615
616fn increment_digit_vector(digits: &[u8]) -> Vec<u8> {
617 add_digit_vectors(digits, &[1])
618}
619
620fn trim_leading_digit_zeros(digits: &mut Vec<u8>) {
621 while digits.len() > 1 && digits.first() == Some(&0) {
622 digits.remove(0);
623 }
624 if digits.is_empty() {
625 digits.push(0);
626 }
627}
628
629fn is_zero_digit_vector(digits: &[u8]) -> bool {
630 digits.len() == 1 && digits[0] == 0
631}
632
633impl fmt::Display for DecimalValue {
634 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
635 if self.negative && !self.is_zero() {
636 write!(f, "-")?;
637 }
638
639 let digits = self
640 .digits
641 .iter()
642 .map(|digit| char::from(b'0' + *digit))
643 .collect::<String>();
644
645 if self.scale == 0 {
646 return write!(f, "{digits}");
647 }
648
649 let split = digits.len().saturating_sub(self.scale as usize);
650 if split == 0 {
651 write!(f, "0.")?;
652 for _ in 0..self.scale as usize - digits.len() {
653 write!(f, "0")?;
654 }
655 write!(f, "{digits}")
656 } else {
657 write!(f, "{}.{}", &digits[..split], &digits[split..])
658 }
659 }
660}
661
662impl PartialOrd for DecimalValue {
663 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
664 Some(self.cmp(other))
665 }
666}
667
668impl Ord for DecimalValue {
669 fn cmp(&self, other: &Self) -> Ordering {
670 if self.negative != other.negative {
671 return if self.negative {
672 Ordering::Less
673 } else {
674 Ordering::Greater
675 };
676 }
677
678 let left_integer_digits = self.digits.len().saturating_sub(self.scale as usize).max(1);
679 let right_integer_digits = other
680 .digits
681 .len()
682 .saturating_sub(other.scale as usize)
683 .max(1);
684
685 let ordering = left_integer_digits
686 .cmp(&right_integer_digits)
687 .then_with(|| self.digits.cmp(&other.digits))
688 .then_with(|| self.scale.cmp(&other.scale).reverse());
689
690 if self.negative {
691 ordering.reverse()
692 } else {
693 ordering
694 }
695 }
696}
697
698#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
699pub struct DateValue {
700 days_since_epoch: i32,
701}
702
703impl DateValue {
704 pub fn epoch() -> Self {
705 Self {
706 days_since_epoch: 0,
707 }
708 }
709
710 pub fn parse(input: &str) -> Result<Self> {
711 let value = input.trim();
712 let parts = value.split('-').collect::<Vec<_>>();
713 if parts.len() != 3
714 || parts[0].len() != 4
715 || parts[1].len() != 2
716 || parts[2].len() != 2
717 || !parts
718 .iter()
719 .all(|part| part.chars().all(|ch| ch.is_ascii_digit()))
720 {
721 return Err(HematiteError::ParseError(format!(
722 "Invalid DATE value '{}'",
723 input
724 )));
725 }
726
727 let year = parts[0]
728 .parse::<i32>()
729 .map_err(|_| HematiteError::ParseError(format!("Invalid DATE value '{}'", input)))?;
730 let month = parts[1]
731 .parse::<u32>()
732 .map_err(|_| HematiteError::ParseError(format!("Invalid DATE value '{}'", input)))?;
733 let day = parts[2]
734 .parse::<u32>()
735 .map_err(|_| HematiteError::ParseError(format!("Invalid DATE value '{}'", input)))?;
736 validate_date_components(year, month, day, input)?;
737 Ok(Self {
738 days_since_epoch: days_from_civil(year, month, day),
739 })
740 }
741
742 pub fn from_days_since_epoch(days_since_epoch: i32) -> Self {
743 Self { days_since_epoch }
744 }
745
746 pub fn days_since_epoch(self) -> i32 {
747 self.days_since_epoch
748 }
749
750 pub fn components(self) -> (i32, u32, u32) {
751 civil_from_days(self.days_since_epoch)
752 }
753}
754
755impl fmt::Display for DateValue {
756 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
757 let (year, month, day) = self.components();
758 write!(f, "{year:04}-{month:02}-{day:02}")
759 }
760}
761
762#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
763pub struct TimeValue {
764 seconds_since_midnight: u32,
765}
766
767impl TimeValue {
768 pub fn midnight() -> Self {
769 Self {
770 seconds_since_midnight: 0,
771 }
772 }
773
774 pub fn parse(input: &str) -> Result<Self> {
775 let value = input.trim();
776 let (hour, minute, second) = parse_time_components(value, "TIME")?;
777 Ok(Self {
778 seconds_since_midnight: hour * 3_600 + minute * 60 + second,
779 })
780 }
781
782 pub fn from_seconds_since_midnight(seconds_since_midnight: u32) -> Self {
783 Self {
784 seconds_since_midnight: seconds_since_midnight % 86_400,
785 }
786 }
787
788 pub fn seconds_since_midnight(self) -> u32 {
789 self.seconds_since_midnight
790 }
791
792 pub fn components(self) -> (u32, u32, u32) {
793 let hour = self.seconds_since_midnight / 3_600;
794 let minute = (self.seconds_since_midnight % 3_600) / 60;
795 let second = self.seconds_since_midnight % 60;
796 (hour, minute, second)
797 }
798}
799
800impl fmt::Display for TimeValue {
801 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
802 let (hour, minute, second) = self.components();
803 write!(f, "{hour:02}:{minute:02}:{second:02}")
804 }
805}
806
807#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
808pub struct DateTimeValue {
809 seconds_since_epoch: i64,
810}
811
812impl DateTimeValue {
813 pub fn epoch() -> Self {
814 Self {
815 seconds_since_epoch: 0,
816 }
817 }
818
819 pub fn parse(input: &str) -> Result<Self> {
820 let value = input.trim();
821 let mut parts = value.split(' ');
822 let date = parts.next().unwrap_or_default();
823 let time = parts.next().unwrap_or_default();
824 if parts.next().is_some() {
825 return Err(HematiteError::ParseError(format!(
826 "Invalid DATETIME value '{}'",
827 input
828 )));
829 }
830 let date = DateValue::parse(date)?;
831 let (hour, minute, second) = parse_time_components(time, "DATETIME")?;
832
833 Ok(Self {
834 seconds_since_epoch: date.days_since_epoch as i64 * 86_400
835 + hour as i64 * 3_600
836 + minute as i64 * 60
837 + second as i64,
838 })
839 }
840
841 pub fn from_seconds_since_epoch(seconds_since_epoch: i64) -> Self {
842 Self {
843 seconds_since_epoch,
844 }
845 }
846
847 pub fn seconds_since_epoch(self) -> i64 {
848 self.seconds_since_epoch
849 }
850
851 pub fn components(self) -> (DateValue, TimeValue) {
852 let days = self.seconds_since_epoch.div_euclid(86_400) as i32;
853 let seconds = self.seconds_since_epoch.rem_euclid(86_400) as u32;
854 (
855 DateValue::from_days_since_epoch(days),
856 TimeValue::from_seconds_since_midnight(seconds),
857 )
858 }
859}
860
861impl fmt::Display for DateTimeValue {
862 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
863 let (date, time) = self.components();
864 let (year, month, day) = date.components();
865 let (hour, minute, second) = time.components();
866 write!(
867 f,
868 "{year:04}-{month:02}-{day:02} {hour:02}:{minute:02}:{second:02}"
869 )
870 }
871}
872
873#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
874pub struct TimeWithTimeZoneValue {
875 seconds_since_midnight: u32,
876 offset_minutes: i16,
877}
878
879impl TimeWithTimeZoneValue {
880 pub fn utc_midnight() -> Self {
881 Self {
882 seconds_since_midnight: 0,
883 offset_minutes: 0,
884 }
885 }
886
887 pub fn parse(input: &str) -> Result<Self> {
888 let value = input.trim();
889 let split = value
890 .rfind(['+', '-'])
891 .filter(|index| *index > 0)
892 .ok_or_else(|| {
893 HematiteError::ParseError(format!("Invalid TIME WITH TIME ZONE value '{}'", input))
894 })?;
895 let (time, offset) = value.split_at(split);
896 let time = TimeValue::parse(time).map_err(|_| {
897 HematiteError::ParseError(format!("Invalid TIME WITH TIME ZONE value '{}'", input))
898 })?;
899 let offset_minutes = parse_timezone_offset(offset, input)?;
900 Ok(Self {
901 seconds_since_midnight: time.seconds_since_midnight(),
902 offset_minutes,
903 })
904 }
905
906 pub fn from_parts(seconds_since_midnight: u32, offset_minutes: i16) -> Self {
907 Self {
908 seconds_since_midnight: seconds_since_midnight % 86_400,
909 offset_minutes,
910 }
911 }
912
913 pub fn seconds_since_midnight(self) -> u32 {
914 self.seconds_since_midnight
915 }
916
917 pub fn offset_minutes(self) -> i16 {
918 self.offset_minutes
919 }
920
921 pub fn time(self) -> TimeValue {
922 TimeValue::from_seconds_since_midnight(self.seconds_since_midnight)
923 }
924}
925
926impl fmt::Display for TimeWithTimeZoneValue {
927 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
928 let sign = if self.offset_minutes < 0 { '-' } else { '+' };
929 let offset = self.offset_minutes.unsigned_abs();
930 let offset_hours = offset / 60;
931 let offset_minutes = offset % 60;
932 write!(
933 f,
934 "{}{}{:02}:{:02}",
935 self.time(),
936 sign,
937 offset_hours,
938 offset_minutes
939 )
940 }
941}
942
943#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
944pub struct IntervalYearMonthValue {
945 total_months: i32,
946}
947
948impl IntervalYearMonthValue {
949 pub fn new(total_months: i32) -> Self {
950 Self { total_months }
951 }
952
953 pub fn parse(input: &str) -> Result<Self> {
954 let trimmed = input.trim();
955 if trimmed.is_empty() {
956 return Err(HematiteError::ParseError(
957 "Invalid INTERVAL YEAR TO MONTH value ''".to_string(),
958 ));
959 }
960
961 let (negative, digits) = match trimmed.as_bytes()[0] {
962 b'+' => (false, &trimmed[1..]),
963 b'-' => (true, &trimmed[1..]),
964 _ => (false, trimmed),
965 };
966 let (years, months) = digits.split_once('-').ok_or_else(|| {
967 HematiteError::ParseError(format!("Invalid INTERVAL YEAR TO MONTH value '{}'", input))
968 })?;
969 if years.is_empty()
970 || months.len() != 2
971 || !years.chars().all(|ch| ch.is_ascii_digit())
972 || !months.chars().all(|ch| ch.is_ascii_digit())
973 {
974 return Err(HematiteError::ParseError(format!(
975 "Invalid INTERVAL YEAR TO MONTH value '{}'",
976 input
977 )));
978 }
979
980 let years = years.parse::<i32>().map_err(|_| {
981 HematiteError::ParseError(format!("Invalid INTERVAL YEAR TO MONTH value '{}'", input))
982 })?;
983 let months = months.parse::<i32>().map_err(|_| {
984 HematiteError::ParseError(format!("Invalid INTERVAL YEAR TO MONTH value '{}'", input))
985 })?;
986 if !(0..12).contains(&months) {
987 return Err(HematiteError::ParseError(format!(
988 "Invalid INTERVAL YEAR TO MONTH value '{}'",
989 input
990 )));
991 }
992
993 let total_months = years
994 .checked_mul(12)
995 .and_then(|total| total.checked_add(months))
996 .ok_or_else(|| {
997 HematiteError::ParseError(
998 "INTERVAL YEAR TO MONTH value overflowed supported range".to_string(),
999 )
1000 })?;
1001 Ok(Self {
1002 total_months: if negative {
1003 -total_months
1004 } else {
1005 total_months
1006 },
1007 })
1008 }
1009
1010 pub fn total_months(self) -> i32 {
1011 self.total_months
1012 }
1013}
1014
1015impl fmt::Display for IntervalYearMonthValue {
1016 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1017 let sign = if self.total_months < 0 { "-" } else { "" };
1018 let total_months = self.total_months.unsigned_abs();
1019 let years = total_months / 12;
1020 let months = total_months % 12;
1021 write!(f, "{sign}{years}-{months:02}")
1022 }
1023}
1024
1025#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
1026pub struct IntervalDaySecondValue {
1027 total_seconds: i64,
1028}
1029
1030impl IntervalDaySecondValue {
1031 pub fn new(total_seconds: i64) -> Self {
1032 Self { total_seconds }
1033 }
1034
1035 pub fn parse(input: &str) -> Result<Self> {
1036 let trimmed = input.trim();
1037 if trimmed.is_empty() {
1038 return Err(HematiteError::ParseError(
1039 "Invalid INTERVAL DAY TO SECOND value ''".to_string(),
1040 ));
1041 }
1042
1043 let (negative, digits) = match trimmed.as_bytes()[0] {
1044 b'+' => (false, &trimmed[1..]),
1045 b'-' => (true, &trimmed[1..]),
1046 _ => (false, trimmed),
1047 };
1048 let (days, time) = digits.split_once(' ').ok_or_else(|| {
1049 HematiteError::ParseError(format!("Invalid INTERVAL DAY TO SECOND value '{}'", input))
1050 })?;
1051 if days.is_empty() || !days.chars().all(|ch| ch.is_ascii_digit()) {
1052 return Err(HematiteError::ParseError(format!(
1053 "Invalid INTERVAL DAY TO SECOND value '{}'",
1054 input
1055 )));
1056 }
1057 let days = days.parse::<i64>().map_err(|_| {
1058 HematiteError::ParseError(format!("Invalid INTERVAL DAY TO SECOND value '{}'", input))
1059 })?;
1060 let (hour, minute, second) = parse_time_components(time, "INTERVAL DAY TO SECOND")?;
1061 let total_seconds = days
1062 .checked_mul(86_400)
1063 .and_then(|total| total.checked_add(hour as i64 * 3_600))
1064 .and_then(|total| total.checked_add(minute as i64 * 60))
1065 .and_then(|total| total.checked_add(second as i64))
1066 .ok_or_else(|| {
1067 HematiteError::ParseError(
1068 "INTERVAL DAY TO SECOND value overflowed supported range".to_string(),
1069 )
1070 })?;
1071 Ok(Self {
1072 total_seconds: if negative {
1073 -total_seconds
1074 } else {
1075 total_seconds
1076 },
1077 })
1078 }
1079
1080 pub fn total_seconds(self) -> i64 {
1081 self.total_seconds
1082 }
1083}
1084
1085impl fmt::Display for IntervalDaySecondValue {
1086 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1087 let sign = if self.total_seconds < 0 { "-" } else { "" };
1088 let total_seconds = self.total_seconds.unsigned_abs();
1089 let days = total_seconds / 86_400;
1090 let remainder = total_seconds % 86_400;
1091 let hours = remainder / 3_600;
1092 let minutes = (remainder % 3_600) / 60;
1093 let seconds = remainder % 60;
1094 write!(f, "{sign}{days} {hours:02}:{minutes:02}:{seconds:02}")
1095 }
1096}
1097
1098#[derive(Debug, Clone, PartialEq)]
1099pub enum Value {
1100 Integer(i32),
1101 BigInt(i64),
1102 Int128(i128),
1103 UInteger(u32),
1104 UBigInt(u64),
1105 UInt128(u128),
1106 Text(String),
1107 Enum(String),
1108 Boolean(bool),
1109 Float32(f32),
1110 Float(f64),
1111 Decimal(DecimalValue),
1112 Blob(Vec<u8>),
1113 Date(DateValue),
1114 Time(TimeValue),
1115 DateTime(DateTimeValue),
1116 TimeWithTimeZone(TimeWithTimeZoneValue),
1117 IntervalYearMonth(IntervalYearMonthValue),
1118 IntervalDaySecond(IntervalDaySecondValue),
1119 Null,
1120}
1121
1122impl Value {
1123 pub fn data_type(&self) -> DataType {
1124 match self {
1125 Value::Integer(_) => DataType::Int,
1126 Value::BigInt(_) => DataType::Int64,
1127 Value::Int128(_) => DataType::Int128,
1128 Value::UInteger(_) => DataType::UInt,
1129 Value::UBigInt(_) => DataType::UInt64,
1130 Value::UInt128(_) => DataType::UInt128,
1131 Value::Text(_) => DataType::Text,
1132 Value::Enum(_) => DataType::Enum(Vec::new()),
1133 Value::Boolean(_) => DataType::Boolean,
1134 Value::Float32(_) => DataType::Float32,
1135 Value::Float(_) => DataType::Float,
1136 Value::Decimal(_) => DataType::Decimal {
1137 precision: None,
1138 scale: None,
1139 },
1140 Value::Blob(_) => DataType::Blob,
1141 Value::Date(_) => DataType::Date,
1142 Value::Time(_) => DataType::Time,
1143 Value::DateTime(_) => DataType::DateTime,
1144 Value::TimeWithTimeZone(_) => DataType::TimeWithTimeZone,
1145 Value::IntervalYearMonth(_) => DataType::IntervalYearMonth,
1146 Value::IntervalDaySecond(_) => DataType::IntervalDaySecond,
1147 Value::Null => DataType::Text,
1148 }
1149 }
1150
1151 pub fn is_compatible_with(&self, data_type: DataType) -> bool {
1152 match (self, data_type) {
1153 (Value::Integer(_), DataType::Int8)
1154 | (Value::Integer(_), DataType::Int16)
1155 | (Value::Integer(_), DataType::Int) => true,
1156 (Value::BigInt(_), DataType::Int64) => true,
1157 (Value::Int128(_), DataType::Int128) => true,
1158 (Value::UInteger(_), DataType::UInt8)
1159 | (Value::UInteger(_), DataType::UInt16)
1160 | (Value::UInteger(_), DataType::UInt) => true,
1161 (Value::UBigInt(_), DataType::UInt64) => true,
1162 (Value::UInt128(_), DataType::UInt128) => true,
1163 (Value::Text(_), DataType::Text)
1164 | (Value::Text(_), DataType::Char(_))
1165 | (Value::Text(_), DataType::VarChar(_)) => true,
1166 (Value::Blob(_), DataType::Binary(_)) | (Value::Blob(_), DataType::VarBinary(_)) => {
1167 true
1168 }
1169 (Value::Enum(value), DataType::Enum(values)) => values.contains(value),
1170 (Value::Boolean(_), DataType::Boolean) => true,
1171 (Value::Float32(_), DataType::Float32) => true,
1172 (Value::Float(_), DataType::Float) => true,
1173 (Value::Decimal(value), DataType::Decimal { precision, scale }) => {
1174 value.fits_precision_scale(precision, scale)
1175 }
1176 (Value::Blob(_), DataType::Blob) => true,
1177 (Value::Date(_), DataType::Date) => true,
1178 (Value::Time(_), DataType::Time) => true,
1179 (Value::DateTime(_), DataType::DateTime) => true,
1180 (Value::TimeWithTimeZone(_), DataType::TimeWithTimeZone) => true,
1181 (Value::IntervalYearMonth(_), DataType::IntervalYearMonth) => true,
1182 (Value::IntervalDaySecond(_), DataType::IntervalDaySecond) => true,
1183 (Value::Null, _) => true,
1184 _ => false,
1185 }
1186 }
1187
1188 pub fn as_integer(&self) -> Option<i32> {
1189 match self {
1190 Value::Integer(i) => Some(*i),
1191 _ => None,
1192 }
1193 }
1194
1195 pub fn as_text(&self) -> Option<String> {
1196 match self {
1197 Value::Text(s) => Some(s.clone()),
1198 Value::Enum(s) => Some(s.clone()),
1199 Value::Decimal(s) => Some(s.to_string()),
1200 Value::Date(s) => Some(s.to_string()),
1201 Value::Time(s) => Some(s.to_string()),
1202 Value::DateTime(s) => Some(s.to_string()),
1203 Value::TimeWithTimeZone(s) => Some(s.to_string()),
1204 Value::IntervalYearMonth(s) => Some(s.to_string()),
1205 Value::IntervalDaySecond(s) => Some(s.to_string()),
1206 _ => None,
1207 }
1208 }
1209
1210 pub fn as_boolean(&self) -> Option<bool> {
1211 match self {
1212 Value::Boolean(b) => Some(*b),
1213 _ => None,
1214 }
1215 }
1216
1217 pub fn as_float(&self) -> Option<f64> {
1218 match self {
1219 Value::Float32(f) => Some(*f as f64),
1220 Value::Float(f) => Some(*f),
1221 _ => None,
1222 }
1223 }
1224
1225 pub fn as_bigint(&self) -> Option<i64> {
1226 match self {
1227 Value::BigInt(i) => Some(*i),
1228 Value::Integer(i) => Some(*i as i64),
1229 Value::UInteger(i) => Some(*i as i64),
1230 _ => None,
1231 }
1232 }
1233
1234 pub fn as_int128(&self) -> Option<i128> {
1235 match self {
1236 Value::Int128(i) => Some(*i),
1237 Value::BigInt(i) => Some(*i as i128),
1238 Value::Integer(i) => Some(*i as i128),
1239 Value::UInteger(i) => Some(*i as i128),
1240 Value::UBigInt(i) => i128::try_from(*i).ok(),
1241 _ => None,
1242 }
1243 }
1244
1245 pub fn as_uint(&self) -> Option<u32> {
1246 match self {
1247 Value::UInteger(i) => Some(*i),
1248 Value::Integer(i) if *i >= 0 => Some(*i as u32),
1249 _ => None,
1250 }
1251 }
1252
1253 pub fn as_uint64(&self) -> Option<u64> {
1254 match self {
1255 Value::UBigInt(i) => Some(*i),
1256 Value::UInteger(i) => Some(*i as u64),
1257 Value::Integer(i) if *i >= 0 => Some(*i as u64),
1258 Value::BigInt(i) if *i >= 0 => Some(*i as u64),
1259 _ => None,
1260 }
1261 }
1262
1263 pub fn as_uint128(&self) -> Option<u128> {
1264 match self {
1265 Value::UInt128(i) => Some(*i),
1266 Value::UBigInt(i) => Some(*i as u128),
1267 Value::UInteger(i) => Some(*i as u128),
1268 Value::Integer(i) if *i >= 0 => Some(*i as u128),
1269 Value::BigInt(i) if *i >= 0 => Some(*i as u128),
1270 Value::Int128(i) if *i >= 0 => Some(*i as u128),
1271 _ => None,
1272 }
1273 }
1274
1275 pub fn as_blob(&self) -> Option<&[u8]> {
1276 match self {
1277 Value::Blob(bytes) => Some(bytes),
1278 _ => None,
1279 }
1280 }
1281
1282 pub fn is_null(&self) -> bool {
1283 matches!(self, Value::Null)
1284 }
1285
1286 fn is_integral_value(&self) -> bool {
1287 matches!(
1288 self,
1289 Value::Integer(_)
1290 | Value::BigInt(_)
1291 | Value::Int128(_)
1292 | Value::UInteger(_)
1293 | Value::UBigInt(_)
1294 | Value::UInt128(_)
1295 )
1296 }
1297
1298 pub fn is_float_like(&self) -> bool {
1299 matches!(self, Value::Float32(_) | Value::Float(_))
1300 }
1301}
1302
1303impl Eq for Value {}
1304
1305impl PartialOrd for Value {
1306 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1307 match (self, other) {
1308 (Value::Integer(a), Value::Integer(b)) => a.partial_cmp(b),
1309 (Value::BigInt(a), Value::BigInt(b)) => a.partial_cmp(b),
1310 (Value::Int128(a), Value::Int128(b)) => a.partial_cmp(b),
1311 (Value::UInteger(a), Value::UInteger(b)) => a.partial_cmp(b),
1312 (Value::UBigInt(a), Value::UBigInt(b)) => a.partial_cmp(b),
1313 (Value::UInt128(a), Value::UInt128(b)) => a.partial_cmp(b),
1314 (Value::Integer(a), Value::BigInt(b)) => (*a as i64).partial_cmp(b),
1315 (Value::BigInt(a), Value::Integer(b)) => a.partial_cmp(&(*b as i64)),
1316 (Value::Integer(a), Value::Int128(b)) => (*a as i128).partial_cmp(b),
1317 (Value::Int128(a), Value::Integer(b)) => a.partial_cmp(&(*b as i128)),
1318 (Value::BigInt(a), Value::Int128(b)) => (*a as i128).partial_cmp(b),
1319 (Value::Int128(a), Value::BigInt(b)) => a.partial_cmp(&(*b as i128)),
1320 (left, right) if left.is_integral_value() && right.is_integral_value() => {
1321 compare_integral_values(left, right)
1322 }
1323 (Value::Text(a), Value::Text(b)) => a.partial_cmp(b),
1324 (Value::Enum(a), Value::Enum(b)) => a.partial_cmp(b),
1325 (Value::Boolean(a), Value::Boolean(b)) => a.partial_cmp(b),
1326 (Value::Float32(a), Value::Float32(b)) => a.partial_cmp(b),
1327 (Value::Float(a), Value::Float(b)) => a.partial_cmp(b),
1328 (Value::Float32(a), Value::Float(b)) => (*a as f64).partial_cmp(b),
1329 (Value::Float(b), Value::Float32(a)) => b.partial_cmp(&(*a as f64)),
1330 (Value::Decimal(a), Value::Decimal(b)) => a.partial_cmp(b),
1331 (Value::Blob(a), Value::Blob(b)) => a.partial_cmp(b),
1332 (Value::Date(a), Value::Date(b)) => a.partial_cmp(b),
1333 (Value::Time(a), Value::Time(b)) => a.partial_cmp(b),
1334 (Value::DateTime(a), Value::DateTime(b)) => a.partial_cmp(b),
1335 (Value::TimeWithTimeZone(a), Value::TimeWithTimeZone(b)) => a.partial_cmp(b),
1336 (Value::IntervalYearMonth(a), Value::IntervalYearMonth(b)) => a.partial_cmp(b),
1337 (Value::IntervalDaySecond(a), Value::IntervalDaySecond(b)) => a.partial_cmp(b),
1338 (Value::Null, _) => Some(Ordering::Less),
1339 (_, Value::Null) => Some(Ordering::Greater),
1340 _ => None,
1341 }
1342 }
1343}
1344
1345fn compare_integral_values(left: &Value, right: &Value) -> Option<Ordering> {
1346 #[derive(Clone, Copy)]
1347 enum Integral {
1348 Signed(i128),
1349 Unsigned(u128),
1350 }
1351
1352 fn integral(value: &Value) -> Option<Integral> {
1353 match value {
1354 Value::Integer(value) => Some(Integral::Signed((*value).into())),
1355 Value::BigInt(value) => Some(Integral::Signed((*value).into())),
1356 Value::Int128(value) => Some(Integral::Signed(*value)),
1357 Value::UInteger(value) => Some(Integral::Unsigned((*value).into())),
1358 Value::UBigInt(value) => Some(Integral::Unsigned((*value).into())),
1359 Value::UInt128(value) => Some(Integral::Unsigned(*value)),
1360 _ => None,
1361 }
1362 }
1363
1364 match (integral(left)?, integral(right)?) {
1365 (Integral::Signed(left), Integral::Signed(right)) => left.partial_cmp(&right),
1366 (Integral::Unsigned(left), Integral::Unsigned(right)) => left.partial_cmp(&right),
1367 (Integral::Signed(left), Integral::Unsigned(right)) => {
1368 if left < 0 {
1369 Some(Ordering::Less)
1370 } else {
1371 (left as u128).partial_cmp(&right)
1372 }
1373 }
1374 (Integral::Unsigned(left), Integral::Signed(right)) => {
1375 if right < 0 {
1376 Some(Ordering::Greater)
1377 } else {
1378 left.partial_cmp(&(right as u128))
1379 }
1380 }
1381 }
1382}
1383
1384fn parse_time_components(input: &str, type_name: &str) -> Result<(u32, u32, u32)> {
1385 let parts = input.split(':').collect::<Vec<_>>();
1386 if parts.len() != 3
1387 || parts.iter().any(|part| part.len() != 2)
1388 || !parts
1389 .iter()
1390 .all(|part| part.chars().all(|ch| ch.is_ascii_digit()))
1391 {
1392 return Err(HematiteError::ParseError(format!(
1393 "Invalid {} value '{}'",
1394 type_name, input
1395 )));
1396 }
1397 let hour = parts[0].parse::<u32>().map_err(|_| {
1398 HematiteError::ParseError(format!("Invalid {} value '{}'", type_name, input))
1399 })?;
1400 let minute = parts[1].parse::<u32>().map_err(|_| {
1401 HematiteError::ParseError(format!("Invalid {} value '{}'", type_name, input))
1402 })?;
1403 let second = parts[2].parse::<u32>().map_err(|_| {
1404 HematiteError::ParseError(format!("Invalid {} value '{}'", type_name, input))
1405 })?;
1406 if hour > 23 || minute > 59 || second > 59 {
1407 return Err(HematiteError::ParseError(format!(
1408 "Invalid {} value '{}'",
1409 type_name, input
1410 )));
1411 }
1412 Ok((hour, minute, second))
1413}
1414
1415fn parse_timezone_offset(offset: &str, input: &str) -> Result<i16> {
1416 if offset.len() != 6
1417 || !matches!(offset.as_bytes()[0], b'+' | b'-')
1418 || offset.as_bytes()[3] != b':'
1419 || !offset[1..3].chars().all(|ch| ch.is_ascii_digit())
1420 || !offset[4..6].chars().all(|ch| ch.is_ascii_digit())
1421 {
1422 return Err(HematiteError::ParseError(format!(
1423 "Invalid TIME WITH TIME ZONE value '{}'",
1424 input
1425 )));
1426 }
1427
1428 let sign = if offset.as_bytes()[0] == b'-' { -1 } else { 1 };
1429 let hours = offset[1..3].parse::<i16>().map_err(|_| {
1430 HematiteError::ParseError(format!("Invalid TIME WITH TIME ZONE value '{}'", input))
1431 })?;
1432 let minutes = offset[4..6].parse::<i16>().map_err(|_| {
1433 HematiteError::ParseError(format!("Invalid TIME WITH TIME ZONE value '{}'", input))
1434 })?;
1435 if hours > 23 || minutes > 59 {
1436 return Err(HematiteError::ParseError(format!(
1437 "Invalid TIME WITH TIME ZONE value '{}'",
1438 input
1439 )));
1440 }
1441
1442 Ok(sign * (hours * 60 + minutes))
1443}
1444
1445fn validate_date_components(year: i32, month: u32, day: u32, input: &str) -> Result<()> {
1446 if !(1..=12).contains(&month) {
1447 return Err(HematiteError::ParseError(format!(
1448 "Invalid DATE value '{}'",
1449 input
1450 )));
1451 }
1452 let max_day = match month {
1453 1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
1454 4 | 6 | 9 | 11 => 30,
1455 2 if is_leap_year(year) => 29,
1456 2 => 28,
1457 _ => unreachable!(),
1458 };
1459 if day == 0 || day > max_day {
1460 return Err(HematiteError::ParseError(format!(
1461 "Invalid DATE value '{}'",
1462 input
1463 )));
1464 }
1465 Ok(())
1466}
1467
1468fn is_leap_year(year: i32) -> bool {
1469 (year % 4 == 0 && year % 100 != 0) || year % 400 == 0
1470}
1471
1472fn days_from_civil(year: i32, month: u32, day: u32) -> i32 {
1473 let year = year - if month <= 2 { 1 } else { 0 };
1474 let era = if year >= 0 { year } else { year - 399 } / 400;
1475 let yoe = year - era * 400;
1476 let month = month as i32;
1477 let day = day as i32;
1478 let doy = (153 * (month + if month > 2 { -3 } else { 9 }) + 2) / 5 + day - 1;
1479 let doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
1480 era * 146097 + doe - 719468
1481}
1482
1483fn civil_from_days(days: i32) -> (i32, u32, u32) {
1484 let z = days + 719468;
1485 let era = if z >= 0 { z } else { z - 146096 } / 146097;
1486 let doe = z - era * 146097;
1487 let yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
1488 let year = yoe + era * 400;
1489 let doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
1490 let mp = (5 * doy + 2) / 153;
1491 let day = doy - (153 * mp + 2) / 5 + 1;
1492 let month = mp + if mp < 10 { 3 } else { -9 };
1493 let year = year + if month <= 2 { 1 } else { 0 };
1494 (year, month as u32, day as u32)
1495}