mirror of
https://github.com/launchbadge/sqlx.git
synced 2026-03-21 17:44:06 +00:00
fix: clippy warnings
This commit is contained in:
@@ -32,12 +32,7 @@ pub struct PgArgumentBuffer {
|
||||
//
|
||||
// This currently is only setup to be useful if there is a *fixed-size* slot that needs to be
|
||||
// tweaked from the input type. However, that's the only use case we currently have.
|
||||
//
|
||||
patches: Vec<(
|
||||
usize, // offset
|
||||
usize, // argument index
|
||||
Box<dyn Fn(&mut [u8], &PgTypeInfo) + 'static + Send + Sync>,
|
||||
)>,
|
||||
patches: Vec<Patch>,
|
||||
|
||||
// Whenever an `Encode` impl encounters a `PgTypeInfo` object that does not have an OID
|
||||
// It pushes a "hole" that must be patched later.
|
||||
@@ -49,6 +44,13 @@ pub struct PgArgumentBuffer {
|
||||
type_holes: Vec<(usize, UStr)>, // Vec<{ offset, type_name }>
|
||||
}
|
||||
|
||||
struct Patch {
|
||||
buf_offset: usize,
|
||||
arg_index: usize,
|
||||
#[allow(clippy::type_complexity)]
|
||||
callback: Box<dyn Fn(&mut [u8], &PgTypeInfo) + 'static + Send + Sync>,
|
||||
}
|
||||
|
||||
/// Implementation of [`Arguments`] for PostgreSQL.
|
||||
#[derive(Default)]
|
||||
pub struct PgArguments {
|
||||
@@ -97,15 +99,15 @@ impl PgArguments {
|
||||
..
|
||||
} = self.buffer;
|
||||
|
||||
for (offset, ty, callback) in patches {
|
||||
let buf = &mut buffer[*offset..];
|
||||
let ty = ¶meters[*ty];
|
||||
for patch in patches {
|
||||
let buf = &mut buffer[patch.buf_offset..];
|
||||
let ty = ¶meters[patch.arg_index];
|
||||
|
||||
callback(buf, ty);
|
||||
(patch.callback)(buf, ty);
|
||||
}
|
||||
|
||||
for (offset, name) in type_holes {
|
||||
let oid = conn.fetch_type_id_by_name(&*name).await?;
|
||||
let oid = conn.fetch_type_id_by_name(name).await?;
|
||||
buffer[*offset..(*offset + 4)].copy_from_slice(&oid.0.to_be_bytes());
|
||||
}
|
||||
|
||||
@@ -169,9 +171,13 @@ impl PgArgumentBuffer {
|
||||
F: Fn(&mut [u8], &PgTypeInfo) + 'static + Send + Sync,
|
||||
{
|
||||
let offset = self.len();
|
||||
let index = self.count;
|
||||
let arg_index = self.count;
|
||||
|
||||
self.patches.push((offset, index, Box::new(callback)));
|
||||
self.patches.push(Patch {
|
||||
buf_offset: offset,
|
||||
arg_index,
|
||||
callback: Box::new(callback),
|
||||
});
|
||||
}
|
||||
|
||||
// Extends the inner buffer by enough space to have an OID
|
||||
|
||||
@@ -23,7 +23,7 @@ impl Column for PgColumn {
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
&*self.name
|
||||
&self.name
|
||||
}
|
||||
|
||||
fn type_info(&self) -> &PgTypeInfo {
|
||||
|
||||
@@ -463,7 +463,7 @@ WHERE rngtypid = $1
|
||||
}) = explains.first()
|
||||
{
|
||||
nullables.resize(outputs.len(), None);
|
||||
visit_plan(&plan, outputs, &mut nullables);
|
||||
visit_plan(plan, outputs, &mut nullables);
|
||||
}
|
||||
|
||||
Ok(nullables)
|
||||
|
||||
@@ -48,7 +48,7 @@ async fn prepare(
|
||||
|
||||
// next we send the PARSE command to the server
|
||||
conn.stream.write(Parse {
|
||||
param_types: &*param_types,
|
||||
param_types: ¶m_types,
|
||||
query: sql,
|
||||
statement: id,
|
||||
});
|
||||
@@ -63,8 +63,7 @@ async fn prepare(
|
||||
conn.stream.flush().await?;
|
||||
|
||||
// indicates that the SQL query string is now successfully parsed and has semantic validity
|
||||
let _ = conn
|
||||
.stream
|
||||
conn.stream
|
||||
.recv_expect(MessageFormat::ParseComplete)
|
||||
.await?;
|
||||
|
||||
@@ -227,7 +226,7 @@ impl PgConnection {
|
||||
statement,
|
||||
formats: &[PgValueFormat::Binary],
|
||||
num_params: arguments.types.len() as i16,
|
||||
params: &*arguments.buffer,
|
||||
params: &arguments.buffer,
|
||||
result_formats: &[PgValueFormat::Binary],
|
||||
});
|
||||
|
||||
@@ -360,15 +359,19 @@ impl PgConnection {
|
||||
impl<'c> Executor<'c> for &'c mut PgConnection {
|
||||
type Database = Postgres;
|
||||
|
||||
fn fetch_many<'e, 'q: 'e, E: 'q>(
|
||||
fn fetch_many<'e, 'q, E>(
|
||||
self,
|
||||
mut query: E,
|
||||
) -> BoxStream<'e, Result<Either<PgQueryResult, PgRow>, Error>>
|
||||
where
|
||||
'c: 'e,
|
||||
E: Execute<'q, Self::Database>,
|
||||
'q: 'e,
|
||||
E: 'q,
|
||||
{
|
||||
let sql = query.sql();
|
||||
// False positive: https://github.com/rust-lang/rust-clippy/issues/12560
|
||||
#[allow(clippy::map_clone)]
|
||||
let metadata = query.statement().map(|s| Arc::clone(&s.metadata));
|
||||
let arguments = query.take_arguments().map_err(Error::Encode);
|
||||
let persistent = query.persistent();
|
||||
@@ -386,15 +389,16 @@ impl<'c> Executor<'c> for &'c mut PgConnection {
|
||||
})
|
||||
}
|
||||
|
||||
fn fetch_optional<'e, 'q: 'e, E: 'q>(
|
||||
self,
|
||||
mut query: E,
|
||||
) -> BoxFuture<'e, Result<Option<PgRow>, Error>>
|
||||
fn fetch_optional<'e, 'q, E>(self, mut query: E) -> BoxFuture<'e, Result<Option<PgRow>, Error>>
|
||||
where
|
||||
'c: 'e,
|
||||
E: Execute<'q, Self::Database>,
|
||||
'q: 'e,
|
||||
E: 'q,
|
||||
{
|
||||
let sql = query.sql();
|
||||
// False positive: https://github.com/rust-lang/rust-clippy/issues/12560
|
||||
#[allow(clippy::map_clone)]
|
||||
let metadata = query.statement().map(|s| Arc::clone(&s.metadata));
|
||||
let arguments = query.take_arguments().map_err(Error::Encode);
|
||||
let persistent = query.persistent();
|
||||
|
||||
@@ -101,7 +101,7 @@ pub(crate) async fn authenticate(
|
||||
let client_key = mac.finalize().into_bytes();
|
||||
|
||||
// StoredKey := H(ClientKey)
|
||||
let stored_key = Sha256::digest(&client_key);
|
||||
let stored_key = Sha256::digest(client_key);
|
||||
|
||||
// client-final-message-without-proof
|
||||
let client_final_message_wo_proof = format!(
|
||||
@@ -120,7 +120,7 @@ pub(crate) async fn authenticate(
|
||||
|
||||
// ClientSignature := HMAC(StoredKey, AuthMessage)
|
||||
let mut mac = Hmac::<Sha256>::new_from_slice(&stored_key).map_err(Error::protocol)?;
|
||||
mac.update(&auth_message.as_bytes());
|
||||
mac.update(auth_message.as_bytes());
|
||||
|
||||
let client_signature = mac.finalize().into_bytes();
|
||||
|
||||
@@ -139,7 +139,7 @@ pub(crate) async fn authenticate(
|
||||
|
||||
// ServerSignature := HMAC(ServerKey, AuthMessage)
|
||||
let mut mac = Hmac::<Sha256>::new_from_slice(&server_key).map_err(Error::protocol)?;
|
||||
mac.update(&auth_message.as_bytes());
|
||||
mac.update(auth_message.as_bytes());
|
||||
|
||||
// client-final-message = client-final-message-without-proof "," proof
|
||||
let mut client_final_message = format!("{client_final_message_wo_proof},{CLIENT_PROOF_ATTR}=");
|
||||
@@ -192,7 +192,7 @@ fn gen_nonce() -> String {
|
||||
fn hi<'a>(s: &'a str, salt: &'a [u8], iter_count: u32) -> Result<[u8; 32], Error> {
|
||||
let mut mac = Hmac::<Sha256>::new_from_slice(s.as_bytes()).map_err(Error::protocol)?;
|
||||
|
||||
mac.update(&salt);
|
||||
mac.update(salt);
|
||||
mac.update(&1u32.to_be_bytes());
|
||||
|
||||
let mut u = mac.finalize_reset().into_bytes();
|
||||
|
||||
@@ -159,11 +159,10 @@ impl PgStream {
|
||||
tracing_level
|
||||
);
|
||||
if log_is_enabled {
|
||||
let message = format!("{}", notice.message());
|
||||
sqlx_core::private_tracing_dynamic_event!(
|
||||
target: "sqlx::postgres::notice",
|
||||
tracing_level,
|
||||
message
|
||||
message = notice.message()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -211,7 +210,7 @@ fn parse_server_version(s: &str) -> Option<u32> {
|
||||
break;
|
||||
}
|
||||
}
|
||||
_ if ch.is_digit(10) => {
|
||||
_ if ch.is_ascii_digit() => {
|
||||
if chs.peek().is_none() {
|
||||
if let Ok(num) = u32::from_str(&s[from..]) {
|
||||
parts.push(num);
|
||||
|
||||
@@ -332,13 +332,15 @@ impl Drop for PgListener {
|
||||
impl<'c> Executor<'c> for &'c mut PgListener {
|
||||
type Database = Postgres;
|
||||
|
||||
fn fetch_many<'e, 'q: 'e, E: 'q>(
|
||||
fn fetch_many<'e, 'q, E>(
|
||||
self,
|
||||
query: E,
|
||||
) -> BoxStream<'e, Result<Either<PgQueryResult, PgRow>, Error>>
|
||||
where
|
||||
'c: 'e,
|
||||
E: Execute<'q, Self::Database>,
|
||||
'q: 'e,
|
||||
E: 'q,
|
||||
{
|
||||
futures_util::stream::once(async move {
|
||||
// need some basic type annotation to help the compiler a bit
|
||||
@@ -349,13 +351,12 @@ impl<'c> Executor<'c> for &'c mut PgListener {
|
||||
.boxed()
|
||||
}
|
||||
|
||||
fn fetch_optional<'e, 'q: 'e, E: 'q>(
|
||||
self,
|
||||
query: E,
|
||||
) -> BoxFuture<'e, Result<Option<PgRow>, Error>>
|
||||
fn fetch_optional<'e, 'q, E>(self, query: E) -> BoxFuture<'e, Result<Option<PgRow>, Error>>
|
||||
where
|
||||
'c: 'e,
|
||||
E: Execute<'q, Self::Database>,
|
||||
'q: 'e,
|
||||
E: 'q,
|
||||
{
|
||||
async move { self.connection().await?.fetch_optional(query).await }.boxed()
|
||||
}
|
||||
|
||||
@@ -162,8 +162,8 @@ impl Decode<'_> for AuthenticationSaslContinue {
|
||||
Ok(Self {
|
||||
iterations,
|
||||
salt,
|
||||
nonce: from_utf8(&*nonce).map_err(Error::protocol)?.to_owned(),
|
||||
message: from_utf8(&*buf).map_err(Error::protocol)?.to_owned(),
|
||||
nonce: from_utf8(&nonce).map_err(Error::protocol)?.to_owned(),
|
||||
message: from_utf8(&buf).map_err(Error::protocol)?.to_owned(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,7 +201,7 @@ impl PgConnectOptions {
|
||||
/// .host("localhost");
|
||||
/// ```
|
||||
pub fn host(mut self, host: &str) -> Self {
|
||||
self.host = host.to_owned();
|
||||
host.clone_into(&mut self.host);
|
||||
self
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ impl PgConnectOptions {
|
||||
/// .username("postgres");
|
||||
/// ```
|
||||
pub fn username(mut self, username: &str) -> Self {
|
||||
self.username = username.to_owned();
|
||||
username.clone_into(&mut self.username);
|
||||
self
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ impl PgConnectOptions {
|
||||
let username = url.username();
|
||||
if !username.is_empty() {
|
||||
options = options.username(
|
||||
&*percent_decode_str(username)
|
||||
&percent_decode_str(username)
|
||||
.decode_utf8()
|
||||
.map_err(Error::config)?,
|
||||
);
|
||||
@@ -32,7 +32,7 @@ impl PgConnectOptions {
|
||||
|
||||
if let Some(password) = url.password() {
|
||||
options = options.password(
|
||||
&*percent_decode_str(password)
|
||||
&percent_decode_str(password)
|
||||
.decode_utf8()
|
||||
.map_err(Error::config)?,
|
||||
);
|
||||
@@ -63,32 +63,32 @@ impl PgConnectOptions {
|
||||
}
|
||||
|
||||
"host" => {
|
||||
if value.starts_with("/") {
|
||||
if value.starts_with('/') {
|
||||
options = options.socket(&*value);
|
||||
} else {
|
||||
options = options.host(&*value);
|
||||
options = options.host(&value);
|
||||
}
|
||||
}
|
||||
|
||||
"hostaddr" => {
|
||||
value.parse::<IpAddr>().map_err(Error::config)?;
|
||||
options = options.host(&*value)
|
||||
options = options.host(&value)
|
||||
}
|
||||
|
||||
"port" => options = options.port(value.parse().map_err(Error::config)?),
|
||||
|
||||
"dbname" => options = options.database(&*value),
|
||||
"dbname" => options = options.database(&value),
|
||||
|
||||
"user" => options = options.username(&*value),
|
||||
"user" => options = options.username(&value),
|
||||
|
||||
"password" => options = options.password(&*value),
|
||||
"password" => options = options.password(&value),
|
||||
|
||||
"application_name" => options = options.application_name(&*value),
|
||||
"application_name" => options = options.application_name(&value),
|
||||
|
||||
"options" => {
|
||||
if let Some(options) = options.options.as_mut() {
|
||||
options.push(' ');
|
||||
options.push_str(&*value);
|
||||
options.push_str(&value);
|
||||
} else {
|
||||
options.options = Some(value.to_string());
|
||||
}
|
||||
@@ -112,7 +112,7 @@ impl PgConnectOptions {
|
||||
pub(crate) fn build_url(&self) -> Url {
|
||||
let host = match &self.socket {
|
||||
Some(socket) => {
|
||||
utf8_percent_encode(&*socket.to_string_lossy(), NON_ALPHANUMERIC).to_string()
|
||||
utf8_percent_encode(&socket.to_string_lossy(), NON_ALPHANUMERIC).to_string()
|
||||
}
|
||||
None => self.host.to_owned(),
|
||||
};
|
||||
@@ -124,12 +124,12 @@ impl PgConnectOptions {
|
||||
.expect("BUG: generated un-parseable URL");
|
||||
|
||||
if let Some(password) = &self.password {
|
||||
let password = utf8_percent_encode(&password, NON_ALPHANUMERIC).to_string();
|
||||
let password = utf8_percent_encode(password, NON_ALPHANUMERIC).to_string();
|
||||
let _ = url.set_password(Some(&password));
|
||||
}
|
||||
|
||||
if let Some(database) = &self.database {
|
||||
url.set_path(&database);
|
||||
url.set_path(database);
|
||||
}
|
||||
|
||||
let ssl_mode = match self.ssl_mode {
|
||||
|
||||
@@ -41,7 +41,14 @@ fn load_password_from_file(
|
||||
username: &str,
|
||||
database: Option<&str>,
|
||||
) -> Option<String> {
|
||||
let file = File::open(&path).ok()?;
|
||||
let file = File::open(&path)
|
||||
.map_err(|e| {
|
||||
tracing::warn!(
|
||||
path = %path.display(),
|
||||
"Failed to open `.pgpass` file: {e:?}",
|
||||
);
|
||||
})
|
||||
.ok()?;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
@@ -54,7 +61,7 @@ fn load_password_from_file(
|
||||
let mode = permissions.mode();
|
||||
if mode & 0o77 != 0 {
|
||||
tracing::warn!(
|
||||
path = %path.to_string_lossy(),
|
||||
path = %path.display(),
|
||||
permissions = format!("{mode:o}"),
|
||||
"Ignoring path. Permissions are not strict enough",
|
||||
);
|
||||
@@ -184,7 +191,7 @@ fn find_next_field<'a>(line: &mut &'a str) -> Option<Cow<'a, str>> {
|
||||
}
|
||||
}
|
||||
|
||||
return None;
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::str::FromStr;
|
||||
/// Options for controlling the level of protection provided for PostgreSQL SSL connections.
|
||||
///
|
||||
/// It is used by the [`ssl_mode`](super::PgConnectOptions::ssl_mode) method.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub enum PgSslMode {
|
||||
/// Only try a non-SSL connection.
|
||||
Disable,
|
||||
@@ -13,6 +13,9 @@ pub enum PgSslMode {
|
||||
Allow,
|
||||
|
||||
/// First try an SSL connection; if that fails, try a non-SSL connection.
|
||||
///
|
||||
/// This is the default if no other mode is specified.
|
||||
#[default]
|
||||
Prefer,
|
||||
|
||||
/// Only try an SSL connection. If a root CA file is present, verify the connection
|
||||
@@ -28,12 +31,6 @@ pub enum PgSslMode {
|
||||
VerifyFull,
|
||||
}
|
||||
|
||||
impl Default for PgSslMode {
|
||||
fn default() -> Self {
|
||||
PgSslMode::Prefer
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for PgSslMode {
|
||||
type Err = Error;
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ impl ColumnIndex<PgRow> for &'_ str {
|
||||
.column_names
|
||||
.get(*self)
|
||||
.ok_or_else(|| Error::ColumnNotFound((*self).into()))
|
||||
.map(|v| *v)
|
||||
.copied()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ impl ColumnIndex<PgStatement<'_>> for &'_ str {
|
||||
.column_names
|
||||
.get(*self)
|
||||
.ok_or_else(|| Error::ColumnNotFound((*self).into()))
|
||||
.map(|v| *v)
|
||||
.copied()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,10 +26,7 @@ static DO_CLEANUP: AtomicBool = AtomicBool::new(true);
|
||||
|
||||
impl TestSupport for Postgres {
|
||||
fn test_context(args: &TestArgs) -> BoxFuture<'_, Result<TestContext<Self>, Error>> {
|
||||
Box::pin(async move {
|
||||
let res = test_context(args).await;
|
||||
res
|
||||
})
|
||||
Box::pin(async move { test_context(args).await })
|
||||
}
|
||||
|
||||
fn cleanup_test(db_name: &str) -> BoxFuture<'_, Result<(), Error>> {
|
||||
@@ -44,7 +41,7 @@ impl TestSupport for Postgres {
|
||||
.await?;
|
||||
|
||||
query("delete from _sqlx_test.databases where db_name = $1")
|
||||
.bind(&db_name)
|
||||
.bind(db_name)
|
||||
.execute(&mut *conn)
|
||||
.await?;
|
||||
|
||||
@@ -157,7 +154,7 @@ async fn test_context(args: &TestArgs) -> Result<TestContext<Postgres>, Error> {
|
||||
returning db_name
|
||||
"#,
|
||||
)
|
||||
.bind(&args.test_path)
|
||||
.bind(args.test_path)
|
||||
.fetch_one(&mut *conn)
|
||||
.await?;
|
||||
|
||||
@@ -190,7 +187,7 @@ async fn do_cleanup(conn: &mut PgConnection, created_before: Duration) -> Result
|
||||
"select db_name from _sqlx_test.databases \
|
||||
where created_at < (to_timestamp($1) at time zone 'UTC')",
|
||||
)
|
||||
.bind(&created_before)
|
||||
.bind(created_before)
|
||||
.fetch_all(&mut *conn)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -561,7 +561,7 @@ impl PgType {
|
||||
PgType::Money => "MONEY",
|
||||
PgType::MoneyArray => "MONEY[]",
|
||||
PgType::Void => "VOID",
|
||||
PgType::Custom(ty) => &*ty.name,
|
||||
PgType::Custom(ty) => &ty.name,
|
||||
PgType::DeclareWithOid(_) => "?",
|
||||
PgType::DeclareWithName(name) => name,
|
||||
}
|
||||
@@ -661,7 +661,7 @@ impl PgType {
|
||||
PgType::Money => "money",
|
||||
PgType::MoneyArray => "_money",
|
||||
PgType::Void => "void",
|
||||
PgType::Custom(ty) => &*ty.name,
|
||||
PgType::Custom(ty) => &ty.name,
|
||||
PgType::DeclareWithOid(_) => "?",
|
||||
PgType::DeclareWithName(name) => name,
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ where
|
||||
T: Encode<'q, Postgres> + Type<Postgres>,
|
||||
{
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
let type_info = if self.len() < 1 {
|
||||
let type_info = if self.is_empty() {
|
||||
T::type_info()
|
||||
} else {
|
||||
self[0].produces().unwrap_or_else(T::type_info)
|
||||
|
||||
@@ -66,7 +66,7 @@ impl Decode<'_, Postgres> for BitVec {
|
||||
))?;
|
||||
}
|
||||
|
||||
let mut bitvec = BitVec::from_bytes(&bytes);
|
||||
let mut bitvec = BitVec::from_bytes(bytes);
|
||||
|
||||
// Chop off zeroes from the back. We get bits in bytes, so if
|
||||
// our bitvec is not in full bytes, extra zeroes are added to
|
||||
|
||||
@@ -24,7 +24,7 @@ impl Encode<'_, Postgres> for NaiveDate {
|
||||
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)
|
||||
Encode::<Postgres>::encode(days, buf)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> usize {
|
||||
|
||||
@@ -35,11 +35,11 @@ impl<Tz: TimeZone> PgHasArrayType for DateTime<Tz> {
|
||||
impl Encode<'_, Postgres> for NaiveDateTime {
|
||||
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())
|
||||
let micros = (*self - postgres_epoch_datetime())
|
||||
.num_microseconds()
|
||||
.ok_or_else(|| format!("NaiveDateTime out of range for Postgres: {self:?}"))?;
|
||||
|
||||
Encode::<Postgres>::encode(&us, buf)
|
||||
Encode::<Postgres>::encode(micros, buf)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> usize {
|
||||
|
||||
@@ -21,11 +21,11 @@ impl PgHasArrayType for NaiveTime {
|
||||
impl Encode<'_, Postgres> for NaiveTime {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
// TIME is encoded as the microseconds since midnight
|
||||
let us = (*self - NaiveTime::default())
|
||||
let micros = (*self - NaiveTime::default())
|
||||
.num_microseconds()
|
||||
.ok_or_else(|| format!("Time out of range for PostgreSQL: {self}"))?;
|
||||
|
||||
Encode::<Postgres>::encode(&us, buf)
|
||||
Encode::<Postgres>::encode(micros, buf)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> usize {
|
||||
|
||||
@@ -167,7 +167,7 @@ impl TryFrom<chrono::Duration> for PgInterval {
|
||||
Ok(Self {
|
||||
months: 0,
|
||||
days: 0,
|
||||
microseconds: microseconds,
|
||||
microseconds,
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
@@ -75,6 +75,9 @@ impl PgLQuery {
|
||||
}
|
||||
|
||||
/// creates lquery from an iterator with checking labels
|
||||
// TODO: this should just be removed but I didn't want to bury it in a massive diff
|
||||
#[deprecated = "renamed to `try_from_iter()`"]
|
||||
#[allow(clippy::should_implement_trait)]
|
||||
pub fn from_iter<I, S>(levels: I) -> Result<Self, PgLQueryParseError>
|
||||
where
|
||||
S: Into<String>,
|
||||
@@ -86,6 +89,26 @@ impl PgLQuery {
|
||||
}
|
||||
Ok(lquery)
|
||||
}
|
||||
|
||||
/// Create an `LQUERY` from an iterator of label strings.
|
||||
///
|
||||
/// Returns an error if any label fails to parse according to [`PgLQueryLevel::from_str()`].
|
||||
pub fn try_from_iter<I, S>(levels: I) -> Result<Self, PgLQueryParseError>
|
||||
where
|
||||
S: AsRef<str>,
|
||||
I: IntoIterator<Item = S>,
|
||||
{
|
||||
levels
|
||||
.into_iter()
|
||||
.map(|level| level.as_ref().parse::<PgLQueryLevel>())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromIterator<PgLQueryLevel> for PgLQuery {
|
||||
fn from_iter<T: IntoIterator<Item = PgLQueryLevel>>(iter: T) -> Self {
|
||||
Self::from(iter.into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for PgLQuery {
|
||||
@@ -104,7 +127,7 @@ impl FromStr for PgLQuery {
|
||||
Ok(Self {
|
||||
levels: s
|
||||
.split('.')
|
||||
.map(|s| PgLQueryLevel::from_str(s))
|
||||
.map(PgLQueryLevel::from_str)
|
||||
.collect::<Result<_, Self::Err>>()?,
|
||||
})
|
||||
}
|
||||
@@ -244,12 +267,12 @@ impl FromStr for PgLQueryLevel {
|
||||
b'!' => Ok(PgLQueryLevel::NotNonStar(
|
||||
s[1..]
|
||||
.split('|')
|
||||
.map(|s| PgLQueryVariant::from_str(s))
|
||||
.map(PgLQueryVariant::from_str)
|
||||
.collect::<Result<Vec<_>, PgLQueryParseError>>()?,
|
||||
)),
|
||||
_ => Ok(PgLQueryLevel::NonStar(
|
||||
s.split('|')
|
||||
.map(|s| PgLQueryVariant::from_str(s))
|
||||
.map(PgLQueryVariant::from_str)
|
||||
.collect::<Result<Vec<_>, PgLQueryParseError>>()?,
|
||||
)),
|
||||
}
|
||||
@@ -262,10 +285,9 @@ impl FromStr for PgLQueryVariant {
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let mut label_length = s.len();
|
||||
let mut rev_iter = s.bytes().rev();
|
||||
let mut modifiers = PgLQueryVariantFlag::empty();
|
||||
|
||||
while let Some(b) = rev_iter.next() {
|
||||
for b in s.bytes().rev() {
|
||||
match b {
|
||||
b'@' => modifiers.insert(PgLQueryVariantFlag::IN_CASE),
|
||||
b'*' => modifiers.insert(PgLQueryVariantFlag::ANY_END),
|
||||
@@ -306,8 +328,8 @@ impl Display for PgLQueryLevel {
|
||||
PgLQueryLevel::Star(Some(at_least), _) => write!(f, "*{{{at_least},}}"),
|
||||
PgLQueryLevel::Star(_, Some(at_most)) => write!(f, "*{{,{at_most}}}"),
|
||||
PgLQueryLevel::Star(_, _) => write!(f, "*"),
|
||||
PgLQueryLevel::NonStar(variants) => write_variants(f, &variants, false),
|
||||
PgLQueryLevel::NotNonStar(variants) => write_variants(f, &variants, true),
|
||||
PgLQueryLevel::NonStar(variants) => write_variants(f, variants, false),
|
||||
PgLQueryLevel::NotNonStar(variants) => write_variants(f, variants, true),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,9 +27,9 @@ pub struct PgLTreeLabel(String);
|
||||
impl PgLTreeLabel {
|
||||
pub fn new<S>(label: S) -> Result<Self, PgLTreeParseError>
|
||||
where
|
||||
String: From<S>,
|
||||
S: Into<String>,
|
||||
{
|
||||
let label = String::from(label);
|
||||
let label = label.into();
|
||||
if label.len() <= 256
|
||||
&& label
|
||||
.bytes()
|
||||
@@ -101,6 +101,9 @@ impl PgLTree {
|
||||
}
|
||||
|
||||
/// creates ltree from an iterator with checking labels
|
||||
// TODO: this should just be removed but I didn't want to bury it in a massive diff
|
||||
#[deprecated = "renamed to `try_from_iter()`"]
|
||||
#[allow(clippy::should_implement_trait)]
|
||||
pub fn from_iter<I, S>(labels: I) -> Result<Self, PgLTreeParseError>
|
||||
where
|
||||
String: From<S>,
|
||||
@@ -113,6 +116,17 @@ impl PgLTree {
|
||||
Ok(ltree)
|
||||
}
|
||||
|
||||
/// Create an `LTREE` from an iterator of label strings.
|
||||
///
|
||||
/// Returns an error if any label fails to parse according to [`PgLTreeLabel::new()`].
|
||||
pub fn try_from_iter<I, S>(labels: I) -> Result<Self, PgLTreeParseError>
|
||||
where
|
||||
S: Into<String>,
|
||||
I: IntoIterator<Item = S>,
|
||||
{
|
||||
labels.into_iter().map(PgLTreeLabel::new).collect()
|
||||
}
|
||||
|
||||
/// push a label to ltree
|
||||
pub fn push(&mut self, label: PgLTreeLabel) {
|
||||
self.labels.push(label);
|
||||
@@ -124,6 +138,14 @@ impl PgLTree {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromIterator<PgLTreeLabel> for PgLTree {
|
||||
fn from_iter<T: IntoIterator<Item = PgLTreeLabel>>(iter: T) -> Self {
|
||||
Self {
|
||||
labels: iter.into_iter().collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for PgLTree {
|
||||
type Item = PgLTreeLabel;
|
||||
type IntoIter = std::vec::IntoIter<Self::Item>;
|
||||
@@ -140,7 +162,7 @@ impl FromStr for PgLTree {
|
||||
Ok(Self {
|
||||
labels: s
|
||||
.split('.')
|
||||
.map(|s| PgLTreeLabel::new(s))
|
||||
.map(PgLTreeLabel::new)
|
||||
.collect::<Result<Vec<_>, Self::Err>>()?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -261,7 +261,7 @@ fn array_compatible<E: Type<Postgres> + ?Sized>(ty: &PgTypeInfo) -> bool {
|
||||
// we require the declared type to be an _array_ with an
|
||||
// element type that is acceptable
|
||||
if let PgTypeKind::Array(element) = &ty.kind() {
|
||||
return E::compatible(&element);
|
||||
return E::compatible(element);
|
||||
}
|
||||
|
||||
false
|
||||
|
||||
@@ -445,7 +445,7 @@ where
|
||||
}
|
||||
|
||||
count += 1;
|
||||
if !(element.is_empty() && !quoted) {
|
||||
if !element.is_empty() || quoted {
|
||||
let value = Some(T::decode(PgValueRef {
|
||||
type_info: T::type_info(),
|
||||
format: PgValueFormat::Text,
|
||||
@@ -515,7 +515,7 @@ fn range_compatible<E: Type<Postgres>>(ty: &PgTypeInfo) -> bool {
|
||||
// we require the declared type to be a _range_ with an
|
||||
// element type that is acceptable
|
||||
if let PgTypeKind::Range(element) = &ty.kind() {
|
||||
return E::compatible(&element);
|
||||
return E::compatible(element);
|
||||
}
|
||||
|
||||
false
|
||||
|
||||
@@ -103,9 +103,9 @@ impl From<&'_ Decimal> for PgNumeric {
|
||||
let groups_diff = scale % 4;
|
||||
if groups_diff > 0 {
|
||||
let remainder = 4 - groups_diff as u32;
|
||||
let power = 10u32.pow(remainder as u32) as u128;
|
||||
let power = 10u32.pow(remainder) as u128;
|
||||
|
||||
mantissa = mantissa * power;
|
||||
mantissa *= power;
|
||||
}
|
||||
|
||||
// Array to store max mantissa of Decimal in Postgres decimal format.
|
||||
@@ -121,7 +121,7 @@ impl From<&'_ Decimal> for PgNumeric {
|
||||
digits.reverse();
|
||||
|
||||
// Weight is number of digits on the left side of the decimal.
|
||||
let digits_after_decimal = (scale + 3) as u16 / 4;
|
||||
let digits_after_decimal = (scale + 3) / 4;
|
||||
let weight = digits.len() as i16 - digits_after_decimal as i16 - 1;
|
||||
|
||||
// Remove non-significant zeroes.
|
||||
|
||||
@@ -125,7 +125,7 @@ impl Encode<'_, Postgres> for String {
|
||||
|
||||
impl<'r> Decode<'r, Postgres> for &'r str {
|
||||
fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
|
||||
Ok(value.as_str()?)
|
||||
value.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ impl Encode<'_, Postgres> for Date {
|
||||
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)
|
||||
Encode::<Postgres>::encode(days, buf)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> usize {
|
||||
|
||||
@@ -37,8 +37,8 @@ impl PgHasArrayType for OffsetDateTime {
|
||||
impl Encode<'_, Postgres> for PrimitiveDateTime {
|
||||
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)
|
||||
let micros = (*self - PG_EPOCH.midnight()).whole_microseconds() as i64;
|
||||
Encode::<Postgres>::encode(micros, buf)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> usize {
|
||||
@@ -69,10 +69,10 @@ impl<'r> Decode<'r, Postgres> for PrimitiveDateTime {
|
||||
// This is given for timestamptz for some reason
|
||||
// Postgres already guarantees this to always be UTC
|
||||
if s.contains('+') {
|
||||
PrimitiveDateTime::parse(&*s, &format_description!("[year]-[month]-[day] [hour]:[minute]:[second].[subsecond][offset_hour]"))?
|
||||
PrimitiveDateTime::parse(&s, &format_description!("[year]-[month]-[day] [hour]:[minute]:[second].[subsecond][offset_hour]"))?
|
||||
} else {
|
||||
PrimitiveDateTime::parse(
|
||||
&*s,
|
||||
&s,
|
||||
&format_description!(
|
||||
"[year]-[month]-[day] [hour]:[minute]:[second].[subsecond]"
|
||||
),
|
||||
@@ -88,7 +88,7 @@ impl Encode<'_, Postgres> for OffsetDateTime {
|
||||
let utc = self.to_offset(offset!(UTC));
|
||||
let primitive = PrimitiveDateTime::new(utc.date(), utc.time());
|
||||
|
||||
Encode::<Postgres>::encode(&primitive, buf)
|
||||
Encode::<Postgres>::encode(primitive, buf)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> usize {
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
mod date;
|
||||
mod datetime;
|
||||
|
||||
// Parent module is named after the `time` crate, this module is named after the `TIME` SQL type.
|
||||
#[allow(clippy::module_inception)]
|
||||
mod time;
|
||||
|
||||
#[rustfmt::skip]
|
||||
|
||||
@@ -22,8 +22,8 @@ impl PgHasArrayType for Time {
|
||||
impl Encode<'_, Postgres> for Time {
|
||||
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)
|
||||
let micros = (*self - Time::MIDNIGHT).whole_microseconds() as i64;
|
||||
Encode::<Postgres>::encode(micros, buf)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> usize {
|
||||
|
||||
@@ -88,38 +88,36 @@ mod chrono {
|
||||
Ok(PgTimeTz { time, offset })
|
||||
}
|
||||
|
||||
PgValueFormat::Text => {
|
||||
let s = value.as_str()?;
|
||||
PgValueFormat::Text => try_parse_timetz(value.as_str()?),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut tmp = String::with_capacity(11 + s.len());
|
||||
tmp.push_str("2001-07-08 ");
|
||||
tmp.push_str(s);
|
||||
fn try_parse_timetz(s: &str) -> Result<PgTimeTz<NaiveTime, FixedOffset>, BoxDynError> {
|
||||
let mut tmp = String::with_capacity(11 + s.len());
|
||||
tmp.push_str("2001-07-08 ");
|
||||
tmp.push_str(s);
|
||||
|
||||
let dt = 'out: loop {
|
||||
let mut err = None;
|
||||
|
||||
for fmt in &["%Y-%m-%d %H:%M:%S%.f%#z", "%Y-%m-%d %H:%M:%S%.f"] {
|
||||
match DateTime::parse_from_str(&tmp, fmt) {
|
||||
Ok(dt) => {
|
||||
break 'out dt;
|
||||
}
|
||||
|
||||
Err(error) => {
|
||||
err = Some(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Err(err.unwrap().into());
|
||||
};
|
||||
let mut err = None;
|
||||
|
||||
for fmt in &["%Y-%m-%d %H:%M:%S%.f%#z", "%Y-%m-%d %H:%M:%S%.f"] {
|
||||
match DateTime::parse_from_str(&tmp, fmt) {
|
||||
Ok(dt) => {
|
||||
let time = dt.time();
|
||||
let offset = *dt.offset();
|
||||
|
||||
Ok(PgTimeTz { time, offset })
|
||||
return Ok(PgTimeTz { time, offset });
|
||||
}
|
||||
|
||||
Err(error) => {
|
||||
err = Some(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(err
|
||||
.expect("BUG: loop should have set `err` to `Some()` before exiting")
|
||||
.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user