Closed hwc0919 closed 3 years ago
I did something like this and it worked!!
// Sync and blocking method
const Result execSqlSync1(const std::string &sql,
const char * const * pcszArguments, int i32Args) noexcept(false)
{
Result r(nullptr);
{
auto binder = *this << sql;
// (void)std::initializer_list<int>{
// (binder << std::forward<Arguments>(args), 0)...};
for (int i = 0; i < i32Args; ++i)
{
LOG_DEBUG << "binder input " << pcszArguments[i] << '\n';
binder << std::string(pcszArguments[i]);
}
// Use blocking mode
binder << Mode::Blocking;
binder >> [&r](const Result &result) { r = result; };
binder.exec(); // exec may be throw exception;
}
return r;
}
But I still don't know how to deal with different data types. Only find overload operator<< for strings.
I did something like this and it worked!!
// Sync and blocking method const Result execSqlSync1(const std::string &sql, const char * const * pcszArguments, int i32Args) noexcept(false) { Result r(nullptr); { auto binder = *this << sql; // (void)std::initializer_list<int>{ // (binder << std::forward<Arguments>(args), 0)...}; for (int i = 0; i < i32Args; ++i) { LOG_DEBUG << "binder input " << pcszArguments[i] << '\n'; binder << std::string(pcszArguments[i]); } // Use blocking mode binder << Mode::Blocking; binder >> [&r](const Result &result) { r = result; }; binder.exec(); // exec may be throw exception; } return r; }
But I still don't know how to deal with different data types. Only find overload operator<< for strings.
operator << can accept multiple type of parameters. and when you use blocking mode of the binder, it may throw exceptions when executing SQL.
Thank you for your reply!
By 'dealing with different data types', I mean something like pg bigint, int, int[], datetime or other user-defined types. We know that PQexecParams
requires an oid array as parameter , I'm looking for something similar in drogon.
BTW, this is a wonderful framework, I'm looking forward to rebuilding my server upon it.
Please refer the SqlBinder class; BTW, you don't need to change the DbClient source code, just create a binder with DbClient object. like this:
try{
auto binder = (*dbClientPtr) << sql;
for (int i = 0; i < i32Args; ++i)
{
LOG_DEBUG << "binder input " << pcszArguments[i] << '\n';
binder << std::string(pcszArguments[i]);
}
// Use blocking mode
binder << Mode::Blocking;
binder >> [&r](const Result &result) { r = result; };
binder.exec(); // exec may be throw exception;
}
catch (const std::exception &err)
{
...}
想用二进制格式传输数组,看了一下源码似乎并不支持。如果想传入数组参数,只能以 literal 的方式传入 ?
pg的数组比较麻烦,还支持嵌套,目前没有原生支持,你要写成'{...}'字符串的形式。
希望可以支持用户传入oid数组,然后用户可以选择自己把数据序列化成 byte array 传给 sqlBinder.
现在的oid数组是直接传了null.
考虑一下怎么搞。。。
我重写了一个 PgClient,基本照抄只保留基本功能(因为想只依赖trantor, 所以没有选择继承),但是参数和结果都用二进制方式 ( paramTypes 自定义, resultFormat = 1 ),请求和结果接入了自己用的序列化库,已经可以正常工作了,基本满足了我的需求。我觉得如果你打算支持二进制的话,可以新增一套接口,比如 execBinSql(std::shared_ptr<SqlBinCmd>)
,把SqlBinCmd
暴露给用户, 用户自己填写请求.
我一开始也是用二进制格式的,但是好像数组类型的字段没调通,就放弃了,二进制属于底层运作方式,可以不用暴露在接口上。
When using
libpq
, we can callPQexecParams
with arbitrary number of arguments. How can we achieve this indrogon
?DbClient
的接口为函数模板,似乎只能在编译时就确定参数个数? 目前正在考虑从别的框架转向drogon
, 我的使用场景是这样的: 在 app 启动时从数据库获取pg函数的元数据,做字符串拼接,根据请求数据匹配相应的函数。请求的解析通过加载新的动态库更新,pg函数可以直接在数据库更新,这样无需重新编译 server 就能适用新的业务逻辑。所以在运行时才能确定参数个数。不知道有没有办法实现?