1pub use self::{
58 decimal::{Decimal, DecimalError},
59 from_sql::{FromSql, FromSqlError, FromSqlResult},
60 ordered_map::OrderedMap,
61 string::DuckString,
62 to_sql::{ToSql, ToSqlOutput},
63 value::Value,
64 value_ref::{EnumType, ListType, TimeUnit, ValueRef},
65};
66pub(crate) use decimal::to_duckdb_decimal;
67pub(crate) use value_ref::{binding_unsupported_value, value_ref_from_value};
68
69use arrow::datatypes::DataType;
70use std::fmt;
71
72use crate::ffi;
73
74#[cfg(feature = "chrono")]
75mod chrono;
76mod from_sql;
77#[cfg(feature = "serde_json")]
78mod serde_json;
79mod to_sql;
80#[cfg(feature = "url")]
81mod url;
82mod value;
83mod value_ref;
84
85mod decimal;
86mod ordered_map;
87mod string;
88
89pub(crate) fn to_duckdb_hugeint(i: i128) -> ffi::duckdb_hugeint {
90 ffi::duckdb_hugeint {
91 lower: i as u64,
92 upper: (i >> 64) as i64,
93 }
94}
95
96pub(crate) fn to_duckdb_uhugeint(i: u128) -> ffi::duckdb_uhugeint {
97 ffi::duckdb_uhugeint {
98 lower: i as u64,
99 upper: (i >> 64) as u64,
100 }
101}
102
103#[derive(Copy, Clone)]
116pub struct Null;
117
118#[derive(Clone, Debug, PartialEq, Eq)]
121#[non_exhaustive]
122pub enum Type {
123 Null,
125 Boolean,
127 TinyInt,
129 SmallInt,
131 Int,
133 BigInt,
135 HugeInt,
137 UHugeInt,
139 UTinyInt,
141 USmallInt,
143 UInt,
145 UBigInt,
147 Float,
149 Double,
151 Decimal,
153 Timestamp,
155 Text,
157 Blob,
159 Geometry,
161 Date32,
163 Time64,
165 Interval,
167 List(Box<Type>),
169 Enum,
171 Struct(Vec<(String, Type)>),
173 Map(Box<Type>, Box<Type>),
175 Array(Box<Type>, u32),
177 Union,
179 Variant,
181 Any,
183}
184
185impl From<&DataType> for Type {
186 fn from(value: &DataType) -> Self {
187 match value {
188 DataType::Null => Self::Null,
189 DataType::Boolean => Self::Boolean,
190 DataType::Int8 => Self::TinyInt,
191 DataType::Int16 => Self::SmallInt,
192 DataType::Int32 => Self::Int,
193 DataType::Int64 => Self::BigInt,
194 DataType::UInt8 => Self::UTinyInt,
195 DataType::UInt16 => Self::USmallInt,
196 DataType::UInt32 => Self::UInt,
197 DataType::UInt64 => Self::UBigInt,
198 DataType::Float32 => Self::Float, DataType::Float64 => Self::Double, DataType::Timestamp(_, _) => Self::Timestamp,
202 DataType::Date32 => Self::Date32,
203 DataType::Time64(_) => Self::Time64,
206 DataType::Binary => Self::Blob,
209 DataType::FixedSizeBinary(_) => Self::Blob,
210 DataType::LargeUtf8 | DataType::Utf8 => Self::Text,
212 DataType::List(inner) => Self::List(Box::new(Self::from(inner.data_type()))),
213 DataType::FixedSizeList(field, size) => Self::Array(
214 Box::new(Self::from(field.data_type())),
215 (*size)
216 .try_into()
217 .expect("Arrow FixedSizeList size must be non-negative"),
218 ),
219 DataType::Struct(inner) => {
221 let capacity = inner.len();
222 let mut struct_vec = Vec::with_capacity(capacity);
223 struct_vec.extend(inner.iter().map(|f| (f.name().to_owned(), Self::from(f.data_type()))));
224 Self::Struct(struct_vec)
225 }
226 DataType::LargeList(inner) => Self::List(Box::new(Self::from(inner.data_type()))),
227 DataType::Union(_, _) => Self::Union,
228 DataType::Decimal32(..) | DataType::Decimal64(..) | DataType::Decimal128(..) | DataType::Decimal256(..) => {
231 Self::Decimal
232 }
233 DataType::Map(field, ..) => {
234 let data_type = field.data_type();
235 match data_type {
236 DataType::Struct(fields) if fields.len() == 2 => Self::Map(
237 Box::new(Self::from(fields[0].data_type())),
238 Box::new(Self::from(fields[1].data_type())),
239 ),
240 DataType::Struct(fields) => {
241 panic!(
242 "Arrow Map child struct must have exactly two fields, got {}",
243 fields.len()
244 )
245 }
246 _ => panic!("Arrow Map child type must be Struct(key, value), got {data_type}"),
247 }
248 }
249 res => unimplemented!("{}", res),
250 }
251 }
252}
253
254impl fmt::Display for Type {
255 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
256 match *self {
257 Self::Null => f.pad("Null"),
258 Self::Boolean => f.pad("Boolean"),
259 Self::TinyInt => f.pad("TinyInt"),
260 Self::SmallInt => f.pad("SmallInt"),
261 Self::Int => f.pad("Int"),
262 Self::BigInt => f.pad("BigInt"),
263 Self::HugeInt => f.pad("HugeInt"),
264 Self::UHugeInt => f.pad("UHugeInt"),
265 Self::UTinyInt => f.pad("UTinyInt"),
266 Self::USmallInt => f.pad("USmallInt"),
267 Self::UInt => f.pad("UInt"),
268 Self::UBigInt => f.pad("UBigInt"),
269 Self::Float => f.pad("Float"),
270 Self::Double => f.pad("Double"),
271 Self::Decimal => f.pad("Decimal"),
272 Self::Timestamp => f.pad("Timestamp"),
273 Self::Text => f.pad("Text"),
274 Self::Blob => f.pad("Blob"),
275 Self::Geometry => f.pad("Geometry"),
276 Self::Date32 => f.pad("Date32"),
277 Self::Time64 => f.pad("Time64"),
278 Self::Interval => f.pad("Interval"),
279 Self::Struct(..) => f.pad("Struct"),
280 Self::List(..) => f.pad("List"),
281 Self::Enum => f.pad("Enum"),
282 Self::Map(..) => f.pad("Map"),
283 Self::Array(..) => f.pad("Array"),
284 Self::Union => f.pad("Union"),
285 Self::Variant => f.pad("Variant"),
286 Self::Any => f.pad("Any"),
287 }
288 }
289}
290
291#[cfg(test)]
292mod test {
293 use super::{Type, Value};
294 use crate::{Connection, Result};
295 use arrow::datatypes::DataType;
296
297 fn checked_memory_handle() -> Result<Connection> {
298 let db = Connection::open_in_memory()?;
299 db.execute_batch("CREATE TABLE foo (b BLOB, t TEXT, i INTEGER, f FLOAT, n BLOB)")?;
300 Ok(db)
301 }
302
303 #[test]
304 fn test_blob() -> Result<()> {
305 let db = checked_memory_handle()?;
306
307 let v1234 = vec![1u8, 2, 3, 4];
308 db.execute("INSERT INTO foo(b) VALUES (?)", [&v1234])?;
309
310 let v: Vec<u8> = db.query_row("SELECT b FROM foo", [], |r| r.get(0))?;
311 assert_eq!(v, v1234);
312 Ok(())
313 }
314
315 #[test]
316 fn test_empty_blob() -> Result<()> {
317 let db = checked_memory_handle()?;
318
319 let empty = vec![];
320 db.execute("INSERT INTO foo(b) VALUES (?)", [&empty])?;
321
322 let v: Vec<u8> = db.query_row("SELECT b FROM foo", [], |r| r.get(0))?;
323 assert_eq!(v, empty);
324 Ok(())
325 }
326
327 #[test]
328 fn test_geometry_value_binds_as_wkb_blob() -> Result<()> {
329 let db = checked_memory_handle()?;
330 let wkb = vec![1_u8, 1, 0, 0, 0];
331
332 let value = Value::Geometry(wkb.clone());
333 let bound: Vec<u8> = db.query_row("SELECT ?::BLOB", [value], |r| r.get(0))?;
334
335 assert_eq!(bound, wkb);
336 Ok(())
337 }
338
339 #[test]
340 fn test_geometry_value_binds_through_st_geomfromwkb() -> Result<()> {
341 let db = checked_memory_handle()?;
342 let wkb = vec![
343 0x01, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xF8, 0x7F, 0, 0, 0, 0, 0, 0, 0xF8, 0x7F,
344 ];
345
346 let value = Value::Geometry(wkb.clone());
347 let bound: Value = db.query_row("SELECT ST_GeomFromWKB(?)", [value], |r| r.get(0))?;
348
349 assert_eq!(bound, Value::Geometry(wkb));
350 Ok(())
351 }
352
353 #[test]
354 fn test_str() -> Result<()> {
355 let db = checked_memory_handle()?;
356
357 let s = "hello, world!";
358 db.execute("INSERT INTO foo(t) VALUES (?)", [&s])?;
359
360 let from: String = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;
361 assert_eq!(from, s);
362 Ok(())
363 }
364
365 #[test]
366 fn test_string() -> Result<()> {
367 let db = checked_memory_handle()?;
368
369 let s = "hello, world!";
370 let result = db.execute("INSERT INTO foo(t) VALUES (?)", [s.to_owned()]);
371 if let Err(e) = result {
372 panic!("exe error: {e}")
373 }
374
375 let from: String = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;
376 assert_eq!(from, s);
377 Ok(())
378 }
379
380 #[test]
381 fn test_value() -> Result<()> {
382 let db = checked_memory_handle()?;
383
384 db.execute("INSERT INTO foo(i) VALUES (?)", [Value::BigInt(10)])?;
385
386 assert_eq!(10i64, db.query_row::<i64, _, _>("SELECT i FROM foo", [], |r| r.get(0))?);
387 Ok(())
388 }
389
390 #[test]
391 fn arrow_decimal_types_match_duckdb_decimal_classification() {
392 assert_eq!(Type::from(&DataType::Decimal32(9, 2)), Type::Decimal);
393 assert_eq!(Type::from(&DataType::Decimal64(18, 2)), Type::Decimal);
394 assert_eq!(Type::from(&DataType::Decimal128(38, 2)), Type::Decimal);
395 assert_eq!(Type::from(&DataType::Decimal256(76, 10)), Type::Decimal);
396 }
397
398 #[test]
399 fn test_option() -> Result<()> {
400 let db = checked_memory_handle()?;
401
402 let s = "hello, world!";
403 let b = Some(vec![1u8, 2, 3, 4]);
404
405 db.execute("INSERT INTO foo(t) VALUES (?)", [&s])?;
406 db.execute("INSERT INTO foo(b) VALUES (?)", [&b])?;
407
408 let mut stmt = db.prepare("SELECT t, b FROM foo ORDER BY ROWID ASC")?;
409 let mut rows = stmt.query([])?;
410
411 {
412 let row1 = rows.next()?.unwrap();
413 let s1: Option<String> = row1.get_unwrap(0);
414 let b1: Option<Vec<u8>> = row1.get_unwrap(1);
415 assert_eq!(s, s1.unwrap());
416 assert!(b1.is_none());
417 }
418
419 {
420 let row2 = rows.next()?.unwrap();
421 let s2: Option<String> = row2.get_unwrap(0);
422 let b2: Option<Vec<u8>> = row2.get_unwrap(1);
423 assert!(s2.is_none());
424 assert_eq!(b, b2);
425 }
426 Ok(())
427 }
428
429 #[test]
430 fn test_dynamic_type() -> Result<()> {
431 use super::Value;
432 let db = checked_memory_handle()?;
433
434 db.execute("INSERT INTO foo(b, t, i, f) VALUES (X'0102', 'text', 1, 1.5)", [])?;
435
436 let mut stmt = db.prepare("SELECT b, t, i, f, n FROM foo")?;
437 let mut rows = stmt.query([])?;
438 let row = rows.next()?.unwrap();
439 assert_eq!(Value::Blob(vec![120, 48, 49, 48, 50]), row.get::<_, Value>(0)?);
442 assert_eq!(Value::Text(String::from("text")), row.get::<_, Value>(1)?);
443 assert_eq!(Value::Int(1), row.get::<_, Value>(2)?);
444 match row.get::<_, Value>(3)? {
445 Value::Float(val) => assert!((1.5 - val).abs() < f32::EPSILON),
446 x => panic!("Invalid Value {x:?}"),
447 }
448 assert_eq!(Value::Null, row.get::<_, Value>(4)?);
449 Ok(())
450 }
451}