我正在使用社会 3.2.2。我正在寻找一种方法来提供多个占位符和相应的值。
std::vector<std::string> vs;
vs.push_back("key1");
vs.push_back("key2");
sql << "select * from mytable as t where t.field1 = :f1 and t.field2 = :f2", use(vs[0]), use(vs[1]);
假设我的表有很多列。例如 field1, field2, ... 占位符 :f1 和 :f2 对应于 filed1 和 field2。占位符的数量动态变化。所以我创建了动态包含占位符的查询字符串。这是一个简单的字符串操作。到现在为止还挺好。但是,我找不到提供与占位符相对应的多个值的方法。use(vs[0]), use(vs[1]), ... 不是字符串而是 C++ 代码。所以我不能在运行时生成它。
我找到了解决它的方法,但它并不优雅。方法是放弃使用函数 use() 并直接使用字符串操作插入实际值,例如“key1”。这不安全。我需要实施以避免 SQL 注入。它是通过 use() 函数实现的。
我正在寻找更好的方法。
更新
解决方案1 使用Core接口
感谢以下评论: https ://github.com/SOCI/soci/issues/354#issuecomment-115658512 https://github.com/SOCI/soci/issues/354#issuecomment-115662758
该问题已使用“核心”界面解决。
http://soci.sourceforge.net/doc/3.2/interfaces.html
这是使用“核心”接口的代码:
session sql(sqlite3, "./test");
std::vector<std::string> qs { "v1", "v2", "v3" }; // determined on run time
int count;
// Create query string dynamically
std::stringstream ss;
ss << "select count(*) from mytable as t where t.field1 = :f1";
for (std::size_t i = 1; i < qs.size(); ++i) {
ss << " and t.field" << i+1 << " = :f" << i+1;
}
// Give the values corresponding to the placeholders in the query string
statement st(sql);
for (auto const& e : qs) {
st.exchange(use(e));
}
st.exchange(into(count));
st.alloc();
st.prepare(ss.str());
st.define_and_bind();
st.execute(true);
std::cout << count << std::endl;
解决方案2 定义自定义映射
std::vector 由 soci 库保留。我需要定义不同的类型。MyVectorOfStrings 就是这样。然后使用 type_conversion 类模板特化定义自定义转换。
#include <soci.h>
#include <sqlite3/soci-sqlite3.h>
#include <iostream>
using namespace soci;
struct MyVectorOfStrings : public std::vector<std::string> {
using std::vector<std::string>::vector;
};
namespace soci
{
template<>
struct type_conversion<MyVectorOfStrings>
{
typedef values base_type;
static void from_base(values const& v, indicator /* ind */, MyVectorOfStrings &p)
{}
static void to_base(const MyVectorOfStrings& p, values& v, indicator& ind) {
for (auto s : p) v << s;
ind = i_ok;
}
};
}
int main()
{
try {
session sql(sqlite3, "./test");
MyVectorOfStrings qs { "v1", "v2", "v3" }; // determined on run time
int count;
sql << "select count(*) from mytable as t where t.field1 = :f1 and t.field2 = :f2 and t.field3 = :f3", use(qs), into(count);
std::cout << count << std::endl;
}
catch (std::exception const &e) {
std::cerr << "Error: " << e.what() << '\n';
}
}