You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用fmt库编译期格式字符串构建防注入的类型安全SQL查询构造器

基于fmtlib的安全SQL查询构造器实现

核心思路

通过参数类型重载实现不同类型的SQL自动转义,直接复用fmt库原生的编译期格式校验能力,无需依赖废弃接口,同时完全保留原生fmt的易用性和类型安全性,从根源避免SQL注入风险。

代码实现

1. 类型化SQL转义函数

针对不同SQL参数类型实现对应的转义逻辑,可按需扩展:

#include <fmt/core.h>
#include <string>
#include <string_view>
#include <type_traits>

// 数值类型无需转义直接返回
template<std::integral T>
T sql_escape(T value) {
    return value;
}

template<std::floating_point T>
T sql_escape(T value) {
    return value;
}

// 布尔值转SQL合法字面量
int sql_escape(bool value) {
    return value ? 1 : 0;
}

// 字符串类型转义单引号,可按需扩展转义其他特殊字符
std::string sql_escape(std::string_view str) {
    std::string res;
    res.reserve(str.size() + 4);
    // 可选:自动包裹单引号,后续格式字符串无需手动加''
    // res += '\'';
    for (char c : str) {
        if (c == '\'') {
            res += "''";
        } else {
            res += c;
        }
    }
    // res += '\'';
    return res;
}

2. 核心查询构造函数

完全保留fmt的编译期格式校验能力:

template <typename... Args>
std::string query(fmt::format_string<decltype(sql_escape(std::declval<Args>()))...> format_str, Args&&... args) {
    return fmt::format(format_str, sql_escape(std::forward<Args>(args))...);
}

3. 使用示例

// 调用语法和原生fmt完全一致
std::string sql = query("SELECT * FROM user WHERE id = {} AND username = '{}'", 123, "O'Neil");
// 生成的SQL为:SELECT * FROM user WHERE id = 123 AND username = 'O''Neil'

注意事项

  • 若启用字符串转义自动包裹单引号,格式字符串中字符串占位符无需手动加'{}',直接写{}即可,进一步减少手写错误
  • 可按需新增sql_escape重载支持NULL、二进制、日期时间等更多SQL类型,无需修改核心query函数逻辑
  • fmt版本低于8.0时,仅需将fmt::format_string替换为对应版本的编译期格式校验接口即可,整体逻辑无需调整

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 06:24:02