1#[cfg(feature = "bigdecimal")]
2mod decimal;
3
4use crate::{
5 ast::Value,
6 connector::queryable::{GetRow, ToColumnNames},
7 error::{Error, ErrorKind},
8};
9#[cfg(feature = "bigdecimal")]
10use bigdecimal::{num_bigint::BigInt, BigDecimal, FromPrimitive, ToPrimitive};
11use bit_vec::BitVec;
12use bytes::BytesMut;
13#[cfg(feature = "chrono")]
14use chrono::{DateTime, NaiveDateTime, Utc};
15#[cfg(feature = "bigdecimal")]
16pub(crate) use decimal::DecimalWrapper;
17use postgres_types::{FromSql, ToSql, WrongType};
18use std::{convert::TryFrom, error::Error as StdError};
19use tokio_postgres::{
20 types::{self, IsNull, Kind, Type as PostgresType},
21 Row as PostgresRow, Statement as PostgresStatement,
22};
23
24#[cfg(feature = "uuid")]
25use uuid::Uuid;
26
27pub(crate) fn conv_params<'a>(params: &'a [Value<'a>]) -> Vec<&'a (dyn types::ToSql + Sync)> {
28 params.iter().map(|x| x as &(dyn ToSql + Sync)).collect::<Vec<_>>()
29}
30
31pub(crate) fn params_to_types(params: &[Value<'_>]) -> Vec<PostgresType> {
33 params
34 .iter()
35 .map(|p| -> PostgresType {
36 if p.is_null() {
39 return PostgresType::UNKNOWN;
40 }
41
42 match p {
43 Value::Int32(_) => PostgresType::INT4,
44 Value::Int64(_) => PostgresType::INT8,
45 Value::Float(_) => PostgresType::FLOAT4,
46 Value::Double(_) => PostgresType::FLOAT8,
47 Value::Text(_) => PostgresType::TEXT,
48 Value::Enum(_) => PostgresType::UNKNOWN,
50 Value::Bytes(_) => PostgresType::BYTEA,
51 Value::Boolean(_) => PostgresType::BOOL,
52 Value::Char(_) => PostgresType::CHAR,
53 #[cfg(feature = "bigdecimal")]
54 Value::Numeric(_) => PostgresType::NUMERIC,
55 #[cfg(feature = "json")]
56 Value::Json(_) => PostgresType::JSONB,
57 Value::Xml(_) => PostgresType::XML,
58 #[cfg(feature = "uuid")]
59 Value::Uuid(_) => PostgresType::UUID,
60 #[cfg(feature = "chrono")]
61 Value::DateTime(_) => PostgresType::TIMESTAMPTZ,
62 #[cfg(feature = "chrono")]
63 Value::Date(_) => PostgresType::TIMESTAMP,
64 #[cfg(feature = "chrono")]
65 Value::Time(_) => PostgresType::TIME,
66 Value::Array(ref arr) => {
67 let arr = arr.as_ref().unwrap();
68
69 if arr.is_empty() {
71 return PostgresType::UNKNOWN;
72 }
73
74 let first = arr.first().unwrap();
75
76 if arr
78 .iter()
79 .any(|val| std::mem::discriminant(first) != std::mem::discriminant(val))
80 {
81 return PostgresType::UNKNOWN;
82 }
83
84 match first {
85 Value::Int32(_) => PostgresType::INT4_ARRAY,
86 Value::Int64(_) => PostgresType::INT8_ARRAY,
87 Value::Float(_) => PostgresType::FLOAT4_ARRAY,
88 Value::Double(_) => PostgresType::FLOAT8_ARRAY,
89 Value::Text(_) => PostgresType::TEXT_ARRAY,
90 Value::Enum(_) => PostgresType::UNKNOWN,
92 Value::Bytes(_) => PostgresType::BYTEA_ARRAY,
93 Value::Boolean(_) => PostgresType::BOOL_ARRAY,
94 Value::Char(_) => PostgresType::CHAR_ARRAY,
95 #[cfg(feature = "bigdecimal")]
96 Value::Numeric(_) => PostgresType::NUMERIC_ARRAY,
97 #[cfg(feature = "json")]
98 Value::Json(_) => PostgresType::JSONB_ARRAY,
99 Value::Xml(_) => PostgresType::XML_ARRAY,
100 #[cfg(feature = "uuid")]
101 Value::Uuid(_) => PostgresType::UUID_ARRAY,
102 #[cfg(feature = "chrono")]
103 Value::DateTime(_) => PostgresType::TIMESTAMPTZ_ARRAY,
104 #[cfg(feature = "chrono")]
105 Value::Date(_) => PostgresType::TIMESTAMP_ARRAY,
106 #[cfg(feature = "chrono")]
107 Value::Time(_) => PostgresType::TIME_ARRAY,
108 Value::Array(_) => PostgresType::UNKNOWN,
110 }
111 }
112 }
113 })
114 .collect()
115}
116
117struct XmlString(pub String);
118
119impl<'a> FromSql<'a> for XmlString {
120 fn from_sql(_ty: &PostgresType, raw: &'a [u8]) -> Result<XmlString, Box<dyn std::error::Error + Sync + Send>> {
121 Ok(XmlString(String::from_utf8(raw.to_owned()).unwrap()))
122 }
123
124 fn accepts(ty: &PostgresType) -> bool {
125 ty == &PostgresType::XML
126 }
127}
128
129struct EnumString {
130 value: String,
131}
132
133impl<'a> FromSql<'a> for EnumString {
134 fn from_sql(_ty: &PostgresType, raw: &'a [u8]) -> Result<EnumString, Box<dyn std::error::Error + Sync + Send>> {
135 Ok(EnumString {
136 value: String::from_utf8(raw.to_owned()).unwrap(),
137 })
138 }
139
140 fn accepts(_ty: &PostgresType) -> bool {
141 true
142 }
143}
144
145#[cfg(feature = "chrono")]
146struct TimeTz(chrono::NaiveTime);
147
148#[cfg(feature = "chrono")]
149impl<'a> FromSql<'a> for TimeTz {
150 fn from_sql(_ty: &PostgresType, raw: &'a [u8]) -> Result<TimeTz, Box<dyn std::error::Error + Sync + Send>> {
151 let time: chrono::NaiveTime = chrono::NaiveTime::from_sql(&PostgresType::TIMETZ, &raw[..8])?;
153 Ok(TimeTz(time))
154 }
155
156 fn accepts(ty: &PostgresType) -> bool {
157 ty == &PostgresType::TIMETZ
158 }
159}
160
161#[cfg(feature = "bigdecimal")]
166struct NaiveMoney(BigDecimal);
167
168#[cfg(feature = "bigdecimal")]
169impl<'a> FromSql<'a> for NaiveMoney {
170 fn from_sql(_ty: &PostgresType, raw: &'a [u8]) -> Result<NaiveMoney, Box<dyn std::error::Error + Sync + Send>> {
171 let cents = i64::from_sql(&PostgresType::INT8, raw)?;
172
173 Ok(NaiveMoney(BigDecimal::new(BigInt::from_i64(cents).unwrap(), 2)))
174 }
175
176 fn accepts(ty: &PostgresType) -> bool {
177 ty == &PostgresType::MONEY
178 }
179}
180
181impl GetRow for PostgresRow {
182 fn get_result_row(&self) -> crate::Result<Vec<Value<'static>>> {
183 fn convert(row: &PostgresRow, i: usize) -> crate::Result<Value<'static>> {
184 let result = match *row.columns()[i].type_() {
185 PostgresType::BOOL => Value::Boolean(row.try_get(i)?),
186 PostgresType::INT2 => match row.try_get(i)? {
187 Some(val) => {
188 let val: i16 = val;
189 Value::int32(val)
190 }
191 None => Value::Int32(None),
192 },
193 PostgresType::INT4 => match row.try_get(i)? {
194 Some(val) => {
195 let val: i32 = val;
196 Value::int32(val)
197 }
198 None => Value::Int32(None),
199 },
200 PostgresType::INT8 => match row.try_get(i)? {
201 Some(val) => {
202 let val: i64 = val;
203 Value::int64(val)
204 }
205 None => Value::Int64(None),
206 },
207 PostgresType::FLOAT4 => match row.try_get(i)? {
208 Some(val) => {
209 let val: f32 = val;
210 Value::float(val)
211 }
212 None => Value::Float(None),
213 },
214 PostgresType::FLOAT8 => match row.try_get(i)? {
215 Some(val) => {
216 let val: f64 = val;
217 Value::double(val)
218 }
219 None => Value::Double(None),
220 },
221 PostgresType::BYTEA => match row.try_get(i)? {
222 Some(val) => {
223 let val: &[u8] = val;
224 Value::bytes(val.to_owned())
225 }
226 None => Value::Bytes(None),
227 },
228 PostgresType::BYTEA_ARRAY => match row.try_get(i)? {
229 Some(val) => {
230 let val: Vec<Option<Vec<u8>>> = val;
231 let byteas = val.into_iter().map(|b| Value::Bytes(b.map(Into::into)));
232
233 Value::array(byteas)
234 }
235 None => Value::Array(None),
236 },
237 #[cfg(feature = "bigdecimal")]
238 PostgresType::NUMERIC => {
239 let dw: Option<DecimalWrapper> = row.try_get(i)?;
240
241 Value::Numeric(dw.map(|dw| dw.0))
242 }
243 #[cfg(feature = "bigdecimal")]
244 PostgresType::MONEY => match row.try_get(i)? {
245 Some(val) => {
246 let val: NaiveMoney = val;
247 Value::numeric(val.0)
248 }
249 None => Value::Numeric(None),
250 },
251 #[cfg(feature = "chrono")]
252 PostgresType::TIMESTAMP => match row.try_get(i)? {
253 Some(val) => {
254 let ts: NaiveDateTime = val;
255 let dt = DateTime::<Utc>::from_utc(ts, Utc);
256 Value::datetime(dt)
257 }
258 None => Value::DateTime(None),
259 },
260 #[cfg(feature = "chrono")]
261 PostgresType::TIMESTAMPTZ => match row.try_get(i)? {
262 Some(val) => {
263 let ts: DateTime<Utc> = val;
264 Value::datetime(ts)
265 }
266 None => Value::DateTime(None),
267 },
268 #[cfg(feature = "chrono")]
269 PostgresType::DATE => match row.try_get(i)? {
270 Some(val) => Value::date(val),
271 None => Value::Date(None),
272 },
273 #[cfg(feature = "chrono")]
274 PostgresType::TIME => match row.try_get(i)? {
275 Some(val) => Value::time(val),
276 None => Value::Time(None),
277 },
278 #[cfg(feature = "chrono")]
279 PostgresType::TIMETZ => match row.try_get(i)? {
280 Some(val) => {
281 let time: TimeTz = val;
282 Value::time(time.0)
283 }
284 None => Value::Time(None),
285 },
286 #[cfg(feature = "uuid")]
287 PostgresType::UUID => match row.try_get(i)? {
288 Some(val) => {
289 let val: Uuid = val;
290 Value::uuid(val)
291 }
292 None => Value::Uuid(None),
293 },
294 #[cfg(feature = "uuid")]
295 PostgresType::UUID_ARRAY => match row.try_get(i)? {
296 Some(val) => {
297 let val: Vec<Option<Uuid>> = val;
298 let val = val.into_iter().map(Value::Uuid);
299
300 Value::array(val)
301 }
302 None => Value::Array(None),
303 },
304 #[cfg(feature = "json")]
305 PostgresType::JSON | PostgresType::JSONB => Value::Json(row.try_get(i)?),
306 PostgresType::INT2_ARRAY => match row.try_get(i)? {
307 Some(val) => {
308 let val: Vec<Option<i16>> = val;
309 let ints = val.into_iter().map(|i| Value::Int32(i.map(|i| i as i32)));
310
311 Value::array(ints)
312 }
313 None => Value::Array(None),
314 },
315 PostgresType::INT4_ARRAY => match row.try_get(i)? {
316 Some(val) => {
317 let val: Vec<Option<i32>> = val;
318 let ints = val.into_iter().map(Value::Int32);
319
320 Value::array(ints)
321 }
322 None => Value::Array(None),
323 },
324 PostgresType::INT8_ARRAY => match row.try_get(i)? {
325 Some(val) => {
326 let val: Vec<Option<i64>> = val;
327 let ints = val.into_iter().map(Value::Int64);
328
329 Value::array(ints)
330 }
331 None => Value::Array(None),
332 },
333 PostgresType::FLOAT4_ARRAY => match row.try_get(i)? {
334 Some(val) => {
335 let val: Vec<Option<f32>> = val;
336 let floats = val.into_iter().map(Value::Float);
337
338 Value::array(floats)
339 }
340 None => Value::Array(None),
341 },
342 PostgresType::FLOAT8_ARRAY => match row.try_get(i)? {
343 Some(val) => {
344 let val: Vec<Option<f64>> = val;
345 let floats = val.into_iter().map(Value::Double);
346
347 Value::array(floats)
348 }
349 None => Value::Array(None),
350 },
351 PostgresType::BOOL_ARRAY => match row.try_get(i)? {
352 Some(val) => {
353 let val: Vec<Option<bool>> = val;
354 let bools = val.into_iter().map(Value::Boolean);
355
356 Value::array(bools)
357 }
358 None => Value::Array(None),
359 },
360 #[cfg(feature = "chrono")]
361 PostgresType::TIMESTAMP_ARRAY => match row.try_get(i)? {
362 Some(val) => {
363 let val: Vec<Option<NaiveDateTime>> = val;
364
365 let dates = val
366 .into_iter()
367 .map(|dt| Value::DateTime(dt.map(|dt| DateTime::<Utc>::from_utc(dt, Utc))));
368
369 Value::array(dates)
370 }
371 None => Value::Array(None),
372 },
373 #[cfg(feature = "bigdecimal")]
374 PostgresType::NUMERIC_ARRAY => match row.try_get(i)? {
375 Some(val) => {
376 let val: Vec<Option<DecimalWrapper>> = val;
377
378 let decimals = val
379 .into_iter()
380 .map(|dec| Value::Numeric(dec.map(|dec| dec.0.to_string().parse().unwrap())));
381
382 Value::array(decimals)
383 }
384 None => Value::Array(None),
385 },
386 PostgresType::TEXT_ARRAY | PostgresType::NAME_ARRAY | PostgresType::VARCHAR_ARRAY => {
387 match row.try_get(i)? {
388 Some(val) => {
389 let strings: Vec<Option<&str>> = val;
390
391 Value::array(strings.into_iter().map(|s| s.map(|s| s.to_string())))
392 }
393 None => Value::Array(None),
394 }
395 }
396 #[cfg(feature = "bigdecimal")]
397 PostgresType::MONEY_ARRAY => match row.try_get(i)? {
398 Some(val) => {
399 let val: Vec<Option<NaiveMoney>> = val;
400 let nums = val.into_iter().map(|num| Value::Numeric(num.map(|num| num.0)));
401
402 Value::array(nums)
403 }
404 None => Value::Array(None),
405 },
406 PostgresType::OID_ARRAY => match row.try_get(i)? {
407 Some(val) => {
408 let val: Vec<Option<u32>> = val;
409 let nums = val.into_iter().map(|oid| Value::Int64(oid.map(|oid| oid as i64)));
410
411 Value::array(nums)
412 }
413 None => Value::Array(None),
414 },
415 #[cfg(feature = "chrono")]
416 PostgresType::TIMESTAMPTZ_ARRAY => match row.try_get(i)? {
417 Some(val) => {
418 let val: Vec<Option<DateTime<Utc>>> = val;
419 let dates = val.into_iter().map(Value::DateTime);
420
421 Value::array(dates)
422 }
423 None => Value::Array(None),
424 },
425 #[cfg(feature = "chrono")]
426 PostgresType::DATE_ARRAY => match row.try_get(i)? {
427 Some(val) => {
428 let val: Vec<Option<chrono::NaiveDate>> = val;
429 let dates = val.into_iter().map(Value::Date);
430
431 Value::array(dates)
432 }
433 None => Value::Array(None),
434 },
435 #[cfg(feature = "chrono")]
436 PostgresType::TIME_ARRAY => match row.try_get(i)? {
437 Some(val) => {
438 let val: Vec<Option<chrono::NaiveTime>> = val;
439 let times = val.into_iter().map(Value::Time);
440
441 Value::array(times)
442 }
443 None => Value::Array(None),
444 },
445 #[cfg(feature = "chrono")]
446 PostgresType::TIMETZ_ARRAY => match row.try_get(i)? {
447 Some(val) => {
448 let val: Vec<Option<TimeTz>> = val;
449 let timetzs = val.into_iter().map(|time| Value::Time(time.map(|time| time.0)));
450
451 Value::array(timetzs)
452 }
453 None => Value::Array(None),
454 },
455 #[cfg(feature = "json")]
456 PostgresType::JSON_ARRAY => match row.try_get(i)? {
457 Some(val) => {
458 let val: Vec<Option<serde_json::Value>> = val;
459 let jsons = val.into_iter().map(Value::Json);
460
461 Value::array(jsons)
462 }
463 None => Value::Array(None),
464 },
465 #[cfg(feature = "json")]
466 PostgresType::JSONB_ARRAY => match row.try_get(i)? {
467 Some(val) => {
468 let val: Vec<Option<serde_json::Value>> = val;
469 let jsons = val.into_iter().map(Value::Json);
470
471 Value::array(jsons)
472 }
473 None => Value::Array(None),
474 },
475 PostgresType::OID => match row.try_get(i)? {
476 Some(val) => {
477 let val: u32 = val;
478 Value::int64(val)
479 }
480 None => Value::Int64(None),
481 },
482 PostgresType::CHAR => match row.try_get(i)? {
483 Some(val) => {
484 let val: i8 = val;
485 Value::character((val as u8) as char)
486 }
487 None => Value::Char(None),
488 },
489 PostgresType::INET | PostgresType::CIDR => match row.try_get(i)? {
490 Some(val) => {
491 let val: std::net::IpAddr = val;
492 Value::text(val.to_string())
493 }
494 None => Value::Text(None),
495 },
496 PostgresType::INET_ARRAY | PostgresType::CIDR_ARRAY => match row.try_get(i)? {
497 Some(val) => {
498 let val: Vec<Option<std::net::IpAddr>> = val;
499 let addrs = val
500 .into_iter()
501 .map(|ip| Value::Text(ip.map(|ip| ip.to_string().into())));
502
503 Value::array(addrs)
504 }
505 None => Value::Array(None),
506 },
507 PostgresType::BIT | PostgresType::VARBIT => match row.try_get(i)? {
508 Some(val) => {
509 let val: BitVec = val;
510 Value::text(bits_to_string(&val)?)
511 }
512 None => Value::Text(None),
513 },
514 PostgresType::BIT_ARRAY | PostgresType::VARBIT_ARRAY => match row.try_get(i)? {
515 Some(val) => {
516 let val: Vec<Option<BitVec>> = val;
517 let stringified = val
518 .into_iter()
519 .map(|bits| match bits {
520 Some(bits) => bits_to_string(&bits).map(Value::text),
521 None => Ok(Value::Text(None)),
522 })
523 .collect::<crate::Result<Vec<_>>>()?;
524
525 Value::array(stringified)
526 }
527 None => Value::Array(None),
528 },
529 PostgresType::XML => match row.try_get(i)? {
530 Some(val) => {
531 let val: XmlString = val;
532 Value::xml(val.0)
533 }
534 None => Value::Xml(None),
535 },
536 PostgresType::XML_ARRAY => match row.try_get(i)? {
537 Some(val) => {
538 let val: Vec<Option<XmlString>> = val;
539 let xmls = val.into_iter().map(|xml| xml.map(|xml| xml.0));
540
541 Value::array(xmls)
542 }
543 None => Value::Array(None),
544 },
545 ref x => match x.kind() {
546 Kind::Enum(_) => match row.try_get(i)? {
547 Some(val) => {
548 let val: EnumString = val;
549
550 Value::enum_variant(val.value)
551 }
552 None => Value::Enum(None),
553 },
554 Kind::Array(inner) => match inner.kind() {
555 Kind::Enum(_) => match row.try_get(i)? {
556 Some(val) => {
557 let val: Vec<Option<EnumString>> = val;
558 let variants = val.into_iter().map(|x| Value::Enum(x.map(|x| x.value.into())));
559
560 Ok(Value::array(variants))
561 }
562 None => Ok(Value::Array(None)),
563 },
564 _ => match row.try_get(i) {
565 Ok(Some(val)) => {
566 let val: Vec<Option<String>> = val;
567 let strings = val.into_iter().map(|str| Value::Text(str.map(Into::into)));
568
569 Ok(Value::array(strings))
570 }
571 Ok(None) => Ok(Value::Array(None)),
572 Err(err) => {
573 if err.source().map(|err| err.is::<WrongType>()).unwrap_or(false) {
574 let kind = ErrorKind::UnsupportedColumnType {
575 column_type: x.to_string(),
576 };
577
578 return Err(Error::builder(kind).build());
579 } else {
580 Err(err)
581 }
582 }
583 },
584 }?,
585 _ => match row.try_get(i) {
586 Ok(Some(val)) => {
587 let val: String = val;
588
589 Ok(Value::text(val))
590 }
591 Ok(None) => Ok(Value::Text(None)),
592 Err(err) => {
593 if err.source().map(|err| err.is::<WrongType>()).unwrap_or(false) {
594 let kind = ErrorKind::UnsupportedColumnType {
595 column_type: x.to_string(),
596 };
597
598 return Err(Error::builder(kind).build());
599 } else {
600 Err(err)
601 }
602 }
603 }?,
604 },
605 };
606
607 Ok(result)
608 }
609
610 let num_columns = self.columns().len();
611 let mut row = Vec::with_capacity(num_columns);
612
613 for i in 0..num_columns {
614 row.push(convert(self, i)?);
615 }
616
617 Ok(row)
618 }
619}
620
621impl ToColumnNames for PostgresStatement {
622 fn to_column_names(&self) -> Vec<String> {
623 self.columns().iter().map(|c| c.name().into()).collect()
624 }
625}
626
627impl<'a> ToSql for Value<'a> {
628 fn to_sql(
629 &self,
630 ty: &PostgresType,
631 out: &mut BytesMut,
632 ) -> Result<IsNull, Box<dyn StdError + 'static + Send + Sync>> {
633 let res = match (self, ty) {
634 (Value::Int32(integer), &PostgresType::INT2) => match integer {
635 Some(i) => {
636 let integer = i16::try_from(*i).map_err(|_| {
637 let kind = ErrorKind::conversion(format!(
638 "Unable to fit integer value '{i}' into an INT2 (16-bit signed integer)."
639 ));
640
641 Error::builder(kind).build()
642 })?;
643
644 Some(integer.to_sql(ty, out))
645 }
646 _ => None,
647 },
648 (Value::Int32(integer), &PostgresType::INT4) => integer.map(|integer| integer.to_sql(ty, out)),
649 (Value::Int32(integer), &PostgresType::INT8) => integer.map(|integer| (integer as i64).to_sql(ty, out)),
650 (Value::Int64(integer), &PostgresType::INT2) => match integer {
651 Some(i) => {
652 let integer = i16::try_from(*i).map_err(|_| {
653 let kind = ErrorKind::conversion(format!(
654 "Unable to fit integer value '{i}' into an INT2 (16-bit signed integer)."
655 ));
656
657 Error::builder(kind).build()
658 })?;
659
660 Some(integer.to_sql(ty, out))
661 }
662 _ => None,
663 },
664 (Value::Int64(integer), &PostgresType::INT4) => match integer {
665 Some(i) => {
666 let integer = i32::try_from(*i).map_err(|_| {
667 let kind = ErrorKind::conversion(format!(
668 "Unable to fit integer value '{i}' into an INT4 (32-bit signed integer)."
669 ));
670
671 Error::builder(kind).build()
672 })?;
673
674 Some(integer.to_sql(ty, out))
675 }
676 _ => None,
677 },
678 (Value::Int64(integer), &PostgresType::INT8) => integer.map(|integer| integer.to_sql(ty, out)),
679 #[cfg(feature = "bigdecimal")]
680 (Value::Int32(integer), &PostgresType::NUMERIC) => integer
681 .map(|integer| BigDecimal::from_i32(integer).unwrap())
682 .map(DecimalWrapper)
683 .map(|dw| dw.to_sql(ty, out)),
684 #[cfg(feature = "bigdecimal")]
685 (Value::Int64(integer), &PostgresType::NUMERIC) => integer
686 .map(|integer| BigDecimal::from_i64(integer).unwrap())
687 .map(DecimalWrapper)
688 .map(|dw| dw.to_sql(ty, out)),
689 (Value::Int32(integer), &PostgresType::TEXT) => integer.map(|integer| format!("{integer}").to_sql(ty, out)),
690 (Value::Int64(integer), &PostgresType::TEXT) => integer.map(|integer| format!("{integer}").to_sql(ty, out)),
691 (Value::Int32(integer), &PostgresType::OID) => match integer {
692 Some(i) => {
693 let integer = u32::try_from(*i).map_err(|_| {
694 let kind = ErrorKind::conversion(format!(
695 "Unable to fit integer value '{i}' into an OID (32-bit unsigned integer)."
696 ));
697
698 Error::builder(kind).build()
699 })?;
700
701 Some(integer.to_sql(ty, out))
702 }
703 _ => None,
704 },
705 (Value::Int64(integer), &PostgresType::OID) => match integer {
706 Some(i) => {
707 let integer = u32::try_from(*i).map_err(|_| {
708 let kind = ErrorKind::conversion(format!(
709 "Unable to fit integer value '{i}' into an OID (32-bit unsigned integer)."
710 ));
711
712 Error::builder(kind).build()
713 })?;
714
715 Some(integer.to_sql(ty, out))
716 }
717 _ => None,
718 },
719 (Value::Int32(integer), _) => integer.map(|integer| integer.to_sql(ty, out)),
720 (Value::Int64(integer), _) => integer.map(|integer| integer.to_sql(ty, out)),
721 (Value::Float(float), &PostgresType::FLOAT8) => float.map(|float| (float as f64).to_sql(ty, out)),
722 #[cfg(feature = "bigdecimal")]
723 (Value::Float(float), &PostgresType::NUMERIC) => float
724 .map(|float| BigDecimal::from_f32(float).unwrap())
725 .map(DecimalWrapper)
726 .map(|dw| dw.to_sql(ty, out)),
727 (Value::Float(float), _) => float.map(|float| float.to_sql(ty, out)),
728 (Value::Double(double), &PostgresType::FLOAT4) => double.map(|double| (double as f32).to_sql(ty, out)),
729 #[cfg(feature = "bigdecimal")]
730 (Value::Double(double), &PostgresType::NUMERIC) => double
731 .map(|double| BigDecimal::from_f64(double).unwrap())
732 .map(DecimalWrapper)
733 .map(|dw| dw.to_sql(ty, out)),
734 (Value::Double(double), _) => double.map(|double| double.to_sql(ty, out)),
735 #[cfg(feature = "bigdecimal")]
736 (Value::Numeric(decimal), &PostgresType::FLOAT4) => decimal.as_ref().map(|decimal| {
737 let f = decimal.to_string().parse::<f32>().expect("decimal to f32 conversion");
738 f.to_sql(ty, out)
739 }),
740 #[cfg(feature = "bigdecimal")]
741 (Value::Numeric(decimal), &PostgresType::FLOAT8) => decimal.as_ref().map(|decimal| {
742 let f = decimal.to_string().parse::<f64>().expect("decimal to f64 conversion");
743 f.to_sql(ty, out)
744 }),
745 #[cfg(feature = "bigdecimal")]
746 (Value::Array(values), &PostgresType::FLOAT4_ARRAY) => values.as_ref().map(|values| {
747 let mut floats = Vec::with_capacity(values.len());
748
749 for value in values.iter() {
750 let float = match value {
751 Value::Numeric(n) => n.as_ref().and_then(|n| n.to_string().parse::<f32>().ok()),
752 Value::Int64(n) => n.map(|n| n as f32),
753 Value::Float(f) => *f,
754 Value::Double(d) => d.map(|d| d as f32),
755 v if v.is_null() => None,
756 v => {
757 let kind = ErrorKind::conversion(format!(
758 "Couldn't add value of type `{v:?}` into a float array."
759 ));
760
761 return Err(Error::builder(kind).build().into());
762 }
763 };
764
765 floats.push(float);
766 }
767
768 floats.to_sql(ty, out)
769 }),
770 #[cfg(feature = "bigdecimal")]
771 (Value::Array(values), &PostgresType::FLOAT8_ARRAY) => values.as_ref().map(|values| {
772 let mut floats = Vec::with_capacity(values.len());
773
774 for value in values.iter() {
775 let float = match value {
776 Value::Numeric(n) => n.as_ref().and_then(|n| n.to_string().parse::<f64>().ok()),
777 Value::Int64(n) => n.map(|n| n as f64),
778 Value::Float(f) => f.map(|f| f as f64),
779 Value::Double(d) => *d,
780 v if v.is_null() => None,
781 v => {
782 let kind = ErrorKind::conversion(format!(
783 "Couldn't add value of type `{v:?}` into a double array."
784 ));
785
786 return Err(Error::builder(kind).build().into());
787 }
788 };
789
790 floats.push(float);
791 }
792
793 floats.to_sql(ty, out)
794 }),
795 #[cfg(feature = "bigdecimal")]
796 (Value::Numeric(decimal), &PostgresType::MONEY) => decimal.as_ref().map(|decimal| {
797 let decimal = (decimal * BigInt::from_i32(100).unwrap()).round(0);
798
799 let i = decimal.to_i64().ok_or_else(|| {
800 let kind = ErrorKind::conversion("Couldn't convert BigDecimal to i64.");
801 Error::builder(kind).build()
802 })?;
803
804 i.to_sql(ty, out)
805 }),
806 #[cfg(feature = "bigdecimal")]
807 (Value::Numeric(decimal), &PostgresType::NUMERIC) => decimal
808 .as_ref()
809 .map(|decimal| DecimalWrapper(decimal.clone()).to_sql(ty, out)),
810 #[cfg(feature = "bigdecimal")]
811 (Value::Numeric(float), _) => float
812 .as_ref()
813 .map(|float| DecimalWrapper(float.clone()).to_sql(ty, out)),
814 #[cfg(feature = "uuid")]
815 (Value::Text(string), &PostgresType::UUID) => string.as_ref().map(|string| {
816 let parsed_uuid: Uuid = string.parse()?;
817 parsed_uuid.to_sql(ty, out)
818 }),
819 #[cfg(feature = "uuid")]
820 (Value::Array(values), &PostgresType::UUID_ARRAY) => values.as_ref().map(|values| {
821 let parsed_uuid: Vec<Option<Uuid>> = values
822 .iter()
823 .map(<Option<Uuid>>::try_from)
824 .collect::<crate::Result<Vec<_>>>()?;
825
826 parsed_uuid.to_sql(ty, out)
827 }),
828 (Value::Text(string), &PostgresType::INET) | (Value::Text(string), &PostgresType::CIDR) => {
829 string.as_ref().map(|string| {
830 let parsed_ip_addr: std::net::IpAddr = string.parse()?;
831 parsed_ip_addr.to_sql(ty, out)
832 })
833 }
834 (Value::Array(values), &PostgresType::INET_ARRAY) | (Value::Array(values), &PostgresType::CIDR_ARRAY) => {
835 values.as_ref().map(|values| {
836 let parsed_ip_addr: Vec<Option<std::net::IpAddr>> = values
837 .iter()
838 .map(<Option<std::net::IpAddr>>::try_from)
839 .collect::<crate::Result<_>>()?;
840
841 parsed_ip_addr.to_sql(ty, out)
842 })
843 }
844 #[cfg(feature = "json")]
845 (Value::Text(string), &PostgresType::JSON) | (Value::Text(string), &PostgresType::JSONB) => string
846 .as_ref()
847 .map(|string| serde_json::from_str::<serde_json::Value>(string)?.to_sql(ty, out)),
848 (Value::Text(string), &PostgresType::BIT) | (Value::Text(string), &PostgresType::VARBIT) => {
849 string.as_ref().map(|string| {
850 let bits: BitVec = string_to_bits(string)?;
851
852 bits.to_sql(ty, out)
853 })
854 }
855 (Value::Text(string), _) => string.as_ref().map(|ref string| string.to_sql(ty, out)),
856 (Value::Array(values), &PostgresType::BIT_ARRAY) | (Value::Array(values), &PostgresType::VARBIT_ARRAY) => {
857 values.as_ref().map(|values| {
858 let bitvecs: Vec<Option<BitVec>> = values
859 .iter()
860 .map(<Option<BitVec>>::try_from)
861 .collect::<crate::Result<Vec<_>>>()?;
862
863 bitvecs.to_sql(ty, out)
864 })
865 }
866 (Value::Bytes(bytes), _) => bytes.as_ref().map(|bytes| bytes.as_ref().to_sql(ty, out)),
867 (Value::Enum(string), _) => string.as_ref().map(|string| {
868 out.extend_from_slice(string.as_bytes());
869 Ok(IsNull::No)
870 }),
871 (Value::Boolean(boo), _) => boo.map(|boo| boo.to_sql(ty, out)),
872 (Value::Char(c), _) => c.map(|c| (c as i8).to_sql(ty, out)),
873 (Value::Array(vec), typ) if matches!(typ.kind(), Kind::Array(_)) => {
874 vec.as_ref().map(|vec| vec.to_sql(ty, out))
875 }
876 (Value::Array(vec), typ) => {
877 let kind = ErrorKind::conversion(format!(
878 "Couldn't serialize value `{vec:?}` into a `{typ}`. Value is a list but `{typ}` is not."
879 ));
880
881 return Err(Error::builder(kind).build().into());
882 }
883 #[cfg(feature = "json")]
884 (Value::Json(value), _) => value.as_ref().map(|value| value.to_sql(ty, out)),
885 (Value::Xml(value), _) => value.as_ref().map(|value| value.to_sql(ty, out)),
886 #[cfg(feature = "uuid")]
887 (Value::Uuid(value), _) => value.map(|value| value.to_sql(ty, out)),
888 #[cfg(feature = "chrono")]
889 (Value::DateTime(value), &PostgresType::DATE) => value.map(|value| value.date_naive().to_sql(ty, out)),
890 #[cfg(feature = "chrono")]
891 (Value::Date(value), _) => value.map(|value| value.to_sql(ty, out)),
892 #[cfg(feature = "chrono")]
893 (Value::Time(value), _) => value.map(|value| value.to_sql(ty, out)),
894 #[cfg(feature = "chrono")]
895 (Value::DateTime(value), &PostgresType::TIME) => value.map(|value| value.time().to_sql(ty, out)),
896 #[cfg(feature = "chrono")]
897 (Value::DateTime(value), &PostgresType::TIMETZ) => value.map(|value| {
898 let result = value.time().to_sql(ty, out)?;
899 out.extend_from_slice(&[0; 4]);
901 Ok(result)
902 }),
903 #[cfg(feature = "chrono")]
904 (Value::DateTime(value), _) => value.map(|value| value.naive_utc().to_sql(ty, out)),
905 };
906
907 match res {
908 Some(res) => res,
909 None => Ok(IsNull::Yes),
910 }
911 }
912
913 fn accepts(_: &PostgresType) -> bool {
914 true }
916
917 tokio_postgres::types::to_sql_checked!();
918}
919
920fn string_to_bits(s: &str) -> crate::Result<BitVec> {
921 use bit_vec::*;
922
923 let mut bits = BitVec::with_capacity(s.len());
924
925 for c in s.chars() {
926 match c {
927 '0' => bits.push(false),
928 '1' => bits.push(true),
929 _ => {
930 let msg = "Unexpected character for bits input. Expected only 1 and 0.";
931 let kind = ErrorKind::conversion(msg);
932
933 return Err(Error::builder(kind).build());
934 }
935 }
936 }
937
938 Ok(bits)
939}
940
941fn bits_to_string(bits: &BitVec) -> crate::Result<String> {
942 let mut s = String::with_capacity(bits.len());
943
944 for bit in bits {
945 if bit {
946 s.push('1');
947 } else {
948 s.push('0');
949 }
950 }
951
952 Ok(s)
953}
954
955impl<'a> TryFrom<&Value<'a>> for Option<BitVec> {
956 type Error = Error;
957
958 fn try_from(value: &Value<'a>) -> Result<Option<BitVec>, Self::Error> {
959 match value {
960 val @ Value::Text(Some(_)) => {
961 let text = val.as_str().unwrap();
962
963 string_to_bits(text).map(Option::Some)
964 }
965 val @ Value::Bytes(Some(_)) => {
966 let text = val.as_str().unwrap();
967
968 string_to_bits(text).map(Option::Some)
969 }
970 v if v.is_null() => Ok(None),
971 v => {
972 let kind = ErrorKind::conversion(format!("Couldn't convert value of type `{v:?}` to bit_vec::BitVec."));
973
974 Err(Error::builder(kind).build())
975 }
976 }
977 }
978}