1#![allow(
36 clippy::cast_precision_loss,
37 reason = "column accessor: explicit user-requested widening"
38)]
39
40use std::sync::Arc;
41
42use crate::protocol::message::backend::DataRowBody;
43use crate::types::FromHyperBinary;
44
45use super::error::{Error, ErrorKind, Result};
46use super::statement::Column;
47
48fn decode_bytea_hex(data: &[u8]) -> Option<Vec<u8>> {
54 if data.len() >= 2 && data[0] == b'\\' && data[1] == b'x' {
55 let hex_data = &data[2..];
56 if hex_data.len() % 2 != 0 {
57 return None;
58 }
59 let mut result = Vec::with_capacity(hex_data.len() / 2);
60 for chunk in hex_data.chunks(2) {
61 let high = hex_digit_to_value(chunk[0])?;
62 let low = hex_digit_to_value(chunk[1])?;
63 result.push((high << 4) | low);
64 }
65 Some(result)
66 } else {
67 Some(data.to_vec())
68 }
69}
70
71#[inline]
72fn hex_digit_to_value(c: u8) -> Option<u8> {
73 match c {
74 b'0'..=b'9' => Some(c - b'0'),
75 b'a'..=b'f' => Some(c - b'a' + 10),
76 b'A'..=b'F' => Some(c - b'A' + 10),
77 _ => None,
78 }
79}
80
81pub struct Row {
105 columns: Arc<Vec<Column>>,
106 data: DataRowBody,
107 ranges: Vec<Option<std::ops::Range<usize>>>,
108}
109
110impl Row {
111 pub(crate) fn new(columns: Arc<Vec<Column>>, data: DataRowBody) -> Result<Self> {
112 let ranges: Vec<_> = data
113 .ranges()
114 .map(|r| r.map_err(|e| Error::protocol(format!("invalid data row: {e}"))))
115 .collect::<Result<Vec<_>>>()?;
116 Ok(Row {
117 columns,
118 data,
119 ranges,
120 })
121 }
122
123 #[inline]
125 pub fn column_count(&self) -> usize {
126 self.columns.len()
127 }
128
129 #[inline]
131 pub fn is_empty(&self) -> bool {
132 self.columns.is_empty()
133 }
134
135 #[inline]
137 pub fn columns(&self) -> &[Column] {
138 &self.columns
139 }
140
141 #[inline]
143 pub fn get_bytes(&self, idx: usize) -> Option<&[u8]> {
144 match self.ranges.get(idx)? {
145 Some(range) => Some(&self.data.buffer()[range.start..range.end]),
146 None => None,
147 }
148 }
149
150 #[inline]
152 pub fn is_null(&self, idx: usize) -> bool {
153 self.ranges
154 .get(idx)
155 .map_or(true, std::option::Option::is_none)
156 }
157
158 #[inline]
159 fn column_format(&self, idx: usize) -> super::statement::ColumnFormat {
160 self.columns
161 .get(idx)
162 .map(super::statement::Column::format)
163 .unwrap_or_default()
164 }
165
166 #[inline]
168 pub fn get_i16(&self, idx: usize) -> Option<i16> {
169 let bytes = self.get_bytes(idx)?;
170 if self.column_format(idx).is_binary() && bytes.len() == 2 {
171 Some(i16::from_le_bytes([bytes[0], bytes[1]]))
172 } else if !self.column_format(idx).is_binary() {
173 std::str::from_utf8(bytes).ok()?.trim().parse().ok()
174 } else {
175 None
176 }
177 }
178
179 #[inline]
181 pub fn get_i32(&self, idx: usize) -> Option<i32> {
182 let bytes = self.get_bytes(idx)?;
183 if self.column_format(idx).is_binary() && bytes.len() == 4 {
184 Some(i32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
185 } else if !self.column_format(idx).is_binary() {
186 std::str::from_utf8(bytes).ok()?.trim().parse().ok()
187 } else {
188 None
189 }
190 }
191
192 #[inline]
194 pub fn get_i64(&self, idx: usize) -> Option<i64> {
195 let bytes = self.get_bytes(idx)?;
196 if self.column_format(idx).is_binary() && bytes.len() == 8 {
197 Some(i64::from_le_bytes([
198 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
199 ]))
200 } else if !self.column_format(idx).is_binary() {
201 std::str::from_utf8(bytes).ok()?.trim().parse().ok()
202 } else {
203 None
204 }
205 }
206
207 #[inline]
209 pub fn get_f32(&self, idx: usize) -> Option<f32> {
210 let bytes = self.get_bytes(idx)?;
211 if self.column_format(idx).is_binary() && bytes.len() == 4 {
212 Some(f32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
213 } else if !self.column_format(idx).is_binary() {
214 std::str::from_utf8(bytes).ok()?.trim().parse().ok()
215 } else {
216 None
217 }
218 }
219
220 #[inline]
222 pub fn get_f64(&self, idx: usize) -> Option<f64> {
223 let bytes = self.get_bytes(idx)?;
224 if self.column_format(idx).is_binary() && bytes.len() == 8 {
225 Some(f64::from_le_bytes([
226 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
227 ]))
228 } else if !self.column_format(idx).is_binary() {
229 std::str::from_utf8(bytes).ok()?.trim().parse().ok()
230 } else {
231 None
232 }
233 }
234
235 #[inline]
237 pub fn get_bool(&self, idx: usize) -> Option<bool> {
238 let bytes = self.get_bytes(idx)?;
239 if self.column_format(idx).is_binary() && bytes.len() == 1 {
240 match bytes[0] {
241 0 => Some(false),
242 1 => Some(true),
243 _ => None,
244 }
245 } else {
246 match bytes {
247 [b't' | b'T'] => Some(true),
248 [b'f' | b'F'] => Some(false),
249 b"true" => Some(true),
250 b"false" => Some(false),
251 _ => None,
252 }
253 }
254 }
255
256 #[inline]
258 pub fn get_string(&self, idx: usize) -> Option<String> {
259 let bytes = self.get_bytes(idx)?;
260 String::from_utf8(bytes.to_vec()).ok()
261 }
262
263 #[inline]
265 pub fn get_bytes_owned(&self, idx: usize) -> Option<Vec<u8>> {
266 let bytes = self.get_bytes(idx)?;
267 if self.column_format(idx).is_binary() {
268 Some(bytes.to_vec())
269 } else {
270 decode_bytea_hex(bytes)
271 }
272 }
273
274 #[inline]
278 pub fn get<T: FromHyperBinary>(&self, idx: usize) -> Option<T> {
279 let bytes = self.get_bytes(idx)?;
280 T::from_hyper_binary(bytes).ok()
281 }
282
283 pub fn get_by_name<T: FromHyperBinary>(&self, name: &str) -> Option<T> {
287 let idx = self.column_index(name).ok()?;
288 self.get(idx)
289 }
290
291 pub fn column_index(&self, name: &str) -> Result<usize> {
298 self.columns
299 .iter()
300 .position(|c| c.name() == name)
301 .ok_or_else(|| Error::new(ErrorKind::Query, format!("column not found: {name}")))
302 }
303}
304
305impl std::fmt::Debug for Row {
306 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
307 f.debug_struct("Row")
308 .field("columns", &self.columns)
309 .field("column_count", &self.column_count())
310 .finish_non_exhaustive()
311 }
312}
313
314#[derive(Debug)]
342pub struct StreamRow {
343 data: DataRowBody,
344}
345
346impl StreamRow {
347 #[inline]
348 pub(crate) fn new(data: DataRowBody) -> Self {
349 StreamRow { data }
350 }
351
352 #[inline]
354 pub fn column_count(&self) -> usize {
355 self.data.column_count() as usize
356 }
357
358 #[inline]
360 pub fn get_bytes(&self, idx: usize) -> Option<&[u8]> {
361 self.data.get_column_bytes(idx)
362 }
363
364 #[inline]
366 pub fn is_null(&self, idx: usize) -> bool {
367 self.data.is_column_null(idx)
368 }
369
370 #[inline]
372 pub fn get_i16(&self, idx: usize) -> Option<i16> {
373 let bytes = self.get_bytes(idx)?;
374 (bytes.len() == 2).then(|| i16::from_le_bytes([bytes[0], bytes[1]]))
375 }
376
377 #[inline]
379 pub fn get_i32(&self, idx: usize) -> Option<i32> {
380 let bytes = self.get_bytes(idx)?;
381 (bytes.len() == 4).then(|| i32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
382 }
383
384 #[inline]
386 pub fn get_i64(&self, idx: usize) -> Option<i64> {
387 let bytes = self.get_bytes(idx)?;
388 (bytes.len() == 8).then(|| {
389 i64::from_le_bytes([
390 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
391 ])
392 })
393 }
394
395 #[inline]
397 pub fn get_f32(&self, idx: usize) -> Option<f32> {
398 let bytes = self.get_bytes(idx)?;
399 (bytes.len() == 4).then(|| f32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
400 }
401
402 #[inline]
404 pub fn get_f64(&self, idx: usize) -> Option<f64> {
405 let bytes = self.get_bytes(idx)?;
406 (bytes.len() == 8).then(|| {
407 f64::from_le_bytes([
408 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
409 ])
410 })
411 }
412
413 #[inline]
415 pub fn get_bool(&self, idx: usize) -> Option<bool> {
416 let bytes = self.get_bytes(idx)?;
417 (bytes.len() == 1).then(|| match bytes[0] {
418 b't' | b'T' | 1 => Some(true),
419 b'f' | b'F' | 0 => Some(false),
420 _ => None,
421 })?
422 }
423
424 #[inline]
426 pub fn get_string(&self, idx: usize) -> Option<String> {
427 let bytes = self.get_bytes(idx)?;
428 String::from_utf8(bytes.to_vec()).ok()
429 }
430
431 #[inline]
435 pub fn get<T: FromBinaryValue>(&self, idx: usize) -> Option<T> {
436 T::from_stream_row(self, idx)
437 }
438
439 #[inline]
441 pub fn to_batch(self) -> BatchRow {
442 BatchRow::from_stream(self)
443 }
444
445 #[inline]
447 pub fn into_data(self) -> DataRowBody {
448 self.data
449 }
450}
451
452#[derive(Debug)]
480pub struct BatchRow {
481 data: DataRowBody,
482 offsets: Vec<Option<(usize, usize)>>,
483}
484
485impl BatchRow {
486 #[inline]
488 pub fn new(data: DataRowBody) -> Self {
489 let offsets = data.compute_all_offsets();
490 BatchRow { data, offsets }
491 }
492
493 #[inline]
495 pub fn from_stream(row: StreamRow) -> Self {
496 Self::new(row.data)
497 }
498
499 #[inline]
501 pub fn column_count(&self) -> usize {
502 self.offsets.len()
503 }
504
505 #[inline]
507 pub fn get_bytes(&self, idx: usize) -> Option<&[u8]> {
508 let (start, end) = self.offsets.get(idx)?.as_ref().copied()?;
509 self.data.buffer().get(start..end)
510 }
511
512 #[inline]
514 pub fn is_null(&self, idx: usize) -> bool {
515 self.offsets
516 .get(idx)
517 .map_or(true, std::option::Option::is_none)
518 }
519
520 #[inline]
522 pub fn get_i16(&self, idx: usize) -> Option<i16> {
523 let bytes = self.get_bytes(idx)?;
524 (bytes.len() == 2).then(|| i16::from_le_bytes([bytes[0], bytes[1]]))
525 }
526
527 #[inline]
529 pub fn get_i32(&self, idx: usize) -> Option<i32> {
530 let bytes = self.get_bytes(idx)?;
531 (bytes.len() == 4).then(|| i32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
532 }
533
534 #[inline]
536 pub fn get_i64(&self, idx: usize) -> Option<i64> {
537 let bytes = self.get_bytes(idx)?;
538 (bytes.len() == 8).then(|| {
539 i64::from_le_bytes([
540 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
541 ])
542 })
543 }
544
545 #[inline]
547 pub fn get_f32(&self, idx: usize) -> Option<f32> {
548 let bytes = self.get_bytes(idx)?;
549 (bytes.len() == 4).then(|| f32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
550 }
551
552 #[inline]
554 pub fn get_f64(&self, idx: usize) -> Option<f64> {
555 let bytes = self.get_bytes(idx)?;
556 (bytes.len() == 8).then(|| {
557 f64::from_le_bytes([
558 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
559 ])
560 })
561 }
562
563 #[inline]
565 pub fn get_bool(&self, idx: usize) -> Option<bool> {
566 let bytes = self.get_bytes(idx)?;
567 (bytes.len() == 1).then(|| match bytes[0] {
568 b't' | b'T' | 1 => Some(true),
569 b'f' | b'F' | 0 => Some(false),
570 _ => None,
571 })?
572 }
573
574 #[inline]
576 pub fn get_string(&self, idx: usize) -> Option<String> {
577 let bytes = self.get_bytes(idx)?;
578 String::from_utf8(bytes.to_vec()).ok()
579 }
580
581 #[inline]
585 pub fn get<T: FromBinaryValue>(&self, idx: usize) -> Option<T> {
586 T::from_batch_row(self, idx)
587 }
588}
589
590pub trait FromBinaryValue: Sized {
596 fn from_stream_row(row: &StreamRow, idx: usize) -> Option<Self>;
598
599 fn from_batch_row(row: &BatchRow, idx: usize) -> Option<Self>;
601}
602
603impl FromBinaryValue for bool {
604 #[inline]
605 fn from_stream_row(row: &StreamRow, idx: usize) -> Option<Self> {
606 row.get_bool(idx)
607 }
608 #[inline]
609 fn from_batch_row(row: &BatchRow, idx: usize) -> Option<Self> {
610 row.get_bool(idx)
611 }
612}
613
614impl FromBinaryValue for i16 {
615 #[inline]
616 fn from_stream_row(row: &StreamRow, idx: usize) -> Option<Self> {
617 row.get_i16(idx)
618 }
619 #[inline]
620 fn from_batch_row(row: &BatchRow, idx: usize) -> Option<Self> {
621 row.get_i16(idx)
622 }
623}
624
625impl FromBinaryValue for i32 {
626 #[inline]
627 fn from_stream_row(row: &StreamRow, idx: usize) -> Option<Self> {
628 row.get_i32(idx).or_else(|| row.get_i16(idx).map(i32::from))
629 }
630 #[inline]
631 fn from_batch_row(row: &BatchRow, idx: usize) -> Option<Self> {
632 row.get_i32(idx).or_else(|| row.get_i16(idx).map(i32::from))
633 }
634}
635
636impl FromBinaryValue for i64 {
637 #[inline]
638 fn from_stream_row(row: &StreamRow, idx: usize) -> Option<Self> {
639 row.get_i64(idx)
640 .or_else(|| row.get_i32(idx).map(i64::from))
641 .or_else(|| row.get_i16(idx).map(i64::from))
642 }
643 #[inline]
644 fn from_batch_row(row: &BatchRow, idx: usize) -> Option<Self> {
645 row.get_i64(idx)
646 .or_else(|| row.get_i32(idx).map(i64::from))
647 .or_else(|| row.get_i16(idx).map(i64::from))
648 }
649}
650
651impl FromBinaryValue for f32 {
652 #[inline]
653 fn from_stream_row(row: &StreamRow, idx: usize) -> Option<Self> {
654 row.get_f32(idx)
655 }
656 #[inline]
657 fn from_batch_row(row: &BatchRow, idx: usize) -> Option<Self> {
658 row.get_f32(idx)
659 }
660}
661
662impl FromBinaryValue for f64 {
663 #[inline]
664 fn from_stream_row(row: &StreamRow, idx: usize) -> Option<Self> {
665 row.get_f64(idx)
666 .or_else(|| row.get_f32(idx).map(f64::from))
667 .or_else(|| row.get_i64(idx).map(|v| v as f64))
668 .or_else(|| row.get_i32(idx).map(f64::from))
669 }
670 #[inline]
671 fn from_batch_row(row: &BatchRow, idx: usize) -> Option<Self> {
672 row.get_f64(idx)
673 .or_else(|| row.get_f32(idx).map(f64::from))
674 .or_else(|| row.get_i64(idx).map(|v| v as f64))
675 .or_else(|| row.get_i32(idx).map(f64::from))
676 }
677}
678
679impl FromBinaryValue for String {
680 #[inline]
681 fn from_stream_row(row: &StreamRow, idx: usize) -> Option<Self> {
682 row.get_string(idx)
683 }
684 #[inline]
685 fn from_batch_row(row: &BatchRow, idx: usize) -> Option<Self> {
686 row.get_string(idx)
687 }
688}
689
690impl FromBinaryValue for Vec<u8> {
691 #[inline]
692 fn from_stream_row(row: &StreamRow, idx: usize) -> Option<Self> {
693 row.get_bytes(idx).map(<[u8]>::to_vec)
694 }
695 #[inline]
696 fn from_batch_row(row: &BatchRow, idx: usize) -> Option<Self> {
697 row.get_bytes(idx).map(<[u8]>::to_vec)
698 }
699}
700
701impl FromBinaryValue for crate::types::Date {
702 #[inline]
703 fn from_stream_row(row: &StreamRow, idx: usize) -> Option<Self> {
704 let bytes = row.get_bytes(idx)?;
705 crate::types::FromHyperBinary::from_hyper_binary(bytes).ok()
706 }
707 #[inline]
708 fn from_batch_row(row: &BatchRow, idx: usize) -> Option<Self> {
709 let bytes = row.get_bytes(idx)?;
710 crate::types::FromHyperBinary::from_hyper_binary(bytes).ok()
711 }
712}
713
714impl FromBinaryValue for crate::types::Time {
715 #[inline]
716 fn from_stream_row(row: &StreamRow, idx: usize) -> Option<Self> {
717 let bytes = row.get_bytes(idx)?;
718 crate::types::FromHyperBinary::from_hyper_binary(bytes).ok()
719 }
720 #[inline]
721 fn from_batch_row(row: &BatchRow, idx: usize) -> Option<Self> {
722 let bytes = row.get_bytes(idx)?;
723 crate::types::FromHyperBinary::from_hyper_binary(bytes).ok()
724 }
725}
726
727impl FromBinaryValue for crate::types::Timestamp {
728 #[inline]
729 fn from_stream_row(row: &StreamRow, idx: usize) -> Option<Self> {
730 let bytes = row.get_bytes(idx)?;
731 crate::types::FromHyperBinary::from_hyper_binary(bytes).ok()
732 }
733 #[inline]
734 fn from_batch_row(row: &BatchRow, idx: usize) -> Option<Self> {
735 let bytes = row.get_bytes(idx)?;
736 crate::types::FromHyperBinary::from_hyper_binary(bytes).ok()
737 }
738}
739
740impl FromBinaryValue for crate::types::Interval {
741 #[inline]
742 fn from_stream_row(row: &StreamRow, idx: usize) -> Option<Self> {
743 let bytes = row.get_bytes(idx)?;
744 crate::types::FromHyperBinary::from_hyper_binary(bytes).ok()
745 }
746 #[inline]
747 fn from_batch_row(row: &BatchRow, idx: usize) -> Option<Self> {
748 let bytes = row.get_bytes(idx)?;
749 crate::types::FromHyperBinary::from_hyper_binary(bytes).ok()
750 }
751}
752
753impl FromBinaryValue for crate::types::OffsetTimestamp {
754 #[inline]
755 fn from_stream_row(row: &StreamRow, idx: usize) -> Option<Self> {
756 let bytes = row.get_bytes(idx)?;
757 crate::types::FromHyperBinary::from_hyper_binary(bytes).ok()
758 }
759 #[inline]
760 fn from_batch_row(row: &BatchRow, idx: usize) -> Option<Self> {
761 let bytes = row.get_bytes(idx)?;
762 crate::types::FromHyperBinary::from_hyper_binary(bytes).ok()
763 }
764}