You need to enable JavaScript to run this app. 如何在Rust的sqlx库query!宏中动态插入列名实现动态排序
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rust的sqlx库query!宏中动态插入列名实现动态排序

问题根因

你当前的写法不生效是因为PostgreSQL的预编译参数绑定(即$1这类占位符)仅支持传入查询值,无法用于传入表名、列名这类SQL标识符,你传入的metric会被视为普通字符串常量,最终查询相当于按固定字符串排序,自然不会生效。

方案1:匹配固定列(推荐,安全性最高)

如果允许排序的列数量不多,直接用match匹配不同列,调用写死的SQL语句,可以保留SQLx编译时SQL校验的能力,完全规避SQL注入风险:

pub async fn fetch_tweets_by_metric(
    pool: &PgPool,
    metric: &str,
) -> Result<Vec<Tweet>, sqlx::error::Error> {
    let tweets = match metric {
        // 这里列出所有允许排序的列,对应写死ORDER BY的列名
        "likes" => sqlx::query_as!(
            Tweet,
            r#"SELECT * FROM tweets ORDER BY likes DESC"#
        )
        .fetch_all(pool)
        .await?,
        "retweet_count" => sqlx::query_as!(
            Tweet,
            r#"SELECT * FROM tweets ORDER BY retweet_count DESC"#
        )
        .fetch_all(pool)
        .await?,
        "created_at" => sqlx::query_as!(
            Tweet,
            r#"SELECT * FROM tweets ORDER BY created_at DESC"#
        )
        .fetch_all(pool)
        .await?,
        // 非法列名直接返回错误,也可以替换为自定义的非法参数错误
        _ => return Err(sqlx::error::Error::RowNotFound),
    };
    Ok(tweets)
}

方案2:动态拼接SQL加白名单校验(灵活)

如果允许排序的列较多,不想写冗余的匹配分支,可以先对传入的metric做白名单校验,确认是合法列名后再动态拼接SQL,注意此时要使用不带!的普通query_as方法(带!的宏是编译时校验,不支持动态SQL):

pub async fn fetch_tweets_by_metric(
    pool: &PgPool,
    metric: &str,
) -> Result<Vec<Tweet>, sqlx::error::Error> {
    // 白名单:所有允许排序的列名,根据实际业务调整
    const ALLOWED_SORT_COLUMNS: &[&str] = &["likes", "retweet_count", "created_at", "view_count"];
    if !ALLOWED_SORT_COLUMNS.contains(&metric) {
        return Err(sqlx::error::Error::RowNotFound);
    }

    // 校验通过后拼接SQL
    let query_sql = format!(
        r#"SELECT * FROM tweets ORDER BY {} DESC"#,
        metric
    );

    let tweets = sqlx::query_as::<_, Tweet>(&query_sql)
        .fetch_all(pool)
        .await?;

    Ok(tweets)
}

注意:绝对不能跳过白名单校验直接拼接用户输入的内容到SQL语句中,否则会存在严重的SQL注入漏洞,导致数据泄露或损坏。

内容的提问来源于stack exchange,提问作者ilmoi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.18 01:36:01