polardbxengine/plugin/polarx_rpc/coders/encoders/encoding_polarx_row.h

291 lines
10 KiB
C++

/*
* Copyright (c) 2019, 2022, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.0,
* as published by the Free Software Foundation.
*
* This program is also distributed with certain software (including
* but not limited to OpenSSL) that is licensed under separate terms,
* as designated in a particular file or component or in included license
* documentation. The authors of MySQL hereby grant you an additional
* permission to link the program and your derivative works with the
* separately licensed software that they have included with MySQL.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License, version 2.0, for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include <cassert>
#include <cstdint>
#include <cstring>
#include <google/protobuf/wire_format_lite.h>
#include <string>
#include <vector>
#include "../xdecimal.h"
#include "decimal.h"
#include "mysql_time.h"
#include "encoding_polarx_messages.h"
namespace protocol {
template <typename Encoder_type> class XRow_encoder_base {
private:
using Position = typename Encoder_type::Position;
Encoder_type *m_encoder = nullptr;
Position m_row_begin;
uint32_t m_fields;
public:
explicit XRow_encoder_base(Encoder_type *encoder) : m_encoder(encoder) {}
uint32_t get_num_fields() const { return m_fields; }
void begin_row() {
m_encoder->template begin_xmessage<tags::Row::server_id, 100>(&m_row_begin);
m_fields = 0;
}
void end_row() { m_encoder->end_xmessage(m_row_begin); }
void abort_row() { m_encoder->abort_xmessage(m_row_begin); }
void field_null() {
++m_fields;
m_encoder->template ensure_buffer_size<20>();
m_encoder->template encode_field_delimited_header<tags::Row::field>();
m_encoder->template encode_const_var_uint<0>();
}
void field_signed_longlong(const longlong value) {
++m_fields;
m_encoder->template ensure_buffer_size<30>();
auto field_begin =
m_encoder->template begin_delimited_field<tags::Row::field>();
m_encoder->encode_var_sint64(static_cast<int64_t>(value));
m_encoder->end_delimited_field(field_begin);
}
void field_unsigned_longlong(const ulonglong value) {
++m_fields;
m_encoder->template ensure_buffer_size<30>();
auto field_begin =
m_encoder->template begin_delimited_field<tags::Row::field>();
m_encoder->encode_var_uint64(static_cast<uint64_t>(value));
m_encoder->end_delimited_field(field_begin);
}
void field_bit(const char *const value, size_t length) {
assert(length <= 8);
++m_fields;
uint64_t binary_value = 0;
for (size_t i = 0; i < length; ++i) {
binary_value +=
((static_cast<uint64_t>(value[i]) & 0xff) << ((length - i - 1) * 8));
}
m_encoder->template ensure_buffer_size<30>();
auto field_begin =
m_encoder->template begin_delimited_field<tags::Row::field>();
m_encoder->encode_var_uint64(binary_value);
m_encoder->end_delimited_field(field_begin);
}
void field_set(const char *const value, size_t length) {
++m_fields;
// special case: empty SET
if (0 == length) {
// write length=0x01 to the buffer and we're done here
m_encoder->template ensure_buffer_size<30>();
m_encoder->template encode_field_delimited_header<tags::Row::field>();
m_encoder->template encode_const_var_uint<1>();
m_encoder->template encode_const_var_uint<1>();
return;
}
std::vector<std::string> set_vals;
const char *comma, *p_value = value;
unsigned int elem_len;
do {
comma = std::strchr(p_value, ',');
if (comma != nullptr) {
elem_len = static_cast<unsigned int>(comma - p_value);
set_vals.push_back(std::string(p_value, elem_len));
p_value = comma + 1;
}
} while (comma != nullptr);
// still sth left to store
if (static_cast<size_t>(p_value - value) < length) {
elem_len = static_cast<unsigned int>(length - (p_value - value));
set_vals.push_back(std::string(p_value, elem_len));
}
m_encoder->template ensure_buffer_size<20>();
auto field_begin =
m_encoder->template begin_delimited_field<tags::Row::field, 3>();
for (size_t i = 0; i < set_vals.size(); ++i) {
m_encoder->template ensure_buffer_size<10>();
m_encoder->encode_var_uint64(set_vals[i].length());
m_encoder->encode_raw(
reinterpret_cast<const uint8_t *>(set_vals[i].c_str()),
set_vals[i].length());
}
m_encoder->end_delimited_field(field_begin);
}
void field_string(const char *value, const size_t length) {
++m_fields;
m_encoder->template ensure_buffer_size<30>();
m_encoder->template encode_field_delimited_header<tags::Row::field>();
m_encoder->encode_var_uint32(static_cast<uint32_t>(length + 1));
m_encoder->encode_raw(reinterpret_cast<const uint8_t *>(value), length);
m_encoder->encode_raw(reinterpret_cast<const uint8_t *>("\0"), 1);
}
void field_datetime(const MYSQL_TIME *value) {
assert(value->year < 10000);
assert(value->month < 13);
assert(value->day < 32);
assert(value->hour < 24);
assert(value->minute < 60);
assert(value->second < 60);
assert(value->second_part < 1000000);
++m_fields;
m_encoder->template ensure_buffer_size<32>();
auto field_begin =
m_encoder->template begin_delimited_field<tags::Row::field>();
m_encoder->encode_fixedvar16_uint32(value->year);
m_encoder->encode_fixedvar8_uint8(value->month);
m_encoder->encode_fixedvar8_uint8(value->day);
if (value->hour || value->minute || value->second || value->second_part) {
m_encoder->encode_fixedvar8_uint8(value->hour);
if (value->minute || value->second || value->second_part) {
m_encoder->encode_fixedvar8_uint8(value->minute);
if (value->second || value->second_part) {
m_encoder->encode_fixedvar8_uint8(value->second);
if (value->second_part) {
m_encoder->encode_var_uint32(value->second_part);
}
}
}
}
m_encoder->end_delimited_field(field_begin);
}
void field_time(const MYSQL_TIME *value) {
assert(value->minute < 60);
assert(value->second < 60);
assert(value->second_part < 1000000);
++m_fields;
m_encoder->template ensure_buffer_size<47>();
auto field_begin =
m_encoder->template begin_delimited_field<tags::Row::field>();
if (value->neg)
m_encoder->template encode_const_var_uint<1>();
else
m_encoder->template encode_const_var_uint<0>();
if (value->day != 0 || value->hour || value->minute || value->second ||
value->second_part) {
m_encoder->encode_var_uint64(value->hour + value->day * 24);
if (value->minute || value->second || value->second_part) {
m_encoder->encode_fixedvar8_uint8(value->minute);
if (value->second || value->second_part) {
m_encoder->encode_fixedvar8_uint8(value->second);
if (value->second_part) {
m_encoder->encode_var_uint32(value->second_part);
}
}
}
}
m_encoder->end_delimited_field(field_begin);
}
void field_date(const MYSQL_TIME *value) {
assert(value->year < 10000);
assert(value->month < 13);
assert(value->day < 32);
++m_fields;
m_encoder->template ensure_buffer_size<27>();
auto field_begin =
m_encoder->template begin_delimited_field<tags::Row::field>();
m_encoder->encode_var_uint32(value->year);
m_encoder->encode_fixedvar8_uint8(value->month);
m_encoder->encode_fixedvar8_uint8(value->day);
m_encoder->end_delimited_field(field_begin);
}
void field_float(const float value) {
++m_fields;
m_encoder->template ensure_buffer_size<24>();
m_encoder->template encode_field_delimited_header<tags::Row::field>();
m_encoder->template encode_const_var_uint<4>(); // Field size
m_encoder->encode_fixed_uint32(
google::protobuf::internal::WireFormatLite::EncodeFloat(value));
}
void field_double(const double value) {
++m_fields;
m_encoder->template ensure_buffer_size<28>();
m_encoder->template encode_field_delimited_header<tags::Row::field>();
m_encoder->template encode_const_var_uint<8>(); // Field size
m_encoder->encode_fixed_uint64(
google::protobuf::internal::WireFormatLite::EncodeDouble(value));
}
void field_decimal(const char *value, const size_t length) {
++m_fields;
std::string dec_str(value, length);
polarx_rpc::Decimal dec(dec_str);
std::string dec_bytes = dec.to_bytes();
m_encoder->template ensure_buffer_size<30>();
m_encoder->template encode_field_delimited_header<tags::Row::field>();
m_encoder->encode_var_uint32(static_cast<uint32_t>(dec_bytes.length()));
m_encoder->encode_raw(reinterpret_cast<const uint8_t *>(dec_bytes.c_str()),
(static_cast<uint32_t>(dec_bytes.length())));
}
void field_decimal(const decimal_t *value) {
++m_fields;
std::string str_buf;
int str_len = 200;
str_buf.resize(str_len);
decimal2string(value, &(str_buf)[0], &str_len, 0, 0, 0);
str_buf.resize(str_len);
polarx_rpc::Decimal dec(str_buf);
std::string dec_bytes = dec.to_bytes();
m_encoder->template ensure_buffer_size<30>();
m_encoder->template encode_field_delimited_header<tags::Row::field>();
m_encoder->encode_var_uint32(static_cast<uint32_t>(dec_bytes.length()));
m_encoder->encode_raw(reinterpret_cast<const uint8_t *>(dec_bytes.c_str()),
(static_cast<uint32_t>(dec_bytes.length())));
}
};
class PolarX_Row_encoder : public XRow_encoder_base<PolarX_Protocol_encoder> {
public:
using Base = XRow_encoder_base<PolarX_Protocol_encoder>;
using Base::Base;
};
} // namespace protocol