mirror of
https://github.com/sogou/workflow.git
synced 2026-02-08 01:33:17 +08:00
486 lines
9.9 KiB
C++
486 lines
9.9 KiB
C++
/*
|
|
Copyright (c) 2019 Sogou, Inc.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
|
|
Authors: Li Yingxin (liyingxin@sogou-inc.com)
|
|
*/
|
|
|
|
#include <math.h>
|
|
#include <string>
|
|
#include <utility>
|
|
#include "mysql_byteorder.h"
|
|
|
|
namespace protocol
|
|
{
|
|
|
|
inline std::string MySQLField::get_name() const
|
|
{
|
|
if (this->data_type == MYSQL_TYPE_NULL)
|
|
return "";
|
|
return std::string(this->name, this->name_length);
|
|
}
|
|
|
|
inline std::string MySQLField::get_org_name() const
|
|
{
|
|
if (this->data_type == MYSQL_TYPE_NULL)
|
|
return "";
|
|
return std::string(this->org_name, this->org_name_length);
|
|
}
|
|
|
|
inline std::string MySQLField::get_table() const
|
|
{
|
|
if (this->data_type == MYSQL_TYPE_NULL)
|
|
return "";
|
|
return std::string(this->table, this->table_length);
|
|
}
|
|
|
|
inline std::string MySQLField::get_org_table() const
|
|
{
|
|
if (this->data_type == MYSQL_TYPE_NULL)
|
|
return "";
|
|
return std::string(this->org_table, this->org_table_length);
|
|
}
|
|
|
|
inline std::string MySQLField::get_db() const
|
|
{
|
|
if (this->data_type == MYSQL_TYPE_NULL)
|
|
return "";
|
|
return std::string(this->db, this->db_length);
|
|
}
|
|
|
|
inline std::string MySQLField::get_catalog() const
|
|
{
|
|
if (this->data_type == MYSQL_TYPE_NULL)
|
|
return "";
|
|
return std::string(this->catalog, this->catalog_length);
|
|
}
|
|
|
|
inline std::string MySQLField::get_def() const
|
|
{
|
|
if (this->data_type == MYSQL_TYPE_NULL)
|
|
return "";
|
|
return std::string(this->def, this->def_length);
|
|
}
|
|
|
|
inline int MySQLField::get_charsetnr() const
|
|
{
|
|
if (this->data_type == MYSQL_TYPE_NULL)
|
|
return 0;
|
|
return this->charsetnr;
|
|
}
|
|
|
|
inline int MySQLField::get_length() const
|
|
{
|
|
if (this->data_type == MYSQL_TYPE_NULL)
|
|
return 0;
|
|
return this->length;
|
|
}
|
|
|
|
inline int MySQLField::get_flags() const
|
|
{
|
|
if (this->data_type == MYSQL_TYPE_NULL)
|
|
return 0;
|
|
return this->flags;
|
|
}
|
|
|
|
inline int MySQLField::get_decimals() const
|
|
{
|
|
if (this->data_type == MYSQL_TYPE_NULL)
|
|
return 0;
|
|
return this->decimals;
|
|
}
|
|
|
|
inline int MySQLField::get_data_type() const
|
|
{
|
|
return this->data_type;
|
|
}
|
|
|
|
inline MySQLCell::MySQLCell(MySQLCell&& move)
|
|
{
|
|
this->operator=(std::move(move));
|
|
}
|
|
|
|
inline MySQLCell& MySQLCell::operator=(MySQLCell&& move)
|
|
{
|
|
if (this != &move)
|
|
{
|
|
this->data = move.data;
|
|
this->len = move.len;
|
|
this->data_type = move.data_type;
|
|
|
|
move.data = NULL;
|
|
move.len = 0;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
inline MySQLCell::MySQLCell(const void *data, size_t len, int data_type)
|
|
{
|
|
this->data_type = data_type;
|
|
this->data = const_cast<void *>(data);
|
|
this->len = len;
|
|
}
|
|
|
|
inline MySQLCell::MySQLCell()
|
|
{
|
|
this->data = NULL;
|
|
this->len = 0;
|
|
this->data_type = MYSQL_TYPE_NULL;
|
|
}
|
|
|
|
inline int MySQLCell::get_data_type() const
|
|
{
|
|
return this->data_type;
|
|
}
|
|
|
|
inline void MySQLCell::get_cell_nocopy(const void **data, size_t *len,
|
|
int *data_type) const
|
|
{
|
|
*data = this->data;
|
|
*len = this->len;
|
|
*data_type = this->data_type;
|
|
}
|
|
|
|
inline bool MySQLCell::is_null() const
|
|
{
|
|
return (this->data_type == MYSQL_TYPE_NULL);
|
|
}
|
|
|
|
inline std::string MySQLCell::as_binary_string() const
|
|
{
|
|
return std::string((char *)this->data, this->len);
|
|
}
|
|
|
|
inline bool MySQLCell::is_int() const
|
|
{
|
|
return (this->data_type == MYSQL_TYPE_TINY ||
|
|
this->data_type == MYSQL_TYPE_SHORT ||
|
|
this->data_type == MYSQL_TYPE_INT24 ||
|
|
this->data_type == MYSQL_TYPE_LONG);
|
|
}
|
|
|
|
inline int MySQLCell::as_int() const
|
|
{
|
|
if (!this->is_int())
|
|
return 0;
|
|
|
|
std::string num((char *)this->data, this->len);
|
|
return atoi(num.c_str());
|
|
}
|
|
|
|
inline bool MySQLCell::is_float() const
|
|
{
|
|
return (this->data_type == MYSQL_TYPE_FLOAT);
|
|
}
|
|
|
|
inline float MySQLCell::as_float() const
|
|
{
|
|
if (!this->is_float())
|
|
return NAN;
|
|
|
|
std::string num((char *)this->data, this->len);
|
|
return strtof(num.c_str(), NULL);
|
|
}
|
|
|
|
inline bool MySQLCell::is_double() const
|
|
{
|
|
return (this->data_type == MYSQL_TYPE_DOUBLE);
|
|
}
|
|
|
|
inline double MySQLCell::as_double() const
|
|
{
|
|
if (!this->is_double())
|
|
return NAN;
|
|
|
|
std::string num((char *)this->data, this->len);
|
|
return strtod(num.c_str(), NULL);
|
|
}
|
|
|
|
inline bool MySQLCell::is_ulonglong() const
|
|
{
|
|
return (this->data_type == MYSQL_TYPE_LONGLONG);
|
|
}
|
|
|
|
inline unsigned long long MySQLCell::as_ulonglong() const
|
|
{
|
|
if (!this->is_ulonglong())
|
|
return (unsigned long long)-1;
|
|
|
|
std::string num((char *)this->data, this->len);
|
|
return strtoull(num.c_str(), NULL, 10);
|
|
}
|
|
|
|
inline bool MySQLCell::is_date() const
|
|
{
|
|
return (this->data_type == MYSQL_TYPE_DATE);
|
|
}
|
|
|
|
inline std::string MySQLCell::as_date() const
|
|
{
|
|
if (!this->is_date())
|
|
return "";
|
|
|
|
return std::string((char *)this->data, this->len);
|
|
}
|
|
|
|
inline bool MySQLCell::is_time() const
|
|
{
|
|
return (this->data_type == MYSQL_TYPE_TIME);
|
|
}
|
|
|
|
inline std::string MySQLCell::as_time() const
|
|
{
|
|
if (!this->is_time())
|
|
return "";
|
|
|
|
return std::string((char *)this->data, this->len);
|
|
}
|
|
|
|
inline bool MySQLCell::is_datetime() const
|
|
{
|
|
return (this->data_type == MYSQL_TYPE_DATETIME ||
|
|
this->data_type == MYSQL_TYPE_TIMESTAMP);
|
|
}
|
|
|
|
inline std::string MySQLCell::as_datetime() const
|
|
{
|
|
if (!this->is_datetime())
|
|
return "";
|
|
|
|
return std::string((char *)this->data, this->len);
|
|
}
|
|
|
|
inline bool MySQLCell::is_string() const
|
|
{
|
|
return (this->data_type == MYSQL_TYPE_DECIMAL ||
|
|
this->data_type == MYSQL_TYPE_STRING ||
|
|
this->data_type == MYSQL_TYPE_VARCHAR ||
|
|
this->data_type == MYSQL_TYPE_VAR_STRING ||
|
|
this->data_type == MYSQL_TYPE_JSON);
|
|
}
|
|
|
|
inline std::string MySQLCell::as_string() const
|
|
{
|
|
if (!this->is_string() && !this->is_time() &&
|
|
!this->is_date() && !this->is_datetime())
|
|
return "";
|
|
|
|
return std::string((char *)this->data, this->len);
|
|
}
|
|
|
|
template<class T>
|
|
bool MySQLResultCursor::fetch_row(T& row_map)
|
|
{
|
|
if (this->status != MYSQL_STATUS_GET_RESULT)
|
|
return false;
|
|
|
|
unsigned long long len;
|
|
const unsigned char *data;
|
|
int data_type;
|
|
|
|
const unsigned char *p = (const unsigned char *)this->pos;
|
|
const unsigned char *end = (const unsigned char *)this->end;
|
|
|
|
row_map.clear();
|
|
|
|
for (int i = 0; i < this->field_count; i++)
|
|
{
|
|
data_type = this->fields[i]->get_data_type();
|
|
if (*p == MYSQL_PACKET_HEADER_NULL)
|
|
{
|
|
data = NULL;
|
|
len = 0;
|
|
p++;
|
|
data_type = MYSQL_TYPE_NULL;
|
|
}
|
|
else if (decode_string(&data, &len, &p, end) == false)
|
|
{
|
|
this->status = MYSQL_STATUS_ERROR;
|
|
return false;
|
|
}
|
|
row_map.emplace(this->fields[i]->get_name(), MySQLCell(data, len, data_type));
|
|
}
|
|
|
|
this->pos = p;
|
|
|
|
if (++this->current_row == this->row_count)
|
|
this->status = MYSQL_STATUS_END;
|
|
|
|
return true;
|
|
}
|
|
|
|
inline const MySQLField *MySQLResultCursor::fetch_field()
|
|
{
|
|
if (this->status != MYSQL_STATUS_GET_RESULT &&
|
|
this->status != MYSQL_STATUS_END)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (this->current_field >= this->field_count)
|
|
return NULL;
|
|
|
|
return this->fields[this->current_field++];
|
|
}
|
|
|
|
inline const MySQLField *const *MySQLResultCursor::fetch_fields() const
|
|
{
|
|
if (this->status != MYSQL_STATUS_GET_RESULT &&
|
|
this->status != MYSQL_STATUS_END)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return this->fields;
|
|
}
|
|
|
|
inline int MySQLResultCursor::get_cursor_status() const
|
|
{
|
|
return this->status;
|
|
}
|
|
|
|
inline int MySQLResultCursor::get_server_status() const
|
|
{
|
|
if (this->status != MYSQL_STATUS_GET_RESULT &&
|
|
this->status != MYSQL_STATUS_END &&
|
|
this->status != MYSQL_STATUS_OK)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return this->server_status;
|
|
}
|
|
|
|
inline int MySQLResultCursor::get_field_count() const
|
|
{
|
|
if (this->status != MYSQL_STATUS_GET_RESULT &&
|
|
this->status != MYSQL_STATUS_END)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return this->field_count;
|
|
}
|
|
|
|
inline int MySQLResultCursor::get_rows_count() const
|
|
{
|
|
if (this->status != MYSQL_STATUS_GET_RESULT &&
|
|
this->status != MYSQL_STATUS_END)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return this->row_count;
|
|
}
|
|
|
|
inline unsigned long long MySQLResultCursor::get_affected_rows() const
|
|
{
|
|
if (this->status != MYSQL_PACKET_OK)
|
|
return 0;
|
|
|
|
return this->affected_rows;
|
|
}
|
|
|
|
inline int MySQLResultCursor::get_warnings() const
|
|
{
|
|
if (this->status != MYSQL_PACKET_OK)
|
|
return 0;
|
|
|
|
return this->warning_count;
|
|
}
|
|
|
|
inline unsigned long long MySQLResultCursor::get_insert_id() const
|
|
{
|
|
if (this->status != MYSQL_PACKET_OK)
|
|
return 0;
|
|
|
|
return this->insert_id;
|
|
}
|
|
|
|
inline std::string MySQLResultCursor::get_info() const
|
|
{
|
|
if (this->status != MYSQL_PACKET_OK)
|
|
return "";
|
|
|
|
return std::string((char *)this->start, this->info_len);
|
|
}
|
|
|
|
inline void MySQLResultCursor::clear()
|
|
{
|
|
for (int i = 0; i < this->field_count; i++)
|
|
delete this->fields[i];
|
|
|
|
delete []this->fields;
|
|
}
|
|
|
|
inline MySQLResultCursor::~MySQLResultCursor()
|
|
{
|
|
this->clear();
|
|
}
|
|
|
|
inline MySQLResultCursor::MySQLResultCursor(MySQLResultCursor&& move)
|
|
{
|
|
this->start = move.start;
|
|
this->end = move.end;
|
|
this->pos = move.pos;
|
|
this->status = move.status;
|
|
this->row_data = move.row_data;
|
|
this->fields = move.fields;
|
|
this->row_count = move.row_count;
|
|
this->field_count = move.field_count;
|
|
this->current_row = move.current_row;
|
|
this->current_field = move.current_field;
|
|
this->affected_rows = move.affected_rows;
|
|
this->insert_id = move.insert_id;
|
|
this->warning_count = move.warning_count;
|
|
this->info_len = move.info_len;
|
|
this->cursor = move.cursor;
|
|
this->parser = move.parser;
|
|
|
|
move.init();
|
|
}
|
|
|
|
inline MySQLResultCursor& MySQLResultCursor::operator=(MySQLResultCursor&& move)
|
|
{
|
|
if (this != &move)
|
|
{
|
|
this->clear();
|
|
|
|
this->start = move.start;
|
|
this->end = move.end;
|
|
this->pos = move.pos;
|
|
this->status = move.status;
|
|
this->row_data = move.row_data;
|
|
this->fields = move.fields;
|
|
this->row_count = move.row_count;
|
|
this->field_count = move.field_count;
|
|
this->current_row = move.current_row;
|
|
this->current_field = move.current_field;
|
|
this->affected_rows = move.affected_rows;
|
|
this->insert_id = move.insert_id;
|
|
this->warning_count = move.warning_count;
|
|
this->info_len = move.info_len;
|
|
this->cursor = move.cursor;
|
|
this->parser = move.parser;
|
|
|
|
move.init();
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
}
|
|
|