Add default value interface to sqlbinder for mysql and postgresql (#704)

This commit is contained in:
interfector18 2021-02-07 03:34:49 +01:00 committed by GitHub
parent 4c577e6fa9
commit 6542236b20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 141 additions and 38 deletions

View File

@ -420,6 +420,7 @@ set(ORM_HEADERS
orm_lib/inc/drogon/orm/ArrayParser.h
orm_lib/inc/drogon/orm/Criteria.h
orm_lib/inc/drogon/orm/DbClient.h
orm_lib/inc/drogon/orm/DbTypes.h
orm_lib/inc/drogon/orm/Exception.h
orm_lib/inc/drogon/orm/Field.h
orm_lib/inc/drogon/orm/FunctionTraits.h

View File

@ -147,5 +147,12 @@ std::string formattedString(const char *format, ...);
*/
int createPath(const std::string &path);
/// Replace all occurances of from to to inplace
/**
* @param from string to replace
* @param to string to replace with
*/
void replaceAll(std::string &s, const std::string &from, const std::string &to);
} // namespace utils
} // namespace drogon

View File

@ -1163,5 +1163,15 @@ std::string getMd5(const char *data, const size_t dataLen)
#endif
}
void replaceAll(std::string &s, const std::string &from, const std::string &to)
{
size_t pos = 0;
while ((pos = s.find(from, pos)) != std::string::npos)
{
s.replace(pos, from.size(), to);
pos += to.size();
}
}
} // namespace utils
} // namespace drogon

View File

