1use super::{Type, Value};
2use crate::types::{Decimal, FromSqlError, FromSqlResult, OrderedMap};
3
4use crate::{Error, Result, Row};
5use arrow::{
6 array::{
7 Array, ArrayRef, DictionaryArray, FixedSizeListArray, LargeListArray, ListArray, MapArray, StringArray,
8 StructArray, UnionArray,
9 },
10 datatypes::{UInt8Type, UInt16Type, UInt32Type},
11};
12
13#[derive(Copy, Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
16pub enum TimeUnit {
17 Second,
19 Millisecond,
21 Microsecond,
23 Nanosecond,
25}
26
27impl TimeUnit {
28 pub fn to_micros(&self, value: i64) -> i64 {
30 match self {
31 Self::Second => value * 1_000_000,
32 Self::Millisecond => value * 1000,
33 Self::Microsecond => value,
34 Self::Nanosecond => value / 1000,
35 }
36 }
37}
38
39#[derive(Copy, Clone, Debug, PartialEq)]
48#[non_exhaustive]
49pub enum ValueRef<'a> {
50 Null,
52 Boolean(bool),
54 TinyInt(i8),
56 SmallInt(i16),
58 Int(i32),
60 BigInt(i64),
62 HugeInt(i128),
64 UHugeInt(u128),
71 UTinyInt(u8),
73 USmallInt(u16),
75 UInt(u32),
77 UBigInt(u64),
79 Float(f32),
81 Double(f64),
83 Decimal(Decimal),
88 Timestamp(TimeUnit, i64),
90 Text(&'a [u8]),
92 Blob(&'a [u8]),
94 Geometry(&'a [u8]),
100 Date32(i32),
102 Time64(TimeUnit, i64),
104 Interval {
106 months: i32,
108 days: i32,
110 nanos: i64,
112 },
113 List(ListType<'a>, usize),
115 Enum(EnumType<'a>, usize),
117 Struct(&'a StructArray, usize),
119 Array(&'a FixedSizeListArray, usize),
121 Map(&'a MapArray, usize),
123 Union(&'a ArrayRef, usize),
125}
126
127#[derive(Debug, Copy, Clone, PartialEq)]
129pub enum ListType<'a> {
130 Regular(&'a ListArray),
132 Large(&'a LargeListArray),
134}
135
136#[derive(Debug, Copy, Clone, PartialEq)]
138pub enum EnumType<'a> {
139 UInt8(&'a DictionaryArray<UInt8Type>),
141 UInt16(&'a DictionaryArray<UInt16Type>),
143 UInt32(&'a DictionaryArray<UInt32Type>),
145}
146
147impl ValueRef<'_> {
148 #[inline]
150 pub fn data_type(&self) -> Type {
151 match *self {
152 ValueRef::Null => Type::Null,
153 ValueRef::Boolean(_) => Type::Boolean,
154 ValueRef::TinyInt(_) => Type::TinyInt,
155 ValueRef::SmallInt(_) => Type::SmallInt,
156 ValueRef::Int(_) => Type::Int,
157 ValueRef::BigInt(_) => Type::BigInt,
158 ValueRef::HugeInt(_) => Type::HugeInt,
159 ValueRef::UHugeInt(_) => Type::UHugeInt,
160 ValueRef::UTinyInt(_) => Type::UTinyInt,
161 ValueRef::USmallInt(_) => Type::USmallInt,
162 ValueRef::UInt(_) => Type::UInt,
163 ValueRef::UBigInt(_) => Type::UBigInt,
164 ValueRef::Float(_) => Type::Float,
165 ValueRef::Double(_) => Type::Double,
166 ValueRef::Decimal(_) => Type::Decimal,
167 ValueRef::Timestamp(..) => Type::Timestamp,
168 ValueRef::Text(_) => Type::Text,
169 ValueRef::Blob(_) => Type::Blob,
170 ValueRef::Geometry(_) => Type::Geometry,
171 ValueRef::Date32(_) => Type::Date32,
172 ValueRef::Time64(..) => Type::Time64,
173 ValueRef::Interval { .. } => Type::Interval,
174 ValueRef::Struct(arr, _) => arr.data_type().into(),
175 ValueRef::Map(arr, _) => arr.data_type().into(),
176 ValueRef::Array(arr, _) => arr.data_type().into(),
177 ValueRef::List(arr, _) => match arr {
178 ListType::Large(arr) => arr.data_type().into(),
179 ListType::Regular(arr) => arr.data_type().into(),
180 },
181 ValueRef::Enum(..) => Type::Enum,
182 ValueRef::Union(arr, _) => arr.data_type().into(),
183 }
184 }
185
186 pub fn to_owned(&self) -> Value {
188 (*self).into()
189 }
190}
191
192impl<'a> ValueRef<'a> {
193 #[inline]
196 pub fn as_str(&self) -> FromSqlResult<&'a str> {
197 match *self {
198 ValueRef::Text(t) => std::str::from_utf8(t).map_err(|e| FromSqlError::Other(Box::new(e))),
199 ValueRef::Enum(ref enum_type, idx) => {
200 let (values, key) = match enum_type {
201 EnumType::UInt8(arr) => (arr.values(), arr.key(idx)),
202 EnumType::UInt16(arr) => (arr.values(), arr.key(idx)),
203 EnumType::UInt32(arr) => (arr.values(), arr.key(idx)),
204 };
205 let dict_key = key.ok_or(FromSqlError::InvalidType)?;
206 let string_array = values
207 .as_any()
208 .downcast_ref::<StringArray>()
209 .ok_or_else(|| FromSqlError::Other("enum dictionary values are not strings".into()))?;
210 if dict_key >= string_array.len() {
211 return Err(FromSqlError::Other(
212 format!("enum key {} out of bounds (len {})", dict_key, string_array.len()).into(),
213 ));
214 }
215 Ok(string_array.value(dict_key))
216 }
217 _ => Err(FromSqlError::InvalidType),
218 }
219 }
220
221 #[inline]
224 pub fn as_blob(&self) -> FromSqlResult<&'a [u8]> {
225 match *self {
226 ValueRef::Blob(b) | ValueRef::Text(b) | ValueRef::Geometry(b) => Ok(b),
227 _ => Err(FromSqlError::InvalidType),
228 }
229 }
230
231 #[inline]
234 pub fn as_geometry_wkb(&self) -> FromSqlResult<&'a [u8]> {
235 match *self {
236 ValueRef::Geometry(wkb) => Ok(wkb),
237 _ => Err(FromSqlError::InvalidType),
238 }
239 }
240}
241
242impl From<ValueRef<'_>> for Value {
243 #[inline]
244 fn from(borrowed: ValueRef<'_>) -> Self {
245 match borrowed {
246 ValueRef::Null => Self::Null,
247 ValueRef::Boolean(i) => Self::Boolean(i),
248 ValueRef::TinyInt(i) => Self::TinyInt(i),
249 ValueRef::SmallInt(i) => Self::SmallInt(i),
250 ValueRef::Int(i) => Self::Int(i),
251 ValueRef::BigInt(i) => Self::BigInt(i),
252 ValueRef::HugeInt(i) => Self::HugeInt(i),
253 ValueRef::UHugeInt(i) => Self::UHugeInt(i),
254 ValueRef::UTinyInt(i) => Self::UTinyInt(i),
255 ValueRef::USmallInt(i) => Self::USmallInt(i),
256 ValueRef::UInt(i) => Self::UInt(i),
257 ValueRef::UBigInt(i) => Self::UBigInt(i),
258 ValueRef::Float(i) => Self::Float(i),
259 ValueRef::Double(i) => Self::Double(i),
260 ValueRef::Decimal(i) => Self::Decimal(i),
261 ValueRef::Timestamp(tu, t) => Self::Timestamp(tu, t),
262 ValueRef::Text(s) => {
263 let s = std::str::from_utf8(s).expect("invalid UTF-8");
264 Self::Text(s.to_string())
265 }
266 ValueRef::Blob(b) => Self::Blob(b.to_vec()),
267 ValueRef::Geometry(wkb) => Self::Geometry(wkb.to_vec()),
268 ValueRef::Date32(d) => Self::Date32(d),
269 ValueRef::Time64(t, d) => Self::Time64(t, d),
270 ValueRef::Interval { months, days, nanos } => Self::Interval { months, days, nanos },
271 ValueRef::List(items, idx) => from_list_value(items, idx),
272 ValueRef::Enum(items, idx) => {
273 let dict_values = match items {
274 EnumType::UInt8(res) => res.values(),
275 EnumType::UInt16(res) => res.values(),
276 EnumType::UInt32(res) => res.values(),
277 }
278 .as_any()
279 .downcast_ref::<StringArray>()
280 .expect("Enum value is not a string");
281 let dict_key = match items {
282 EnumType::UInt8(res) => res.key(idx),
283 EnumType::UInt16(res) => res.key(idx),
284 EnumType::UInt32(res) => res.key(idx),
285 }
286 .unwrap();
287 Self::Enum(dict_values.value(dict_key).to_string())
288 }
289 ValueRef::Struct(items, idx) => from_struct(items, idx),
290 ValueRef::Map(arr, idx) => from_map(arr, idx),
291 ValueRef::Array(items, idx) => from_array(items, idx),
292 ValueRef::Union(column, idx) => from_union(column, idx),
293 }
294 }
295}
296
297fn from_list_value(items: ListType<'_>, idx: usize) -> Value {
298 match items {
299 ListType::Regular(items) => {
300 let offsets = items.offsets();
301 from_list(
302 offsets[idx].try_into().unwrap(),
303 offsets[idx + 1].try_into().unwrap(),
304 items.values(),
305 )
306 }
307 ListType::Large(items) => {
308 let offsets = items.offsets();
309 from_list(
310 offsets[idx].try_into().unwrap(),
311 offsets[idx + 1].try_into().unwrap(),
312 items.values(),
313 )
314 }
315 }
316}
317
318fn from_list(start: usize, end: usize, values: &ArrayRef) -> Value {
319 let capacity = end - start;
320 let mut list_vec = Vec::with_capacity(capacity);
321 list_vec.extend((start..end).map(|row| Row::value_ref_internal(row, values).to_owned()));
322 Value::List(list_vec)
323}
324
325fn from_struct(items: &StructArray, idx: usize) -> Value {
326 let capacity = items.columns().len();
327 let mut value = Vec::with_capacity(capacity);
328 value.extend(
329 items
330 .columns()
331 .iter()
332 .zip(items.fields().iter().map(|f| f.name().to_owned()))
333 .map(|(column, name)| -> (String, Value) { (name, Row::value_ref_internal(idx, column).to_owned()) }),
334 );
335 Value::Struct(OrderedMap::from(value))
336}
337
338fn from_map(arr: &MapArray, idx: usize) -> Value {
339 let keys = arr.keys();
340 let values = arr.values();
341 let offsets = arr.offsets();
342 let range = offsets[idx]..offsets[idx + 1];
343 let capacity = range.len();
344 let mut map_vec = Vec::with_capacity(capacity);
345 map_vec.extend(range.map(|row| {
346 let row = row.try_into().unwrap();
347 let key = Row::value_ref_internal(row, keys).to_owned();
348 let value = Row::value_ref_internal(row, values).to_owned();
349 (key, value)
350 }));
351 Value::Map(OrderedMap::from(map_vec))
352}
353
354fn from_array(items: &FixedSizeListArray, idx: usize) -> Value {
355 let value_length = usize::try_from(items.value_length()).unwrap();
356 let range = (idx * value_length)..((idx + 1) * value_length);
357 let mut array_vec = Vec::with_capacity(value_length);
358 array_vec.extend(range.map(|row| Row::value_ref_internal(row, items.values()).to_owned()));
359 Value::Array(array_vec)
360}
361
362fn from_union(column: &ArrayRef, idx: usize) -> Value {
363 let column = column.as_any().downcast_ref::<UnionArray>().unwrap();
364 let type_id = column.type_id(idx);
365 let value_offset = column.value_offset(idx);
369 let tag = Row::value_ref_internal(value_offset, column.child(type_id));
370 Value::Union(Box::new(tag.to_owned()))
371}
372
373impl<'a> From<&'a str> for ValueRef<'a> {
374 #[inline]
375 fn from(s: &str) -> ValueRef<'_> {
376 ValueRef::Text(s.as_bytes())
377 }
378}
379
380impl<'a> From<&'a [u8]> for ValueRef<'a> {
381 #[inline]
382 fn from(s: &[u8]) -> ValueRef<'_> {
383 ValueRef::Blob(s)
384 }
385}
386
387impl From<Decimal> for ValueRef<'_> {
388 #[inline]
389 fn from(decimal: Decimal) -> Self {
390 Self::Decimal(decimal)
391 }
392}
393
394pub(crate) fn value_ref_from_value<'a>(
395 value: &'a Value,
396 unsupported_message: impl FnOnce(&'static str) -> String,
397) -> Result<ValueRef<'a>> {
398 if let Some(variant) = unsupported_value_variant(value) {
399 return Err(Error::ToSqlConversionFailure(unsupported_message(variant).into()));
400 }
401
402 Ok(ValueRef::from(value))
403}
404
405pub(crate) fn binding_unsupported_value(value_type: impl std::fmt::Display) -> String {
406 format!("binding {value_type} parameters is not yet supported")
407}
408
409fn unsupported_value_variant(value: &Value) -> Option<&'static str> {
410 match value {
411 Value::Null
412 | Value::Boolean(_)
413 | Value::TinyInt(_)
414 | Value::SmallInt(_)
415 | Value::Int(_)
416 | Value::BigInt(_)
417 | Value::HugeInt(_)
418 | Value::UHugeInt(_)
419 | Value::UTinyInt(_)
420 | Value::USmallInt(_)
421 | Value::UInt(_)
422 | Value::UBigInt(_)
423 | Value::Float(_)
424 | Value::Double(_)
425 | Value::Decimal(_)
426 | Value::Timestamp(_, _)
427 | Value::Text(_)
428 | Value::Blob(_)
429 | Value::Geometry(_)
430 | Value::Date32(_)
431 | Value::Time64(_, _)
432 | Value::Interval { .. } => None,
433 Value::List(_) => Some("List"),
434 Value::Array(_) => Some("Array"),
435 Value::Struct(_) => Some("Struct"),
436 Value::Map(_) => Some("Map"),
437 Value::Union(_) => Some("Union"),
438 Value::Enum(_) => Some("Enum"),
439 }
440}
441
442impl<'a> From<&'a Value> for ValueRef<'a> {
443 #[inline]
451 fn from(value: &'a Value) -> Self {
452 match *value {
453 Value::Null => ValueRef::Null,
454 Value::Boolean(i) => ValueRef::Boolean(i),
455 Value::TinyInt(i) => ValueRef::TinyInt(i),
456 Value::SmallInt(i) => ValueRef::SmallInt(i),
457 Value::Int(i) => ValueRef::Int(i),
458 Value::BigInt(i) => ValueRef::BigInt(i),
459 Value::HugeInt(i) => ValueRef::HugeInt(i),
460 Value::UHugeInt(i) => ValueRef::UHugeInt(i),
461 Value::UTinyInt(i) => ValueRef::UTinyInt(i),
462 Value::USmallInt(i) => ValueRef::USmallInt(i),
463 Value::UInt(i) => ValueRef::UInt(i),
464 Value::UBigInt(i) => ValueRef::UBigInt(i),
465 Value::Float(i) => ValueRef::Float(i),
466 Value::Double(i) => ValueRef::Double(i),
467 Value::Decimal(i) => ValueRef::Decimal(i),
468 Value::Timestamp(tu, t) => ValueRef::Timestamp(tu, t),
469 Value::Text(ref s) => ValueRef::Text(s.as_bytes()),
470 Value::Blob(ref b) => ValueRef::Blob(b),
471 Value::Geometry(ref wkb) => ValueRef::Geometry(wkb),
472 Value::Date32(d) => ValueRef::Date32(d),
473 Value::Time64(t, d) => ValueRef::Time64(t, d),
474 Value::Interval { months, days, nanos } => ValueRef::Interval { months, days, nanos },
475 Value::Enum(..)
476 | Value::List(..)
477 | Value::Struct(..)
478 | Value::Map(..)
479 | Value::Array(..)
480 | Value::Union(..) => {
481 let variant = unsupported_value_variant(value).expect("unsupported Value variant");
482 panic!("ValueRef::from(&Value::{variant}) is not supported; use value_ref_from_value")
483 }
484 }
485 }
486}
487
488impl<'a, T> From<Option<T>> for ValueRef<'a>
489where
490 T: Into<Self>,
491{
492 #[inline]
493 fn from(s: Option<T>) -> Self {
494 match s {
495 Some(x) => x.into(),
496 None => ValueRef::Null,
497 }
498 }
499}
500
501#[cfg(test)]
502mod tests {
503 use crate::types::{Type, Value, ValueRef};
504 use crate::{Connection, Result};
505
506 #[test]
507 #[should_panic(expected = "ValueRef::from(&Value::List)")]
508 fn value_ref_from_list_value_panics() {
509 let value = Value::List(vec![Value::Int(1)]);
510 let _ = ValueRef::from(&value);
511 }
512
513 #[test]
514 fn test_geometry_ref_is_wkb_bytes() {
515 use crate::types::FromSql;
516
517 let wkb = &[1_u8, 1, 0, 0, 0];
518 let geometry = ValueRef::Geometry(wkb);
519
520 assert_eq!(geometry.data_type(), Type::Geometry);
521 assert_eq!(geometry.as_geometry_wkb().unwrap(), wkb);
522 assert_eq!(geometry.as_blob().unwrap(), wkb);
523 assert!(geometry.as_str().is_err());
524 assert!(ValueRef::Blob(wkb).as_geometry_wkb().is_err());
525 assert_eq!(ValueRef::Blob(wkb).as_blob().unwrap(), wkb);
526 assert_eq!(Vec::<u8>::column_result(geometry).unwrap(), wkb.to_vec());
527 assert_eq!(geometry.to_owned(), Value::Geometry(wkb.to_vec()));
528 }
529
530 #[test]
531 fn test_text_ref_is_convertible_to_bytes() {
532 use crate::types::FromSql;
533
534 let text = ValueRef::Text(b"goose");
535
536 assert_eq!(text.as_blob().unwrap(), b"goose");
537 assert_eq!(Vec::<u8>::column_result(text).unwrap(), b"goose".to_vec());
538 }
539
540 #[test]
541 fn test_list_types() -> Result<()> {
542 let conn = Connection::open_in_memory()?;
543 conn.execute(
544 "CREATE TABLE test_table (float_list FLOAT[], double_list DOUBLE[], int_list INT[])",
545 [],
546 )?;
547 conn.execute("INSERT INTO test_table VALUES ([1.5, 2.5], [3.5, 4.5], [1, 2])", [])?;
548
549 let mut stmt = conn.prepare("SELECT float_list, double_list, int_list FROM test_table")?;
550 let mut rows = stmt.query([])?;
551 let row = rows.next()?.unwrap();
552
553 let float_list = row.get_ref_unwrap(0);
554 assert!(
555 matches!(float_list.data_type(), Type::List(ref inner_type) if **inner_type == Type::Float),
556 "Expected Type::List(Type::Float), got {:?}",
557 float_list.data_type()
558 );
559
560 let double_list = row.get_ref_unwrap(1);
561 assert!(
562 matches!(double_list.data_type(), Type::List(ref inner_type) if **inner_type == Type::Double),
563 "Expected Type::List(Type::Double), got {:?}",
564 double_list.data_type()
565 );
566
567 let int_list = row.get_ref_unwrap(2);
568 assert!(
569 matches!(int_list.data_type(), Type::List(ref inner_type) if **inner_type == Type::Int),
570 "Expected Type::List(Type::Int), got {:?}",
571 int_list.data_type()
572 );
573
574 Ok(())
575 }
576}