使用Sqlx query_as查询PostgreSQL时类型不匹配问题求助
问题解决:Sqlx query_as函数动态查询类型不匹配,query_as!宏正常
错误原因
query_as!宏是编译时展开的,会根据结构体字段和查询语句自动生成适配的类型解码逻辑,能正确识别UuidWrapper与PostgreSQL bpchar(36)的映射关系。而直接调用query_as函数时,Sqlx需要自定义类型手动实现Decode<Postgres>和Type<Postgres> trait,否则会触发默认解码逻辑,导致类型不匹配错误。
另外你的FromRow实现未被调用,是因为Sqlx在尝试逐个解码字段时就已失败,未走到调用FromRow的流程。
解决方案
1. 为UuidWrapper实现必要的Sqlx trait
需要让Sqlx知道如何将数据库的bpchar(36)类型转换为UuidWrapper,实现Decode、Type(如需写入数据库还需实现Encode):
use sqlx::{postgres::PgTypeInfo, Decode, Encode, Postgres, Type}; use uuid::Uuid; #[derive(PartialEq, Debug, Clone)] pub struct UuidWrapper(pub(crate) Uuid); // 实现解码:将bpchar(36)字符串转为Uuid impl<'r> Decode<'r, Postgres> for UuidWrapper { fn decode(value: sqlx::postgres::PgValueRef<'r>) -> Result<Self, sqlx::Error> { let uuid_str: &str = Decode::decode(value)?; let uuid = Uuid::parse_str(uuid_str) .map_err(|e| sqlx::Error::Decode(e.into()))?; Ok(UuidWrapper(uuid)) } fn decode_nullable(value: sqlx::postgres::PgValueRef<'r>) -> Result<Option<Self>, sqlx::Error> { value.is_null().then_some(None).unwrap_or_else(|| Ok(Some(Self::decode(value)?))) } } // 声明对应的SQL类型 impl Type<Postgres> for UuidWrapper { fn type_info() -> PgTypeInfo { // 对应PostgreSQL的character(bpchar)类型 PgTypeInfo::with_name("character") } fn compatible(ty: &PgTypeInfo) -> bool { // 兼容char和character两种类型名 ty.name() == "char" || ty.name() == "character" } } // 如需向数据库写入数据,实现Encode impl Encode<'_, Postgres> for UuidWrapper { fn encode_by_ref(&self, buf: &mut sqlx::postgres::PgArgumentBuffer) -> Result<(), sqlx::Error> { let uuid_str = self.0.to_string(); Encode::encode(uuid_str, buf) } }
2. 优先使用参数化查询替代字符串拼接
动态拼接SQL存在SQL注入风险,建议使用参数化查询,同时保留query_as!宏的编译时检查优势:
async fn select_where( pool: &Pool<Postgres>, owner_id: &Uuid, create_date: &chrono::NaiveDate ) -> Vec<Self> where Self: Sized, { query_as!( Post, "SELECT * FROM posts WHERE owner_id = $1 AND CAST(create_time AS DATE) = $2", owner_id, create_date ) .fetch_all(pool) .await .unwrap() }
3. 确认动态查询语句的正确性
如果必须使用动态SQL,确保拼接后的语句与query_as!中硬编码的语句完全一致,避免列缺失或语法错误导致的解码异常。
内容的提问来源于stack exchange,提问作者radu781
相关产品推荐
相关产品推荐

