mirror of
https://github.com/launchbadge/sqlx.git
synced 2026-03-19 08:39:44 +00:00
Make Encode return a result (#3126)
* Make encode and encode_by_ref fallible This only changes the trait for now and makes it compile, calling .expect() on all users. Those will be removed in a later commit. * PgNumeric: Turn TryFrom Decimal to an infallible From * Turn panics in Encode implementations into errors * Add Encode error analogous to the Decode error * Propagate decode errors through Arguments::add This pushes the panics one level further to mostly bind calls. Those will also be removed later. * Only check argument encoding at the end * Use Result in Query internally * Implement query_with functions in terms of _with_result * Surface encode errors when executing a query. * Remove remaining panics in AnyConnectionBackend implementations * PostgreSQL BigDecimal: Return encode error immediately * Arguments: Add len method to report how many arguments were added * Query::bind: Report which argument failed to encode * IsNull: Add is_null method * MySqlArguments: Replace manual bitmap code with NullBitMap helper type * Roll back buffer in MySqlArguments if encoding fails * Roll back buffer in SqliteArguments if encoding fails * Roll back PgArgumentBuffer if encoding fails
This commit is contained in:
@@ -4,7 +4,8 @@ use crate::{
|
||||
};
|
||||
use futures_core::future::BoxFuture;
|
||||
use futures_core::stream::BoxStream;
|
||||
use futures_util::{StreamExt, TryFutureExt, TryStreamExt};
|
||||
use futures_util::{stream, StreamExt, TryFutureExt, TryStreamExt};
|
||||
use std::future;
|
||||
|
||||
pub use sqlx_core::any::*;
|
||||
|
||||
@@ -76,10 +77,15 @@ impl AnyConnectionBackend for PgConnection {
|
||||
arguments: Option<AnyArguments<'q>>,
|
||||
) -> BoxStream<'q, sqlx_core::Result<Either<AnyQueryResult, AnyRow>>> {
|
||||
let persistent = arguments.is_some();
|
||||
let args = arguments.as_ref().map(AnyArguments::convert_to);
|
||||
let arguments = match arguments.as_ref().map(AnyArguments::convert_to).transpose() {
|
||||
Ok(arguments) => arguments,
|
||||
Err(error) => {
|
||||
return stream::once(future::ready(Err(sqlx_core::Error::Encode(error)))).boxed()
|
||||
}
|
||||
};
|
||||
|
||||
Box::pin(
|
||||
self.run(query, args, 0, persistent, None)
|
||||
self.run(query, arguments, 0, persistent, None)
|
||||
.try_flatten_stream()
|
||||
.map(
|
||||
move |res: sqlx_core::Result<Either<PgQueryResult, PgRow>>| match res? {
|
||||
@@ -96,10 +102,15 @@ impl AnyConnectionBackend for PgConnection {
|
||||
arguments: Option<AnyArguments<'q>>,
|
||||
) -> BoxFuture<'q, sqlx_core::Result<Option<AnyRow>>> {
|
||||
let persistent = arguments.is_some();
|
||||
let args = arguments.as_ref().map(AnyArguments::convert_to);
|
||||
let arguments = arguments
|
||||
.as_ref()
|
||||
.map(AnyArguments::convert_to)
|
||||
.transpose()
|
||||
.map_err(sqlx_core::Error::Encode);
|
||||
|
||||
Box::pin(async move {
|
||||
let stream = self.run(query, args, 1, persistent, None).await?;
|
||||
let arguments = arguments?;
|
||||
let stream = self.run(query, arguments, 1, persistent, None).await?;
|
||||
futures_util::pin_mut!(stream);
|
||||
|
||||
if let Some(Either::Right(row)) = stream.try_next().await? {
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::types::Type;
|
||||
use crate::{PgConnection, PgTypeInfo, Postgres};
|
||||
|
||||
pub(crate) use sqlx_core::arguments::Arguments;
|
||||
use sqlx_core::error::BoxDynError;
|
||||
|
||||
// TODO: buf.patch(|| ...) is a poor name, can we think of a better name? Maybe `buf.lazy(||)` ?
|
||||
// TODO: Extend the patch system to support dynamic lengths
|
||||
@@ -59,19 +60,27 @@ pub struct PgArguments {
|
||||
}
|
||||
|
||||
impl PgArguments {
|
||||
pub(crate) fn add<'q, T>(&mut self, value: T)
|
||||
pub(crate) fn add<'q, T>(&mut self, value: T) -> Result<(), BoxDynError>
|
||||
where
|
||||
T: Encode<'q, Postgres> + Type<Postgres>,
|
||||
{
|
||||
// remember the type information for this value
|
||||
self.types
|
||||
.push(value.produces().unwrap_or_else(T::type_info));
|
||||
let type_info = value.produces().unwrap_or_else(T::type_info);
|
||||
|
||||
let buffer_snapshot = self.buffer.snapshot();
|
||||
|
||||
// encode the value into our buffer
|
||||
self.buffer.encode(value);
|
||||
if let Err(error) = self.buffer.encode(value) {
|
||||
// reset the value buffer to its previous value if encoding failed so we don't leave a half-encoded value behind
|
||||
self.buffer.reset_to_snapshot(buffer_snapshot);
|
||||
return Err(error);
|
||||
};
|
||||
|
||||
// remember the type information for this value
|
||||
self.types.push(type_info);
|
||||
// increment the number of arguments we are tracking
|
||||
self.buffer.count += 1;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Apply patches
|
||||
@@ -112,7 +121,7 @@ impl<'q> Arguments<'q> for PgArguments {
|
||||
self.buffer.reserve(size);
|
||||
}
|
||||
|
||||
fn add<T>(&mut self, value: T)
|
||||
fn add<T>(&mut self, value: T) -> Result<(), BoxDynError>
|
||||
where
|
||||
T: Encode<'q, Self::Database> + Type<Self::Database>,
|
||||
{
|
||||
@@ -122,10 +131,14 @@ impl<'q> Arguments<'q> for PgArguments {
|
||||
fn format_placeholder<W: Write>(&self, writer: &mut W) -> fmt::Result {
|
||||
write!(writer, "${}", self.buffer.count)
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.buffer.count
|
||||
}
|
||||
}
|
||||
|
||||
impl PgArgumentBuffer {
|
||||
pub(crate) fn encode<'q, T>(&mut self, value: T)
|
||||
pub(crate) fn encode<'q, T>(&mut self, value: T) -> Result<(), BoxDynError>
|
||||
where
|
||||
T: Encode<'q, Postgres>,
|
||||
{
|
||||
@@ -134,7 +147,7 @@ impl PgArgumentBuffer {
|
||||
self.extend(&[0; 4]);
|
||||
|
||||
// encode the value into our buffer
|
||||
let len = if let IsNull::No = value.encode(self) {
|
||||
let len = if let IsNull::No = value.encode(self)? {
|
||||
(self.len() - offset - 4) as i32
|
||||
} else {
|
||||
// Write a -1 to indicate NULL
|
||||
@@ -145,6 +158,8 @@ impl PgArgumentBuffer {
|
||||
|
||||
// write the len to the beginning of the value
|
||||
self[offset..(offset + 4)].copy_from_slice(&len.to_be_bytes());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Adds a callback to be invoked later when we know the parameter type
|
||||
@@ -167,6 +182,44 @@ impl PgArgumentBuffer {
|
||||
self.extend_from_slice(&0_u32.to_be_bytes());
|
||||
self.type_holes.push((offset, type_name.clone()));
|
||||
}
|
||||
|
||||
fn snapshot(&self) -> PgArgumentBufferSnapshot {
|
||||
let Self {
|
||||
buffer,
|
||||
count,
|
||||
patches,
|
||||
type_holes,
|
||||
} = self;
|
||||
|
||||
PgArgumentBufferSnapshot {
|
||||
buffer_length: buffer.len(),
|
||||
count: *count,
|
||||
patches_length: patches.len(),
|
||||
type_holes_length: type_holes.len(),
|
||||
}
|
||||
}
|
||||
|
||||
fn reset_to_snapshot(
|
||||
&mut self,
|
||||
PgArgumentBufferSnapshot {
|
||||
buffer_length,
|
||||
count,
|
||||
patches_length,
|
||||
type_holes_length,
|
||||
}: PgArgumentBufferSnapshot,
|
||||
) {
|
||||
self.buffer.truncate(buffer_length);
|
||||
self.count = count;
|
||||
self.patches.truncate(patches_length);
|
||||
self.type_holes.truncate(type_holes_length);
|
||||
}
|
||||
}
|
||||
|
||||
struct PgArgumentBufferSnapshot {
|
||||
buffer_length: usize,
|
||||
count: usize,
|
||||
patches_length: usize,
|
||||
type_holes_length: usize,
|
||||
}
|
||||
|
||||
impl Deref for PgArgumentBuffer {
|
||||
|
||||
@@ -382,9 +382,10 @@ WHERE rngtypid = $1
|
||||
bind + 2
|
||||
);
|
||||
|
||||
args.add(i as i32);
|
||||
args.add(column.relation_id);
|
||||
args.add(column.relation_attribute_no);
|
||||
args.add(i as i32).map_err(Error::Encode)?;
|
||||
args.add(column.relation_id).map_err(Error::Encode)?;
|
||||
args.add(column.relation_attribute_no)
|
||||
.map_err(Error::Encode)?;
|
||||
}
|
||||
|
||||
nullable_query.push_str(
|
||||
|
||||
@@ -370,10 +370,11 @@ impl<'c> Executor<'c> for &'c mut PgConnection {
|
||||
{
|
||||
let sql = query.sql();
|
||||
let metadata = query.statement().map(|s| Arc::clone(&s.metadata));
|
||||
let arguments = query.take_arguments();
|
||||
let arguments = query.take_arguments().map_err(Error::Encode);
|
||||
let persistent = query.persistent();
|
||||
|
||||
Box::pin(try_stream! {
|
||||
let arguments = arguments?;
|
||||
let s = self.run(sql, arguments, 0, persistent, metadata).await?;
|
||||
pin_mut!(s);
|
||||
|
||||
@@ -395,10 +396,11 @@ impl<'c> Executor<'c> for &'c mut PgConnection {
|
||||
{
|
||||
let sql = query.sql();
|
||||
let metadata = query.statement().map(|s| Arc::clone(&s.metadata));
|
||||
let arguments = query.take_arguments();
|
||||
let arguments = query.take_arguments().map_err(Error::Encode);
|
||||
let persistent = query.persistent();
|
||||
|
||||
Box::pin(async move {
|
||||
let arguments = arguments?;
|
||||
let s = self.run(sql, arguments, 1, persistent, metadata).await?;
|
||||
pin_mut!(s);
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ where
|
||||
T: Encode<'q, Postgres>,
|
||||
{
|
||||
#[inline]
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
self.as_slice().encode_by_ref(buf)
|
||||
}
|
||||
}
|
||||
@@ -146,7 +146,7 @@ where
|
||||
for<'a> &'a [T]: Encode<'q, Postgres>,
|
||||
T: Encode<'q, Postgres>,
|
||||
{
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
self.as_slice().encode_by_ref(buf)
|
||||
}
|
||||
}
|
||||
@@ -155,7 +155,7 @@ impl<'q, T> Encode<'q, Postgres> for &'_ [T]
|
||||
where
|
||||
T: Encode<'q, Postgres> + Type<Postgres>,
|
||||
{
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
let type_info = if self.len() < 1 {
|
||||
T::type_info()
|
||||
} else {
|
||||
@@ -178,10 +178,10 @@ where
|
||||
buf.extend(&1_i32.to_be_bytes()); // lower bound
|
||||
|
||||
for element in self.iter() {
|
||||
buf.encode(element);
|
||||
buf.encode(element)?;
|
||||
}
|
||||
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -137,24 +137,10 @@ impl TryFrom<&'_ BigDecimal> for PgNumeric {
|
||||
|
||||
#[doc=include_str!("bigdecimal-range.md")]
|
||||
impl Encode<'_, Postgres> for BigDecimal {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
// If the argument is too big, then we replace it with a less big argument.
|
||||
// This less big argument is already outside the range of allowed PostgreSQL DECIMAL, which
|
||||
// means that PostgreSQL will return the 22P03 error kind upon receiving it. This is the
|
||||
// expected error, and the user should be ready to handle it anyway.
|
||||
PgNumeric::try_from(self)
|
||||
.unwrap_or_else(|_| {
|
||||
PgNumeric::Number {
|
||||
digits: vec![1],
|
||||
// This is larger than the maximum allowed value, so Postgres should return an error.
|
||||
scale: 0x4000,
|
||||
weight: 0,
|
||||
sign: sign_to_pg(self.sign()),
|
||||
}
|
||||
})
|
||||
.encode(buf);
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
PgNumeric::try_from(self)?.encode(buf);
|
||||
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> usize {
|
||||
|
||||
@@ -30,11 +30,11 @@ impl PgHasArrayType for BitVec {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for BitVec {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
buf.extend(&(self.len() as i32).to_be_bytes());
|
||||
buf.extend(self.to_bytes());
|
||||
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> usize {
|
||||
|
||||
@@ -17,10 +17,10 @@ impl PgHasArrayType for bool {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for bool {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
buf.push(*self as u8);
|
||||
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,27 +35,27 @@ impl<const N: usize> PgHasArrayType for [u8; N] {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for &'_ [u8] {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
buf.extend_from_slice(self);
|
||||
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for Box<[u8]> {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
<&[u8] as Encode<Postgres>>::encode(self.as_ref(), buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for Vec<u8> {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
<&[u8] as Encode<Postgres>>::encode(self, buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> Encode<'_, Postgres> for [u8; N] {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
<&[u8] as Encode<Postgres>>::encode(self.as_slice(), buf)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ impl PgHasArrayType for NaiveDate {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for NaiveDate {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
// DATE is encoded as the days since epoch
|
||||
let days = (*self - postgres_epoch_date()).num_days() as i32;
|
||||
Encode::<Postgres>::encode(&days, buf)
|
||||
|
||||
@@ -33,12 +33,11 @@ impl<Tz: TimeZone> PgHasArrayType for DateTime<Tz> {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for NaiveDateTime {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
// FIXME: We should *really* be returning an error, Encode needs to be fallible
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
// TIMESTAMP is encoded as the microseconds since the epoch
|
||||
let us = (*self - postgres_epoch_datetime())
|
||||
.num_microseconds()
|
||||
.unwrap_or_else(|| panic!("NaiveDateTime out of range for Postgres: {self:?}"));
|
||||
.ok_or_else(|| format!("NaiveDateTime out of range for Postgres: {self:?}"))?;
|
||||
|
||||
Encode::<Postgres>::encode(&us, buf)
|
||||
}
|
||||
@@ -76,7 +75,7 @@ impl<'r> Decode<'r, Postgres> for NaiveDateTime {
|
||||
}
|
||||
|
||||
impl<Tz: TimeZone> Encode<'_, Postgres> for DateTime<Tz> {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
Encode::<Postgres>::encode(self.naive_utc(), buf)
|
||||
}
|
||||
|
||||
|
||||
@@ -19,10 +19,11 @@ impl PgHasArrayType for NaiveTime {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for NaiveTime {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
// TIME is encoded as the microseconds since midnight
|
||||
// NOTE: panic! is on overflow and 1 day does not have enough micros to overflow
|
||||
let us = (*self - NaiveTime::default()).num_microseconds().unwrap();
|
||||
let us = (*self - NaiveTime::default())
|
||||
.num_microseconds()
|
||||
.ok_or_else(|| format!("Time out of range for PostgreSQL: {self}"))?;
|
||||
|
||||
Encode::<Postgres>::encode(&us, buf)
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ impl PgHasArrayType for PgCiText {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for PgCiText {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
<&str as Encode<Postgres>>::encode(&**self, buf)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,10 +19,10 @@ impl PgHasArrayType for f32 {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for f32 {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
buf.extend(&self.to_be_bytes());
|
||||
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,10 +48,10 @@ impl PgHasArrayType for f64 {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for f64 {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
buf.extend(&self.to_be_bytes());
|
||||
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,10 +44,10 @@ impl PgHasArrayType for i8 {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for i8 {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
buf.extend(&self.to_be_bytes());
|
||||
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,10 +89,10 @@ impl PgHasArrayType for i16 {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for i16 {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
buf.extend(&self.to_be_bytes());
|
||||
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,10 +115,10 @@ impl PgHasArrayType for i32 {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for i32 {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
buf.extend(&self.to_be_bytes());
|
||||
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,10 +141,10 @@ impl PgHasArrayType for i64 {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for i64 {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
buf.extend(&self.to_be_bytes());
|
||||
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,12 +54,12 @@ impl<'de> Decode<'de, Postgres> for PgInterval {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for PgInterval {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
buf.extend(&self.microseconds.to_be_bytes());
|
||||
buf.extend(&self.days.to_be_bytes());
|
||||
buf.extend(&self.months.to_be_bytes());
|
||||
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> usize {
|
||||
@@ -83,10 +83,8 @@ impl PgHasArrayType for std::time::Duration {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for std::time::Duration {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
PgInterval::try_from(*self)
|
||||
.expect("failed to encode `std::time::Duration`")
|
||||
.encode_by_ref(buf)
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
PgInterval::try_from(*self)?.encode_by_ref(buf)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> usize {
|
||||
@@ -130,8 +128,8 @@ impl PgHasArrayType for chrono::Duration {
|
||||
|
||||
#[cfg(feature = "chrono")]
|
||||
impl Encode<'_, Postgres> for chrono::Duration {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
let pg_interval = PgInterval::try_from(*self).expect("Failed to encode chrono::Duration");
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
let pg_interval = PgInterval::try_from(*self)?;
|
||||
pg_interval.encode_by_ref(buf)
|
||||
}
|
||||
|
||||
@@ -192,8 +190,8 @@ impl PgHasArrayType for time::Duration {
|
||||
|
||||
#[cfg(feature = "time")]
|
||||
impl Encode<'_, Postgres> for time::Duration {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
let pg_interval = PgInterval::try_from(*self).expect("Failed to encode time::Duration");
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
let pg_interval = PgInterval::try_from(*self)?;
|
||||
pg_interval.encode_by_ref(buf)
|
||||
}
|
||||
|
||||
@@ -234,7 +232,7 @@ fn test_encode_interval() {
|
||||
};
|
||||
assert!(matches!(
|
||||
Encode::<Postgres>::encode(&interval, &mut buf),
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
));
|
||||
assert_eq!(&**buf, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
|
||||
buf.clear();
|
||||
@@ -246,7 +244,7 @@ fn test_encode_interval() {
|
||||
};
|
||||
assert!(matches!(
|
||||
Encode::<Postgres>::encode(&interval, &mut buf),
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
));
|
||||
assert_eq!(&**buf, [0, 0, 0, 0, 0, 0, 3, 232, 0, 0, 0, 0, 0, 0, 0, 0]);
|
||||
buf.clear();
|
||||
@@ -258,7 +256,7 @@ fn test_encode_interval() {
|
||||
};
|
||||
assert!(matches!(
|
||||
Encode::<Postgres>::encode(&interval, &mut buf),
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
));
|
||||
assert_eq!(&**buf, [0, 0, 0, 0, 0, 15, 66, 64, 0, 0, 0, 0, 0, 0, 0, 0]);
|
||||
buf.clear();
|
||||
@@ -270,7 +268,7 @@ fn test_encode_interval() {
|
||||
};
|
||||
assert!(matches!(
|
||||
Encode::<Postgres>::encode(&interval, &mut buf),
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
));
|
||||
assert_eq!(
|
||||
&**buf,
|
||||
@@ -285,7 +283,7 @@ fn test_encode_interval() {
|
||||
};
|
||||
assert!(matches!(
|
||||
Encode::<Postgres>::encode(&interval, &mut buf),
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
));
|
||||
assert_eq!(&**buf, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]);
|
||||
buf.clear();
|
||||
@@ -297,7 +295,7 @@ fn test_encode_interval() {
|
||||
};
|
||||
assert!(matches!(
|
||||
Encode::<Postgres>::encode(&interval, &mut buf),
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
));
|
||||
assert_eq!(&**buf, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
|
||||
buf.clear();
|
||||
|
||||
@@ -35,7 +35,7 @@ impl<'db> Encode<'db, Postgres> for IpAddr
|
||||
where
|
||||
IpNetwork: Encode<'db, Postgres>,
|
||||
{
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
IpNetwork::from(*self).encode_by_ref(buf)
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ impl PgHasArrayType for IpNetwork {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for IpNetwork {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
// https://github.com/postgres/postgres/blob/574925bfd0a8175f6e161936ea11d9695677ba09/src/backend/utils/adt/network.c#L293
|
||||
// https://github.com/postgres/postgres/blob/574925bfd0a8175f6e161936ea11d9695677ba09/src/backend/utils/adt/network.c#L271
|
||||
|
||||
@@ -58,7 +58,7 @@ impl Encode<'_, Postgres> for IpNetwork {
|
||||
}
|
||||
}
|
||||
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> usize {
|
||||
|
||||
@@ -58,7 +58,7 @@ impl<'q, T> Encode<'q, Postgres> for Json<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
// we have a tiny amount of dynamic behavior depending if we are resolved to be JSON
|
||||
// instead of JSONB
|
||||
buf.patch(|buf, ty: &PgTypeInfo| {
|
||||
@@ -71,10 +71,9 @@ where
|
||||
buf.push(1);
|
||||
|
||||
// the JSON data written to the buffer is the same regardless of parameter type
|
||||
serde_json::to_writer(&mut **buf, &self.0)
|
||||
.expect("failed to serialize to JSON for encoding on transmission to the database");
|
||||
serde_json::to_writer(&mut **buf, &self.0)?;
|
||||
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -139,12 +139,11 @@ impl Type<Postgres> for PgLQuery {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for PgLQuery {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
buf.extend(1i8.to_le_bytes());
|
||||
write!(buf, "{self}")
|
||||
.expect("Display implementation panicked while writing to PgArgumentBuffer");
|
||||
write!(buf, "{self}")?;
|
||||
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -181,12 +181,11 @@ impl PgHasArrayType for PgLTree {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for PgLTree {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
buf.extend(1i8.to_le_bytes());
|
||||
write!(buf, "{self}")
|
||||
.expect("Display implementation panicked while writing to PgArgumentBuffer");
|
||||
write!(buf, "{self}")?;
|
||||
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,9 +23,9 @@ impl PgHasArrayType for MacAddress {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for MacAddress {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
buf.extend_from_slice(&self.bytes()); // write just the address
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> usize {
|
||||
|
||||
@@ -165,10 +165,10 @@ where
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for PgMoney {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
buf.extend(&self.0.to_be_bytes());
|
||||
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,10 +36,10 @@ impl PgHasArrayType for Oid {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for Oid {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
buf.extend(&self.0.to_be_bytes());
|
||||
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -292,7 +292,7 @@ impl<'q, T> Encode<'q, Postgres> for PgRange<T>
|
||||
where
|
||||
T: Encode<'q, Postgres>,
|
||||
{
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
// https://github.com/postgres/postgres/blob/2f48ede080f42b97b594fb14102c82ca1001b80c/src/backend/utils/adt/rangetypes.c#L245
|
||||
|
||||
let mut flags = RangeFlags::empty();
|
||||
@@ -312,15 +312,15 @@ where
|
||||
buf.push(flags.bits());
|
||||
|
||||
if let Bound::Included(v) | Bound::Excluded(v) = &self.start {
|
||||
buf.encode(v);
|
||||
buf.encode(v)?;
|
||||
}
|
||||
|
||||
if let Bound::Included(v) | Bound::Excluded(v) = &self.end {
|
||||
buf.encode(v);
|
||||
buf.encode(v)?;
|
||||
}
|
||||
|
||||
// ranges are themselves never null
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ impl<'a> PgRecordEncoder<'a> {
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn encode<'q, T>(&mut self, value: T) -> &mut Self
|
||||
pub fn encode<'q, T>(&mut self, value: T) -> Result<&mut Self, BoxDynError>
|
||||
where
|
||||
'a: 'q,
|
||||
T: Encode<'q, Postgres> + Type<Postgres>,
|
||||
@@ -50,10 +50,10 @@ impl<'a> PgRecordEncoder<'a> {
|
||||
self.buf.extend(&ty.0.oid().0.to_be_bytes());
|
||||
}
|
||||
|
||||
self.buf.encode(value);
|
||||
self.buf.encode(value)?;
|
||||
self.num += 1;
|
||||
|
||||
self
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,18 +72,16 @@ impl TryFrom<PgNumeric> for Decimal {
|
||||
}
|
||||
|
||||
// This impl is effectively infallible because `NUMERIC` has a greater range than `Decimal`.
|
||||
impl TryFrom<&'_ Decimal> for PgNumeric {
|
||||
type Error = BoxDynError;
|
||||
|
||||
fn try_from(decimal: &Decimal) -> Result<Self, BoxDynError> {
|
||||
impl From<&'_ Decimal> for PgNumeric {
|
||||
fn from(decimal: &Decimal) -> Self {
|
||||
// `Decimal` added `is_zero()` as an inherent method in a more recent version
|
||||
if Zero::is_zero(decimal) {
|
||||
return Ok(PgNumeric::Number {
|
||||
PgNumeric::Number {
|
||||
sign: PgNumericSign::Positive,
|
||||
scale: 0,
|
||||
weight: 0,
|
||||
digits: vec![],
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
let scale = decimal.scale() as u16;
|
||||
@@ -131,7 +129,7 @@ impl TryFrom<&'_ Decimal> for PgNumeric {
|
||||
digits.pop();
|
||||
}
|
||||
|
||||
Ok(PgNumeric::Number {
|
||||
PgNumeric::Number {
|
||||
sign: match decimal.is_sign_negative() {
|
||||
false => PgNumericSign::Positive,
|
||||
true => PgNumericSign::Negative,
|
||||
@@ -139,17 +137,15 @@ impl TryFrom<&'_ Decimal> for PgNumeric {
|
||||
scale: scale as i16,
|
||||
weight,
|
||||
digits,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for Decimal {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
PgNumeric::try_from(self)
|
||||
.expect("BUG: `Decimal` to `PgNumeric` conversion should be infallible")
|
||||
.encode(buf);
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
PgNumeric::from(self).encode(buf);
|
||||
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -95,15 +95,15 @@ impl PgHasArrayType for String {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for &'_ str {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
buf.extend(self.as_bytes());
|
||||
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for Cow<'_, str> {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
match self {
|
||||
Cow::Borrowed(str) => <&str as Encode<Postgres>>::encode(*str, buf),
|
||||
Cow::Owned(str) => <&str as Encode<Postgres>>::encode(&**str, buf),
|
||||
@@ -112,13 +112,13 @@ impl Encode<'_, Postgres> for Cow<'_, str> {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for Box<str> {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
<&str as Encode<Postgres>>::encode(&**self, buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for String {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
<&str as Encode<Postgres>>::encode(&**self, buf)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,19 +22,9 @@ impl<'q, T> Encode<'q, Postgres> for Text<T>
|
||||
where
|
||||
T: Display,
|
||||
{
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
// Unfortunately, our API design doesn't give us a way to bubble up the error here.
|
||||
//
|
||||
// Fortunately, writing to `Vec<u8>` is infallible so the only possible source of
|
||||
// errors is from the implementation of `Display::fmt()` itself,
|
||||
// where the onus is on the user.
|
||||
//
|
||||
// The blanket impl of `ToString` also panics if there's an error, so this is not
|
||||
// unprecedented.
|
||||
//
|
||||
// However, the panic should be documented anyway.
|
||||
write!(**buf, "{}", self.0).expect("unexpected error from `Display::fmt()`");
|
||||
IsNull::No
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
write!(**buf, "{}", self.0)?;
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ impl PgHasArrayType for Date {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for Date {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
// DATE is encoded as the days since epoch
|
||||
let days = (*self - PG_EPOCH).whole_days() as i32;
|
||||
Encode::<Postgres>::encode(&days, buf)
|
||||
|
||||
@@ -35,7 +35,7 @@ impl PgHasArrayType for OffsetDateTime {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for PrimitiveDateTime {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
// TIMESTAMP is encoded as the microseconds since the epoch
|
||||
let us = (*self - PG_EPOCH.midnight()).whole_microseconds() as i64;
|
||||
Encode::<Postgres>::encode(&us, buf)
|
||||
@@ -84,7 +84,7 @@ impl<'r> Decode<'r, Postgres> for PrimitiveDateTime {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for OffsetDateTime {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
let utc = self.to_offset(offset!(UTC));
|
||||
let primitive = PrimitiveDateTime::new(utc.date(), utc.time());
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ impl PgHasArrayType for Time {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for Time {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
// TIME is encoded as the microseconds since midnight
|
||||
let us = (*self - Time::MIDNIGHT).whole_microseconds() as i64;
|
||||
Encode::<Postgres>::encode(&us, buf)
|
||||
|
||||
@@ -51,11 +51,12 @@ mod chrono {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for PgTimeTz<NaiveTime, FixedOffset> {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
let _ = <NaiveTime as Encode<'_, Postgres>>::encode(self.time, buf);
|
||||
let _ = <i32 as Encode<'_, Postgres>>::encode(self.offset.utc_minus_local(), buf);
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
let _: IsNull = <NaiveTime as Encode<'_, Postgres>>::encode(self.time, buf)?;
|
||||
let _: IsNull =
|
||||
<i32 as Encode<'_, Postgres>>::encode(self.offset.utc_minus_local(), buf)?;
|
||||
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> usize {
|
||||
@@ -134,11 +135,12 @@ mod time {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for PgTimeTz<Time, UtcOffset> {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
let _ = <Time as Encode<'_, Postgres>>::encode(self.time, buf);
|
||||
let _ = <i32 as Encode<'_, Postgres>>::encode(-self.offset.whole_seconds(), buf);
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
let _: IsNull = <Time as Encode<'_, Postgres>>::encode(self.time, buf)?;
|
||||
let _: IsNull =
|
||||
<i32 as Encode<'_, Postgres>>::encode(-self.offset.whole_seconds(), buf)?;
|
||||
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> usize {
|
||||
|
||||
@@ -19,10 +19,10 @@ impl PgHasArrayType for Uuid {
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for Uuid {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
buf.extend_from_slice(self.as_bytes());
|
||||
|
||||
IsNull::No
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user