/* * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved. * * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit). * * Use of this source code is governed by MIT license that can be found in the * LICENSE file in the root of the source tree. All contributing project authors * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SQL_SQLCONNECTION_H_ #define SQL_SQLCONNECTION_H_ #include #include #include #include #include #include #include #include #include #include #include "logger.h" #include "util.h" #include #if defined(_WIN32) #pragma comment (lib,"libmysql") #endif namespace toolkit { /** * 数据库异常类 * Database exception class * [AUTO-TRANSLATED:f92df85e] */ class SqlException : public std::exception { public: SqlException(const std::string &sql, const std::string &err) { _sql = sql; _err = err; } virtual const char *what() const noexcept { return _err.data(); } const std::string &getSql() const { return _sql; } private: std::string _sql; std::string _err; }; /** * mysql连接 * MySQL connection * [AUTO-TRANSLATED:a2deb48d] */ class SqlConnection { public: /** * 构造函数 * @param url 数据库地址 * @param port 数据库端口号 * @param dbname 数据库名 * @param username 用户名 * @param password 用户密码 * @param character 字符集 * Constructor * @param url Database address * @param port Database port number * @param dbname Database name * @param username Username * @param password User password * @param character Character set * [AUTO-TRANSLATED:410a33a6] */ SqlConnection(const std::string &url, unsigned short port, const std::string &dbname, const std::string &username, const std::string &password, const std::string &character = "utf8mb4") { mysql_init(&_sql); unsigned int timeout = 3; mysql_options(&_sql, MYSQL_OPT_CONNECT_TIMEOUT, &timeout); if (!mysql_real_connect(&_sql, url.data(), username.data(), password.data(), dbname.data(), port, nullptr, 0)) { mysql_close(&_sql); throw SqlException("mysql_real_connect", mysql_error(&_sql)); } //兼容bool与my_bool [AUTO-TRANSLATED:7d8d4190] //Compatible with bool and my_bool uint32_t reconnect = 0x01010101; mysql_options(&_sql, MYSQL_OPT_RECONNECT, &reconnect); mysql_set_character_set(&_sql, character.data()); } ~SqlConnection() { mysql_close(&_sql); } /** * 以printf样式执行sql,无数据返回 * @param rowId insert时的插入rowid * @param fmt printf类型fmt * @param arg 可变参数列表 * @return 影响行数 * Execute SQL in printf style, no data returned * @param rowId Insert rowid when inserting * @param fmt printf type fmt * @param arg Variable argument list * @return Affected rows * [AUTO-TRANSLATED:7c72ab80] */ template int64_t query(int64_t &rowId, Fmt &&fmt, Args &&...arg) { check(); auto tmp = queryString(std::forward(fmt), std::forward(arg)...); if (doQuery(tmp)) { throw SqlException(tmp, mysql_error(&_sql)); } rowId = mysql_insert_id(&_sql); return mysql_affected_rows(&_sql); } /** * 以printf样式执行sql,并且返回list类型的结果(不包含数据列名) * @param rowId insert时的插入rowid * @param ret 返回数据列表 * @param fmt printf类型fmt * @param arg 可变参数列表 * @return 影响行数 * Execute SQL in printf style, and return list type result (excluding column names) * @param rowId Insert rowid when inserting * @param ret Returned data list * @param fmt printf type fmt * @param arg Variable argument list * @return Affected rows * [AUTO-TRANSLATED:57baa44e] */ template int64_t query(int64_t &rowId, std::vector > &ret, Fmt &&fmt, Args &&...arg) { return queryList(rowId, ret, std::forward(fmt), std::forward(arg)...); } template int64_t query(int64_t &rowId, std::vector> &ret, Fmt &&fmt, Args &&...arg) { return queryList(rowId, ret, std::forward(fmt), std::forward(arg)...); } template int64_t query(int64_t &rowId, std::vector > &ret, Fmt &&fmt, Args &&...arg) { return queryList(rowId, ret, std::forward(fmt), std::forward(arg)...); } /** * 以printf样式执行sql,并且返回Map类型的结果(包含数据列名) * @param rowId insert时的插入rowid * @param ret 返回数据列表 * @param fmt printf类型fmt * @param arg 可变参数列表 * @return 影响行数 * Execute SQL in printf style, and return Map type result (including column names) * @param rowId Insert rowid when inserting * @param ret Returned data list * @param fmt printf type fmt * @param arg Variable argument list * @return Affected rows * [AUTO-TRANSLATED:a12a695e] */ template int64_t query(int64_t &rowId, std::vector &ret, Fmt &&fmt, Args &&...arg) { check(); auto tmp = queryString(std::forward(fmt), std::forward(arg)...); if (doQuery(tmp)) { throw SqlException(tmp, mysql_error(&_sql)); } ret.clear(); MYSQL_RES *res = mysql_store_result(&_sql); if (!res) { rowId = mysql_insert_id(&_sql); return mysql_affected_rows(&_sql); } MYSQL_ROW row; unsigned int column = mysql_num_fields(res); MYSQL_FIELD *fields = mysql_fetch_fields(res); while ((row = mysql_fetch_row(res)) != nullptr) { ret.emplace_back(); auto &back = ret.back(); for (unsigned int i = 0; i < column; i++) { back[std::string(fields[i].name, fields[i].name_length)] = (row[i] ? row[i] : ""); } } mysql_free_result(res); rowId = mysql_insert_id(&_sql); return mysql_affected_rows(&_sql); } std::string escape(const std::string &str) { char *out = new char[str.length() * 2 + 1]; mysql_real_escape_string(&_sql, out, str.c_str(), str.size()); std::string ret(out); delete[] out; return ret; } template static std::string queryString(const char *fmt, Args &&...arg) { char *ptr_out = nullptr; if (asprintf(&ptr_out, fmt, arg...) > 0 && ptr_out) { std::string ret(ptr_out); free(ptr_out); return ret; } return ""; } template static std::string queryString(const std::string &fmt, Args &&...args) { return queryString(fmt.data(), std::forward(args)...); } static const char *queryString(const char *fmt) { return fmt; } static const std::string &queryString(const std::string &fmt) { return fmt; } private: template int64_t queryList(int64_t &rowId, std::vector &ret, Fmt &&fmt, Args &&...arg) { check(); auto tmp = queryString(std::forward(fmt), std::forward(arg)...); if (doQuery(tmp)) { throw SqlException(tmp, mysql_error(&_sql)); } ret.clear(); MYSQL_RES *res = mysql_store_result(&_sql); if (!res) { rowId = mysql_insert_id(&_sql); return mysql_affected_rows(&_sql); } MYSQL_ROW row; unsigned int column = mysql_num_fields(res); while ((row = mysql_fetch_row(res)) != nullptr) { ret.emplace_back(); auto &back = ret.back(); for (unsigned int i = 0; i < column; i++) { back.emplace_back(row[i] ? row[i] : ""); } } mysql_free_result(res); rowId = mysql_insert_id(&_sql); return mysql_affected_rows(&_sql); } inline void check() { if (mysql_ping(&_sql) != 0) { throw SqlException("mysql_ping", "Mysql connection ping failed"); } } int doQuery(const std::string &sql) { return mysql_query(&_sql, sql.data()); } int doQuery(const char *sql) { return mysql_query(&_sql, sql); } private: MYSQL _sql; }; } /* namespace toolkit */ #endif /* SQL_SQLCONNECTION_H_ */