404 lines
12 KiB
C++
404 lines
12 KiB
C++
/*
|
|
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
|
|
*
|
|
* 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
|
|
*/
|
|
|
|
#include "plugin/x/client/xrow_impl.h"
|
|
|
|
#include <cassert>
|
|
#include <utility>
|
|
|
|
#include "m_string.h"
|
|
#include "my_compiler.h"
|
|
|
|
namespace xcl {
|
|
namespace details {
|
|
|
|
std::string as_string(const Column_metadata &m MY_ATTRIBUTE((unused)),
|
|
const std::set<std::string> &values) {
|
|
std::string result;
|
|
bool first = true;
|
|
|
|
for (const auto &value : values) {
|
|
if (!first) {
|
|
result += ",";
|
|
}
|
|
result += value;
|
|
first = false;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
std::string as_string(const Column_metadata &m MY_ATTRIBUTE((unused)),
|
|
const std::string &value) {
|
|
return value;
|
|
}
|
|
|
|
std::string as_string(const Column_metadata &m MY_ATTRIBUTE((unused)),
|
|
const Time &value) {
|
|
return value.to_string();
|
|
}
|
|
|
|
std::string as_string(const Column_metadata &m MY_ATTRIBUTE((unused)),
|
|
const DateTime &value) {
|
|
return value.to_string();
|
|
}
|
|
|
|
std::string as_string(const Column_metadata &m MY_ATTRIBUTE((unused)),
|
|
const Decimal &value) {
|
|
return value.to_string();
|
|
}
|
|
|
|
// 'my_gcvt()' function doesn't have overload for float,
|
|
// thus 'value' argument must be double (version of this
|
|
// method that takes float as 'value' is not needed)
|
|
std::string floating_point_as_string(const Column_metadata &m,
|
|
const my_gcvt_arg_type arg_type,
|
|
const double &value) {
|
|
char buffer[100];
|
|
|
|
if (m.fractional_digits < DECIMAL_NOT_SPECIFIED) {
|
|
my_fcvt(value, m.fractional_digits, buffer, NULL);
|
|
|
|
return buffer;
|
|
}
|
|
|
|
my_gcvt(value, arg_type, sizeof(buffer) - 1, buffer, NULL);
|
|
|
|
return buffer;
|
|
}
|
|
|
|
std::string as_string(const Column_metadata &metadata, const double &value) {
|
|
return floating_point_as_string(metadata, MY_GCVT_ARG_DOUBLE, value);
|
|
}
|
|
|
|
std::string as_string(const Column_metadata &metadata, const float &value) {
|
|
return floating_point_as_string(metadata, MY_GCVT_ARG_FLOAT, value);
|
|
}
|
|
|
|
template <typename Value_type>
|
|
std::string as_string(const Column_metadata &m MY_ATTRIBUTE((unused)),
|
|
const Value_type &value) {
|
|
return std::to_string(value);
|
|
}
|
|
|
|
} // namespace details
|
|
|
|
XRow_impl::XRow_impl(Metadata *metadata, Context *context)
|
|
: m_metadata(metadata), m_context(context) {}
|
|
|
|
int32_t XRow_impl::get_number_of_fields() const {
|
|
return static_cast<int32>(m_row->field_size());
|
|
}
|
|
|
|
bool XRow_impl::is_null(const int32_t field_index) const {
|
|
return 0 == m_row->field(field_index).size();
|
|
}
|
|
|
|
bool XRow_impl::get_int64(const int32_t field_index, int64_t *out_data) const {
|
|
if (m_metadata->empty()) return false;
|
|
if (Column_type::SINT != (*m_metadata)[field_index].type) return false;
|
|
|
|
const std::string &field = m_row->field(field_index);
|
|
|
|
return row_decoder::buffer_to_s64(field, out_data);
|
|
}
|
|
|
|
bool XRow_impl::get_uint64(const int32_t field_index,
|
|
uint64_t *out_data) const {
|
|
if (m_metadata->empty()) return false;
|
|
if (Column_type::UINT != (*m_metadata)[field_index].type) return false;
|
|
|
|
const std::string &field = m_row->field(field_index);
|
|
|
|
return row_decoder::buffer_to_u64(field, out_data);
|
|
}
|
|
|
|
bool XRow_impl::get_double(const int32_t field_index, double *out_data) const {
|
|
if (m_metadata->empty()) return false;
|
|
if (Column_type::DOUBLE != (*m_metadata)[field_index].type) return false;
|
|
|
|
const std::string &field = m_row->field(field_index);
|
|
|
|
return row_decoder::buffer_to_double(field, out_data);
|
|
}
|
|
|
|
bool XRow_impl::get_float(const int32_t field_index, float *out_data) const {
|
|
if (m_metadata->empty()) return false;
|
|
if (Column_type::FLOAT != (*m_metadata)[field_index].type) return false;
|
|
|
|
const std::string &field = m_row->field(field_index);
|
|
|
|
return row_decoder::buffer_to_float(field, out_data);
|
|
}
|
|
|
|
bool XRow_impl::get_string(const int32_t field_index,
|
|
std::string *out_data) const {
|
|
const char *string_data;
|
|
size_t string_size;
|
|
|
|
if (!get_string(field_index, &string_data, &string_size)) return false;
|
|
|
|
*out_data = std::string(string_data, string_size);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool XRow_impl::get_enum(const int32_t field_index,
|
|
std::string *out_data) const {
|
|
const char *string_data;
|
|
size_t string_size;
|
|
|
|
if (!get_enum(field_index, &string_data, &string_size)) return false;
|
|
|
|
*out_data = std::string(string_data, string_size);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool XRow_impl::get_enum(const int32_t field_index, const char **out_data,
|
|
size_t *out_data_length) const {
|
|
return get_string_based_field(Column_type::ENUM, field_index, out_data,
|
|
out_data_length);
|
|
}
|
|
|
|
bool XRow_impl::get_decimal(const int32_t field_index,
|
|
Decimal *out_data) const {
|
|
if (m_metadata->empty()) return false;
|
|
if (Column_type::DECIMAL != (*m_metadata)[field_index].type) return false;
|
|
|
|
const std::string &field = m_row->field(field_index);
|
|
|
|
row_decoder::buffer_to_decimal(field, out_data);
|
|
|
|
if (out_data) {
|
|
return out_data->is_valid();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool XRow_impl::get_string(const int32_t field_index, const char **out_data,
|
|
size_t *out_data_length) const {
|
|
return get_string_based_field(Column_type::BYTES, field_index, out_data,
|
|
out_data_length);
|
|
}
|
|
|
|
bool XRow_impl::get_time(const int32_t field_index, Time *out_data) const {
|
|
if (m_metadata->empty()) return false;
|
|
if (Column_type::TIME != (*m_metadata)[field_index].type) return false;
|
|
|
|
const std::string &field = m_row->field(field_index);
|
|
|
|
return row_decoder::buffer_to_time(field, out_data);
|
|
}
|
|
|
|
bool XRow_impl::get_datetime(const int32_t field_index,
|
|
DateTime *out_data) const {
|
|
if (m_metadata->empty()) return false;
|
|
if (Column_type::DATETIME != (*m_metadata)[field_index].type) return false;
|
|
|
|
const std::string &field = m_row->field(field_index);
|
|
|
|
bool has_time = false;
|
|
// Metadata does not contain content_type, the only way to determine
|
|
// if there is a time part is to look at the fields length.
|
|
if (!(*m_metadata)[field_index].has_content_type) {
|
|
if ((*m_metadata)[field_index].length >
|
|
m_context->m_datetime_length_discriminator)
|
|
has_time = true;
|
|
} else if ((*m_metadata)[field_index].content_type ==
|
|
static_cast<uint32_t>(Mysqlx::Resultset::DATETIME)) {
|
|
has_time = true;
|
|
}
|
|
|
|
return row_decoder::buffer_to_datetime(field, out_data, has_time);
|
|
}
|
|
|
|
bool XRow_impl::get_set(const int32_t field_index,
|
|
std::set<std::string> *out_data) const {
|
|
if (m_metadata->empty()) return false;
|
|
if (Column_type::SET != (*m_metadata)[field_index].type) return false;
|
|
|
|
const std::string &field = m_row->field(field_index);
|
|
|
|
return row_decoder::buffer_to_set(field, out_data);
|
|
}
|
|
|
|
bool XRow_impl::get_bit(const int32_t field_index, bool *out_data) const {
|
|
if (m_metadata->empty()) return false;
|
|
if (Column_type::BIT != (*m_metadata)[field_index].type) return false;
|
|
|
|
const std::string &field = m_row->field(field_index);
|
|
uint64_t value;
|
|
|
|
if (!row_decoder::buffer_to_u64(field, &value)) return false;
|
|
|
|
*out_data = 0 != value;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool XRow_impl::get_bit(const int32_t field_index, uint64_t *out_data) const {
|
|
if (m_metadata->empty()) return false;
|
|
if (Column_type::BIT != (*m_metadata)[field_index].type) return false;
|
|
|
|
const std::string &field = m_row->field(field_index);
|
|
|
|
return row_decoder::buffer_to_u64(field, out_data);
|
|
}
|
|
|
|
bool XRow_impl::get_field_as_string(const int32_t field_index,
|
|
std::string *out_data) const {
|
|
if (m_metadata->empty()) return false;
|
|
const auto &col = (*m_metadata)[field_index];
|
|
|
|
if (is_null(field_index)) {
|
|
if (out_data) *out_data = "null";
|
|
|
|
return true;
|
|
}
|
|
|
|
switch (col.type) {
|
|
case xcl::Column_type::SINT: {
|
|
int64_t value;
|
|
|
|
if (!get_int64(field_index, &value)) return false;
|
|
|
|
if (out_data) *out_data = details::as_string(col, value);
|
|
|
|
return true;
|
|
}
|
|
|
|
case xcl::Column_type::UINT: {
|
|
uint64_t value;
|
|
|
|
if (!get_uint64(field_index, &value)) return false;
|
|
|
|
if (out_data) *out_data = details::as_string(col, value);
|
|
|
|
return true;
|
|
}
|
|
|
|
case xcl::Column_type::DOUBLE: {
|
|
double value;
|
|
|
|
if (!get_double(field_index, &value)) return false;
|
|
|
|
if (out_data) *out_data = details::as_string(col, value);
|
|
|
|
return true;
|
|
}
|
|
|
|
case xcl::Column_type::FLOAT: {
|
|
float value;
|
|
|
|
if (!get_float(field_index, &value)) return false;
|
|
|
|
if (out_data) *out_data = details::as_string(col, value);
|
|
|
|
return true;
|
|
}
|
|
|
|
case xcl::Column_type::BYTES: {
|
|
return get_string(field_index, out_data);
|
|
}
|
|
|
|
case xcl::Column_type::TIME: {
|
|
Time value;
|
|
|
|
if (!get_time(field_index, &value)) return false;
|
|
|
|
if (out_data) *out_data = details::as_string(col, value);
|
|
|
|
return true;
|
|
}
|
|
|
|
case xcl::Column_type::DATETIME: {
|
|
DateTime value;
|
|
|
|
if (!get_datetime(field_index, &value)) return false;
|
|
|
|
if (out_data) *out_data = details::as_string(col, value);
|
|
|
|
return true;
|
|
}
|
|
|
|
case xcl::Column_type::DECIMAL: {
|
|
Decimal value;
|
|
|
|
if (!get_decimal(field_index, &value)) return false;
|
|
|
|
if (out_data) *out_data = details::as_string(col, value);
|
|
|
|
return true;
|
|
}
|
|
|
|
case xcl::Column_type::SET: {
|
|
String_set value;
|
|
|
|
if (!get_set(field_index, &value)) return false;
|
|
|
|
if (out_data) *out_data = details::as_string(col, value);
|
|
|
|
return true;
|
|
}
|
|
|
|
case xcl::Column_type::ENUM: {
|
|
return get_enum(field_index, out_data);
|
|
}
|
|
|
|
case xcl::Column_type::BIT: {
|
|
uint64_t value;
|
|
|
|
if (!get_bit(field_index, &value)) return false;
|
|
|
|
if (out_data) *out_data = details::as_string(col, value);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool XRow_impl::valid() const { return nullptr != m_row.get(); }
|
|
|
|
void XRow_impl::clean() { m_row.reset(); }
|
|
|
|
void XRow_impl::set_row(std::unique_ptr<Row> &&row) { m_row = std::move(row); }
|
|
|
|
bool XRow_impl::get_string_based_field(const Column_type expected_type,
|
|
const int32_t field_index,
|
|
const char **out_data,
|
|
size_t *out_data_length) const {
|
|
if (m_metadata->empty()) return false;
|
|
if (expected_type != (*m_metadata)[field_index].type) return false;
|
|
|
|
const std::string &field = m_row->field(field_index);
|
|
|
|
return row_decoder::buffer_to_string(field, out_data, out_data_length);
|
|
}
|
|
|
|
} // namespace xcl
|