@ -0,0 +1,40 @@
/**
*
* @file DbTypes.h
* @author interfector18
*
* Copyright 2020, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#pragma once
namespace drogon
{
namespace orm
{
class DefaultValue
{
};
namespace internal
{
enum FieldType
{
MySqlTiny,
MySqlShort,
MySqlLong,
MySqlLongLong,
MySqlNull,
MySqlString,
DrogonDefaultValue,
};
} // namespace internal
} // namespace orm
} // namespace drogon

View File

@ -13,6 +13,7 @@
*/
#pragma once
#include <drogon/orm/DbTypes.h>
#include <drogon/orm/Exception.h>
#include <drogon/orm/Field.h>
#include <drogon/orm/FunctionTraits.h>
@ -432,6 +433,7 @@ class SqlBinder
}
self &operator<<(double f);
self &operator<<(std::nullptr_t nullp);
self &operator<<(DefaultValue dv);
self &operator<<(const Mode &mode)
{
mode_ = mode;
@ -466,7 +468,7 @@ class SqlBinder
int getMysqlTypeBySize(size_t size);
std::shared_ptr<std::string> sqlPtr_;
const char *sqlViewPtr_;
const size_t sqlViewLength_;
size_t sqlViewLength_;
DbClient &client_;
size_t parametersNumber_{0};
std::vector<const char *> parameters_;

View File

@ -15,8 +15,10 @@
#include <drogon/config.h>
#include <drogon/orm/DbClient.h>
#include <drogon/orm/SqlBinder.h>
#include <drogon/utils/Utilities.h>
#include <future>
#include <iostream>
#include <regex>
#include <stdio.h>
#if USE_MYSQL
#include <mysql.h>
@ -144,9 +146,7 @@ SqlBinder &SqlBinder::operator<<(const std::string &str)
}
else if (type_ == ClientType::Mysql)
{
#if USE_MYSQL
formats_.push_back(MYSQL_TYPE_STRING);
#endif
formats_.push_back(MySqlString);
}
else if (type_ == ClientType::Sqlite3)
{
@ -169,9 +169,7 @@ SqlBinder &SqlBinder::operator<<(std::string &&str)
}
else if (type_ == ClientType::Mysql)
{
#if USE_MYSQL
formats_.push_back(MYSQL_TYPE_STRING);
#endif
formats_.push_back(MySqlString);
}
else if (type_ == ClientType::Sqlite3)
{
@ -194,9 +192,7 @@ SqlBinder &SqlBinder::operator<<(const std::vector<char> &v)
}
else if (type_ == ClientType::Mysql)
{
#if USE_MYSQL
formats_.push_back(MYSQL_TYPE_STRING);
#endif
formats_.push_back(MySqlString);
}
else if (type_ == ClientType::Sqlite3)
{
@ -204,6 +200,7 @@ SqlBinder &SqlBinder::operator<<(const std::vector<char> &v)
}
return *this;
}
SqlBinder &SqlBinder::operator<<(std::vector<char> &&v)
{
std::shared_ptr<std::vector<char>> obj =
@ -218,9 +215,7 @@ SqlBinder &SqlBinder::operator<<(std::vector<char> &&v)
}
else if (type_ == ClientType::Mysql)
{
#if USE_MYSQL
formats_.push_back(MYSQL_TYPE_STRING);
#endif
formats_.push_back(MySqlString);
}
else if (type_ == ClientType::Sqlite3)
{
@ -243,6 +238,7 @@ SqlBinder &SqlBinder::operator<<(double f)
}
return operator<<(std::to_string(f));
}
SqlBinder &SqlBinder::operator<<(std::nullptr_t nullp)
{
(void)nullp;
@ -255,9 +251,7 @@ SqlBinder &SqlBinder::operator<<(std::nullptr_t nullp)
}
else if (type_ == ClientType::Mysql)
{
#if USE_MYSQL
formats_.push_back(MYSQL_TYPE_NULL);
#endif
formats_.push_back(MySqlNull);
}
else if (type_ == ClientType::Sqlite3)
{
@ -266,22 +260,65 @@ SqlBinder &SqlBinder::operator<<(std::nullptr_t nullp)
return *this;
}
SqlBinder &SqlBinder::operator<<(DefaultValue dv)
{
(void)dv;
if (type_ == ClientType::PostgreSQL)
{
std::regex r("\\$" + std::to_string(parametersNumber_ + 1) + "\\b");
// initialize with empty, as the next line will make a copy anyway
if (!sqlPtr_)
sqlPtr_ = std::make_shared<std::string>();
*sqlPtr_ = std::regex_replace(sqlViewPtr_, r, "default");
// decrement all other $n parameters by 1
size_t i = parametersNumber_ + 2;
while ((sqlPtr_->find("$" + std::to_string(i))) != std::string::npos)
{
r = "\\$" + std::to_string(i) + "\\b";
// use sed format to avoid $n regex group substitution,
// and use ->data() to compile in C++14 mode
*sqlPtr_ = std::regex_replace(sqlPtr_->data(),
r,
"$" + std::to_string(i - 1),
std::regex_constants::format_sed);
++i;
}
sqlViewPtr_ = sqlPtr_->data();
sqlViewLength_ = sqlPtr_->length();
}
else if (type_ == ClientType::Mysql)
{
++parametersNumber_;
parameters_.push_back(NULL);
lengths_.push_back(0);
formats_.push_back(DrogonDefaultValue);
}
else if (type_ == ClientType::Sqlite3)
{
LOG_FATAL << "default not supported in sqlite3";
exit(1);
}
return *this;
}
int SqlBinder::getMysqlTypeBySize(size_t size)
{
#if USE_MYSQL
switch (size)
{
case 1:
return MYSQL_TYPE_TINY;
return MySqlTiny;
break;
case 2:
return MYSQL_TYPE_SHORT;
return MySqlShort;
break;
case 4:
return MYSQL_TYPE_LONG;
return MySqlLong;
break;
case 8:
return MYSQL_TYPE_LONGLONG;
return MySqlLongLong;
break;
default:
return 0;

View File

@ -15,6 +15,7 @@
#include "MysqlConnection.h"
#include "MysqlResultImpl.h"
#include <algorithm>
#include <drogon/orm/DbTypes.h>
#include <drogon/utils/Utilities.h>
#include <drogon/utils/string_view.h>
#include <errmsg.h>
@ -428,24 +429,24 @@ void MysqlConnection::execSqlInLoop(
pos = seekPos + 1;
switch (format[i])
{
case MYSQL_TYPE_TINY:
case internal::MySqlTiny:
sql_.append(std::to_string(*((char *)parameters[i])));
break;
case MYSQL_TYPE_SHORT:
case internal::MySqlShort:
sql_.append(std::to_string(*((short *)parameters[i])));
break;
case MYSQL_TYPE_LONG:
case internal::MySqlLong:
sql_.append(
std::to_string(*((int32_t *)parameters[i])));
break;
case MYSQL_TYPE_LONGLONG:
case internal::MySqlLongLong:
sql_.append(
std::to_string(*((int64_t *)parameters[i])));
break;
case MYSQL_TYPE_NULL:
case internal::MySqlNull:
sql_.append("NULL");
break;
case MYSQL_TYPE_STRING:
case internal::MySqlString:
{
sql_.append("'");
std::string to(length[i] * 2, '\0');
@ -458,6 +459,9 @@ void MysqlConnection::execSqlInLoop(
sql_.append("'");
}
break;
case internal::DrogonDefaultValue:
sql_.append("default");
break;
default:
break;
}

View File

@ -14,6 +14,7 @@
*/
#include <drogon/config.h>
#include <drogon/orm/DbClient.h>
#include <drogon/orm/DbTypes.h>
#include <trantor/utils/Logger.h>
#include <chrono>
#include <iostream>
@ -125,12 +126,12 @@ void doPostgreTest(const drogon::orm::DbClientPtr &clientPtr)
"postgresql - DbClient streaming-type interface(0)");
};
/// 1.2 insert,blocking
*clientPtr << "insert into users (user_id,user_name,password,org_name) "
"values($1,$2,$3,$4) returning *"
<< "pg1"
<< "postgresql1"
<< "123"
<< "default" << Mode::Blocking >>
*clientPtr
<< "insert into users (user_id,user_name,admin,password,org_name) "
"values($1,$2,$3,$4,$5) returning *"
<< "pg1"
<< "postgresql1" << drogon::orm::DefaultValue{} << "123"
<< "default" << Mode::Blocking >>
[](const Result &r) {
// std::cout << "id=" << r[0]["id"].as<int64_t>() << std::endl;
testOutput(r[0]["id"].as<int64_t>() == 2,
@ -811,12 +812,13 @@ void doMysqlTest(const drogon::orm::DbClientPtr &clientPtr)
};
/// Test1:DbClient streaming-type interface
/// 1.1 insert,non-blocking
*clientPtr << "insert into users (user_id,user_name,password,org_name) "
"values(?,?,?,?)"
<< "pg"
<< "postgresql"
<< "123"
<< "default" >>
*clientPtr
<< "insert into users (user_id,user_name,password,org_name,admin) "
"values(?,?,?,?,?)"
<< "pg"
<< "postgresql"
<< "123"
<< "default" << drogon::orm::DefaultValue{} >>
[](const Result &r) {
testOutput(r.insertId() == 1,
"mysql - DbClient streaming-type interface(0)");