diff --git a/sqlx-core/src/postgres/protocol/type_id.rs b/sqlx-core/src/postgres/protocol/type_id.rs index 4c14ed98..5622e5fc 100644 --- a/sqlx-core/src/postgres/protocol/type_id.rs +++ b/sqlx-core/src/postgres/protocol/type_id.rs @@ -23,6 +23,8 @@ impl TypeId { pub(crate) const NUMERIC: TypeId = TypeId(1700); pub(crate) const TEXT: TypeId = TypeId(25); + pub(crate) const VARCHAR: TypeId = TypeId(1043); + pub(crate) const BPCHAR: TypeId = TypeId(1042); pub(crate) const DATE: TypeId = TypeId(1082); pub(crate) const TIME: TypeId = TypeId(1083); @@ -48,6 +50,8 @@ impl TypeId { pub(crate) const ARRAY_FLOAT8: TypeId = TypeId(1022); pub(crate) const ARRAY_TEXT: TypeId = TypeId(1009); + pub(crate) const ARRAY_VARCHAR: TypeId = TypeId(1015); + pub(crate) const ARRAY_BPCHAR: TypeId = TypeId(1014); pub(crate) const ARRAY_NUMERIC: TypeId = TypeId(1700); diff --git a/sqlx-core/src/postgres/types/mod.rs b/sqlx-core/src/postgres/types/mod.rs index ae520249..a04a07d8 100644 --- a/sqlx-core/src/postgres/types/mod.rs +++ b/sqlx-core/src/postgres/types/mod.rs @@ -247,6 +247,28 @@ impl TypeInfo for PgTypeInfo { | (TypeId::ARRAY_CIDR, TypeId::ARRAY_INET) | (TypeId::ARRAY_INET, TypeId::ARRAY_CIDR) => true, + // text, varchar, and bpchar are compatible + (TypeId::VARCHAR, other) | (TypeId::TEXT, other) | (TypeId::BPCHAR, other) + if match other { + TypeId::VARCHAR | TypeId::TEXT | TypeId::BPCHAR => true, + _ => false, + } => + { + true + } + + // text[], varchar[], and bpchar[] are compatible + (TypeId::ARRAY_VARCHAR, other) + | (TypeId::ARRAY_TEXT, other) + | (TypeId::ARRAY_BPCHAR, other) + if match other { + TypeId::ARRAY_VARCHAR | TypeId::ARRAY_TEXT | TypeId::ARRAY_BPCHAR => true, + _ => false, + } => + { + true + } + _ => { // TODO: 99% of postgres types are direct equality for [compatible]; when we add something that isn't (e.g, JSON/JSONB), fix this here self.id.0 == other.id.0 diff --git a/tests/postgres-macros.rs b/tests/postgres-macros.rs index adf71b96..c23efc21 100644 --- a/tests/postgres-macros.rs +++ b/tests/postgres-macros.rs @@ -29,6 +29,38 @@ async fn test_no_result() -> anyhow::Result<()> { Ok(()) } +#[cfg_attr(feature = "runtime-async-std", async_std::test)] +#[cfg_attr(feature = "runtime-tokio", tokio::test)] +async fn test_text_var_char_char_n() -> anyhow::Result<()> { + let mut conn = connect().await?; + + // TEXT + + let rec = sqlx::query!("SELECT 'Hello'::text as greeting") + .fetch_one(&mut conn) + .await?; + + assert_eq!(rec.greeting, "Hello"); + + // VARCHAR(N) + + let rec = sqlx::query!("SELECT 'Hello'::varchar(5) as greeting") + .fetch_one(&mut conn) + .await?; + + assert_eq!(rec.greeting, "Hello"); + + // CHAR(N) + + let rec = sqlx::query!("SELECT 'Hello'::char(5) as greeting") + .fetch_one(&mut conn) + .await?; + + assert_eq!(rec.greeting, "Hello"); + + Ok(()) +} + #[cfg_attr(feature = "runtime-async-std", async_std::test)] #[cfg_attr(feature = "runtime-tokio", tokio::test)] async fn _file() -> anyhow::Result<()> {