mirror of
https://github.com/launchbadge/sqlx.git
synced 2025-10-03 07:45:30 +00:00
fix: tests in sqlx-postgres
This commit is contained in:
parent
b4e7a2fe7d
commit
9ec09fb789
@ -17,6 +17,8 @@
|
|||||||
#![allow(clippy::needless_doctest_main, clippy::type_complexity)]
|
#![allow(clippy::needless_doctest_main, clippy::type_complexity)]
|
||||||
// See `clippy.toml` at the workspace root
|
// See `clippy.toml` at the workspace root
|
||||||
#![deny(clippy::disallowed_methods)]
|
#![deny(clippy::disallowed_methods)]
|
||||||
|
#![deny(clippy::cast_possible_truncation)]
|
||||||
|
#![deny(clippy::cast_possible_wrap)]
|
||||||
// The only unsafe code in SQLx is that necessary to interact with native APIs like with SQLite,
|
// The only unsafe code in SQLx is that necessary to interact with native APIs like with SQLite,
|
||||||
// and that can live in its own separate driver crate.
|
// and that can live in its own separate driver crate.
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
|
@ -15,9 +15,15 @@ json = ["sqlx-core/json"]
|
|||||||
migrate = ["sqlx-core/migrate"]
|
migrate = ["sqlx-core/migrate"]
|
||||||
offline = ["sqlx-core/offline"]
|
offline = ["sqlx-core/offline"]
|
||||||
|
|
||||||
# Type integration features which require additional dependencies
|
# Type Integration features
|
||||||
rust_decimal = ["dep:rust_decimal", "rust_decimal/maths"]
|
bigdecimal = ["dep:bigdecimal", "dep:num-bigint", "sqlx-core/bigdecimal"]
|
||||||
bigdecimal = ["dep:bigdecimal", "dep:num-bigint"]
|
bit-vec = ["dep:bit-vec", "sqlx-core/bit-vec"]
|
||||||
|
chrono = ["dep:chrono", "sqlx-core/chrono"]
|
||||||
|
ipnetwork = ["dep:ipnetwork", "sqlx-core/ipnetwork"]
|
||||||
|
mac_address = ["dep:mac_address", "sqlx-core/mac_address"]
|
||||||
|
rust_decimal = ["dep:rust_decimal", "rust_decimal/maths", "sqlx-core/rust_decimal"]
|
||||||
|
time = ["dep:time", "sqlx-core/time"]
|
||||||
|
uuid = ["dep:uuid", "sqlx-core/uuid"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Futures crates
|
# Futures crates
|
||||||
@ -71,8 +77,9 @@ workspace = true
|
|||||||
# We use JSON in the driver implementation itself so there's no reason not to enable it here.
|
# We use JSON in the driver implementation itself so there's no reason not to enable it here.
|
||||||
features = ["json"]
|
features = ["json"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies.sqlx]
|
||||||
sqlx.workspace = true
|
workspace = true
|
||||||
|
features = ["postgres", "derive"]
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
etcetera = "0.8.0"
|
etcetera = "0.8.0"
|
||||||
|
@ -98,7 +98,6 @@ impl PgAdvisoryLock {
|
|||||||
/// [hkdf]: https://datatracker.ietf.org/doc/html/rfc5869
|
/// [hkdf]: https://datatracker.ietf.org/doc/html/rfc5869
|
||||||
/// ### Example
|
/// ### Example
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # extern crate sqlx_core as sqlx;
|
|
||||||
/// use sqlx::postgres::{PgAdvisoryLock, PgAdvisoryLockKey};
|
/// use sqlx::postgres::{PgAdvisoryLock, PgAdvisoryLockKey};
|
||||||
///
|
///
|
||||||
/// let lock = PgAdvisoryLock::new("my first Postgres advisory lock!");
|
/// let lock = PgAdvisoryLock::new("my first Postgres advisory lock!");
|
||||||
|
@ -2,17 +2,17 @@ use crate::error::Error;
|
|||||||
use crate::ext::ustr::UStr;
|
use crate::ext::ustr::UStr;
|
||||||
use crate::message::{ParameterDescription, RowDescription};
|
use crate::message::{ParameterDescription, RowDescription};
|
||||||
use crate::query_as::query_as;
|
use crate::query_as::query_as;
|
||||||
use crate::query_scalar::{query_scalar, query_scalar_with};
|
use crate::query_scalar::{query_scalar};
|
||||||
use crate::statement::PgStatementMetadata;
|
use crate::statement::PgStatementMetadata;
|
||||||
use crate::type_info::{PgArrayOf, PgCustomType, PgType, PgTypeKind};
|
use crate::type_info::{PgArrayOf, PgCustomType, PgType, PgTypeKind};
|
||||||
use crate::types::Json;
|
use crate::types::Json;
|
||||||
use crate::types::Oid;
|
use crate::types::Oid;
|
||||||
use crate::HashMap;
|
use crate::HashMap;
|
||||||
use crate::{PgArguments, PgColumn, PgConnection, PgTypeInfo};
|
use crate::{PgColumn, PgConnection, PgTypeInfo};
|
||||||
use futures_core::future::BoxFuture;
|
use futures_core::future::BoxFuture;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::fmt::Write;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use sqlx_core::query_builder::QueryBuilder;
|
||||||
|
|
||||||
/// Describes the type of the `pg_type.typtype` column
|
/// Describes the type of the `pg_type.typtype` column
|
||||||
///
|
///
|
||||||
@ -423,29 +423,34 @@ WHERE rngtypid = $1
|
|||||||
return Ok(vec![]);
|
return Ok(vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut nullable_query = String::from("SELECT NOT pg_attribute.attnotnull FROM (VALUES ");
|
if meta.columns.len() * 3 > 65535 {
|
||||||
let mut args = PgArguments::default();
|
tracing::debug!(
|
||||||
|
?stmt_id,
|
||||||
for (i, (column, bind)) in meta.columns.iter().zip((1..).step_by(3)).enumerate() {
|
num_columns=meta.columns.len(),
|
||||||
if !args.buffer.is_empty() {
|
"number of columns in query is too large to pull nullability for"
|
||||||
nullable_query += ", ";
|
|
||||||
}
|
|
||||||
|
|
||||||
let _ = write!(
|
|
||||||
nullable_query,
|
|
||||||
"(${}::int4, ${}::int4, ${}::int2)",
|
|
||||||
bind,
|
|
||||||
bind + 1,
|
|
||||||
bind + 2
|
|
||||||
);
|
);
|
||||||
|
|
||||||
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(
|
// Query for NOT NULL constraints for each column in the query.
|
||||||
|
//
|
||||||
|
// This will include columns that don't have a `relation_id` (are not from a table);
|
||||||
|
// assuming those are a minority of columns, it's less code to _not_ work around it
|
||||||
|
// and just let Postgres return `NULL`.
|
||||||
|
let mut nullable_query = QueryBuilder::new(
|
||||||
|
"SELECT NOT pg_attribute.attnotnull FROM ( "
|
||||||
|
);
|
||||||
|
|
||||||
|
nullable_query.push_values(
|
||||||
|
meta.columns.iter().zip(0i32..),
|
||||||
|
|mut tuple, (column, i)| {
|
||||||
|
// ({i}::int4, {column.relation_id}::int4, {column.relation_attribute_no}::int2)
|
||||||
|
tuple.push_bind(i).push_unseparated("::int4");
|
||||||
|
tuple.push_bind(column.relation_id).push_unseparated("::int4");
|
||||||
|
tuple.push_bind(column.relation_attribute_no).push_bind_unseparated("::int2");
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
nullable_query.push(
|
||||||
") as col(idx, table_id, col_idx) \
|
") as col(idx, table_id, col_idx) \
|
||||||
LEFT JOIN pg_catalog.pg_attribute \
|
LEFT JOIN pg_catalog.pg_attribute \
|
||||||
ON table_id IS NOT NULL \
|
ON table_id IS NOT NULL \
|
||||||
@ -454,7 +459,8 @@ WHERE rngtypid = $1
|
|||||||
ORDER BY col.idx",
|
ORDER BY col.idx",
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut nullables = query_scalar_with::<_, Option<bool>, _>(&nullable_query, args)
|
let mut nullables: Vec<Option<bool>> = nullable_query
|
||||||
|
.build_query_scalar()
|
||||||
.fetch_all(&mut *self)
|
.fetch_all(&mut *self)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
//! **PostgreSQL** database driver.
|
//! **PostgreSQL** database driver.
|
||||||
|
#![deny(clippy::cast_possible_truncation)]
|
||||||
|
#![deny(clippy::cast_possible_wrap)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate sqlx_core;
|
extern crate sqlx_core;
|
||||||
|
@ -188,19 +188,17 @@ impl PgListener {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use sqlx_core::postgres::PgListener;
|
/// # use sqlx::postgres::PgListener;
|
||||||
/// # use sqlx_core::error::Error;
|
|
||||||
/// #
|
/// #
|
||||||
/// # #[cfg(feature = "_rt")]
|
|
||||||
/// # sqlx::__rt::test_block_on(async move {
|
/// # sqlx::__rt::test_block_on(async move {
|
||||||
/// # let mut listener = PgListener::connect("postgres:// ...").await?;
|
/// let mut listener = PgListener::connect("postgres:// ...").await?;
|
||||||
/// loop {
|
/// loop {
|
||||||
/// // ask for next notification, re-connecting (transparently) if needed
|
/// // ask for next notification, re-connecting (transparently) if needed
|
||||||
/// let notification = listener.recv().await?;
|
/// let notification = listener.recv().await?;
|
||||||
///
|
///
|
||||||
/// // handle notification, do something interesting
|
/// // handle notification, do something interesting
|
||||||
/// }
|
/// }
|
||||||
/// # Result::<(), Error>::Ok(())
|
/// # Result::<(), sqlx::Error>::Ok(())
|
||||||
/// # }).unwrap();
|
/// # }).unwrap();
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn recv(&mut self) -> Result<PgNotification, Error> {
|
pub async fn recv(&mut self) -> Result<PgNotification, Error> {
|
||||||
@ -219,10 +217,8 @@ impl PgListener {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use sqlx_core::postgres::PgListener;
|
/// # use sqlx::postgres::PgListener;
|
||||||
/// # use sqlx_core::error::Error;
|
|
||||||
/// #
|
/// #
|
||||||
/// # #[cfg(feature = "_rt")]
|
|
||||||
/// # sqlx::__rt::test_block_on(async move {
|
/// # sqlx::__rt::test_block_on(async move {
|
||||||
/// # let mut listener = PgListener::connect("postgres:// ...").await?;
|
/// # let mut listener = PgListener::connect("postgres:// ...").await?;
|
||||||
/// loop {
|
/// loop {
|
||||||
@ -233,7 +229,7 @@ impl PgListener {
|
|||||||
///
|
///
|
||||||
/// // connection lost, do something interesting
|
/// // connection lost, do something interesting
|
||||||
/// }
|
/// }
|
||||||
/// # Result::<(), Error>::Ok(())
|
/// # Result::<(), sqlx::Error>::Ok(())
|
||||||
/// # }).unwrap();
|
/// # }).unwrap();
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn try_recv(&mut self) -> Result<Option<PgNotification>, Error> {
|
pub async fn try_recv(&mut self) -> Result<Option<PgNotification>, Error> {
|
||||||
|
@ -230,6 +230,7 @@ CREATE TABLE IF NOT EXISTS _sqlx_migrations (
|
|||||||
let elapsed = start.elapsed();
|
let elapsed = start.elapsed();
|
||||||
|
|
||||||
// language=SQL
|
// language=SQL
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
let _ = query(
|
let _ = query(
|
||||||
r#"
|
r#"
|
||||||
UPDATE _sqlx_migrations
|
UPDATE _sqlx_migrations
|
||||||
|
@ -82,7 +82,8 @@ mod ssl_mode;
|
|||||||
/// // Information about SQL queries is logged at `DEBUG` level by default.
|
/// // Information about SQL queries is logged at `DEBUG` level by default.
|
||||||
/// opts = opts.log_statements(log::LevelFilter::Trace);
|
/// opts = opts.log_statements(log::LevelFilter::Trace);
|
||||||
///
|
///
|
||||||
/// let pool = PgPool::connect_with(&opts).await?;
|
/// let pool = PgPool::connect_with(opts).await?;
|
||||||
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -294,7 +294,7 @@ impl PgTypeInfo {
|
|||||||
/// in quotes, e.g.:
|
/// in quotes, e.g.:
|
||||||
/// ```
|
/// ```
|
||||||
/// use sqlx::postgres::PgTypeInfo;
|
/// use sqlx::postgres::PgTypeInfo;
|
||||||
/// use sqlx::Type;
|
/// use sqlx::{Type, TypeInfo};
|
||||||
///
|
///
|
||||||
/// /// `CREATE TYPE "_foo" AS ENUM ('Bar', 'Baz');`
|
/// /// `CREATE TYPE "_foo" AS ENUM ('Bar', 'Baz');`
|
||||||
/// #[derive(sqlx::Type)]
|
/// #[derive(sqlx::Type)]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user