blob: b15fd450f2db3475a0b9ea4ee5883da3717ef906 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#define _USE_MATH_DEFINES
#include <cmath>
#include "binary_tuple_builder.h"
#include "binary_tuple_parser.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <cstring>
#include <optional>
#include <random>
#include <string>
#include <tuple>
#include <type_traits>
#include <vector>
using namespace std::string_literals;
using namespace ignite;
/** A set of binary values for a whole or partial row. */
using tuple_view = std::vector<bytes_view>;
template<typename T>
T get_value(bytes_view data) {
T res;
if constexpr (std::is_same<T, std::int8_t>::value) {
res = binary_tuple_parser::get_int8(data);
} else if constexpr (std::is_same<T, std::int16_t>::value) {
res = binary_tuple_parser::get_int16(data);
} else if constexpr (std::is_same<T, std::int32_t>::value) {
res = binary_tuple_parser::get_int32(data);
} else if constexpr (std::is_same<T, std::int64_t>::value) {
res = binary_tuple_parser::get_int64(data);
} else if constexpr (std::is_same<T, float>::value) {
res = binary_tuple_parser::get_float(data);
} else if constexpr (std::is_same<T, double>::value) {
res = binary_tuple_parser::get_double(data);
} else if constexpr (std::is_same<T, big_integer>::value) {
res = binary_tuple_parser::get_number(data);
} else if constexpr (std::is_same<T, ignite_date>::value) {
res = binary_tuple_parser::get_date(data);
} else if constexpr (std::is_same<T, ignite_time>::value) {
res = binary_tuple_parser::get_time(data);
} else if constexpr (std::is_same<T, ignite_date_time>::value) {
res = binary_tuple_parser::get_date_time(data);
} else if constexpr (std::is_same<T, ignite_timestamp>::value) {
res = binary_tuple_parser::get_timestamp(data);
} else if constexpr (std::is_same<T, uuid>::value) {
res = binary_tuple_parser::get_uuid(data);
} else if constexpr (std::is_same<T, std::string>::value) {
res = std::string(binary_tuple_parser::get_varlen(data));
} else if constexpr (std::is_same<T, big_decimal>::value) {
res = big_decimal(binary_tuple_parser::get_decimal(data));
} else if constexpr (std::is_same<T, bool>::value) {
res = binary_tuple_parser::get_bool(data);
} else if constexpr (std::is_same<T, ignite_period>::value) {
res = binary_tuple_parser::get_period(data);
} else if constexpr (std::is_same<T, ignite_duration>::value) {
res = binary_tuple_parser::get_duration(data);
} else {
throw std::logic_error("Type is not supported");
}
return res;
}
big_decimal get_decimal(bytes_view data, int16_t scale) {
return binary_tuple_parser::get_decimal(data, scale);
}
struct builder : binary_tuple_builder {
using binary_tuple_builder::binary_tuple_builder;
template<typename T>
void claim_value(const T &value) {
if constexpr (std::is_same<T, std::nullopt_t>::value) {
claim_null();
} else if constexpr (std::is_same<T, std::int8_t>::value) {
claim_int8(value);
} else if constexpr (std::is_same<T, std::int16_t>::value) {
claim_int16(value);
} else if constexpr (std::is_same<T, std::int32_t>::value) {
claim_int32(value);
} else if constexpr (std::is_same<T, std::int64_t>::value) {
claim_int64(value);
} else if constexpr (std::is_same<T, float>::value) {
claim_float(value);
} else if constexpr (std::is_same<T, double>::value) {
claim_double(value);
} else if constexpr (std::is_same<T, std::string>::value) {
claim_varlen(value);
} else if constexpr (std::is_same<T, big_decimal>::value || std::is_same<T, big_integer>::value) {
claim_number(value);
} else {
throw std::logic_error("Type is not supported");
}
}
template<typename T>
void append_value(const T &value) {
if constexpr (std::is_same<T, std::nullopt_t>::value) {
append_null();
} else if constexpr (std::is_same<T, std::int8_t>::value) {
append_int8(value);
} else if constexpr (std::is_same<T, std::int16_t>::value) {
append_int16(value);
} else if constexpr (std::is_same<T, std::int32_t>::value) {
append_int32(value);
} else if constexpr (std::is_same<T, std::int64_t>::value) {
append_int64(value);
} else if constexpr (std::is_same<T, float>::value) {
append_float(value);
} else if constexpr (std::is_same<T, double>::value) {
append_double(value);
} else if constexpr (std::is_same<T, std::string>::value) {
append_varlen(value);
} else if constexpr (std::is_same<T, big_decimal>::value || std::is_same<T, big_integer>::value) {
append_number(value);
} else {
throw std::logic_error("Type is not supported");
}
}
/**
* @brief Assembles and returns a tuple in binary format.
*
* @tparam Ts Types parameter pack.
* @param tupleArgs Elements to be appended to column.
* @return Byte buffer with tuple in the binary form.
*/
template<typename... Ts>
const auto &build(std::tuple<Ts...> const &tuple) {
start();
std::apply([&](auto &&...args) { ((claim_value(args)), ...); }, tuple);
layout();
std::apply([&](auto &&...args) { ((append_value(args)), ...); }, tuple);
return binary_tuple_builder::build();
}
};
struct parser : binary_tuple_parser {
using binary_tuple_parser::binary_tuple_parser;
parser(tuple_num_t num_elements, const std::vector<int8_t> &data)
: binary_tuple_parser(num_elements, {reinterpret_cast<const std::byte *>(data.data()), data.size()}) {}
tuple_view parse() {
assert(num_parsed_elements() == 0);
tuple_num_t num = num_elements();
tuple_view tuple;
tuple.reserve(num);
while (num_parsed_elements() < num) {
tuple.emplace_back(get_next());
}
return tuple;
}
};
struct single_value_check {
explicit single_value_check(binary_tuple_parser &parser)
: parser{parser} {}
binary_tuple_parser &parser;
template<typename T>
void operator()(T value) {
auto res = get_value<T>(parser.get_next());
EXPECT_EQ(value, res);
}
void operator()(std::nullopt_t /*null*/) { EXPECT_TRUE(parser.get_next().empty()); }
};
template<typename... Ts, int size>
void check_reader_writer_equality(
const std::tuple<Ts...> &values, const std::int8_t (&data)[size], bool skip_assembler_check = false) {
constexpr tuple_num_t NUM_ELEMENTS = sizeof...(Ts);
bytes_view bytes{reinterpret_cast<const std::byte *>(data), size};
if (!skip_assembler_check) {
builder ta(NUM_ELEMENTS);
bytes_view built = ta.build(values);
EXPECT_THAT(built, testing::ContainerEq(bytes));
}
binary_tuple_parser tp(NUM_ELEMENTS, bytes);
std::apply([&tp](const Ts... args) { ((single_value_check(tp)(args)), ...); }, values);
EXPECT_EQ(tp.num_elements(), tp.num_parsed_elements());
}
template<typename T>
void check_reader_writer_equality(const T &value) {
builder ta(1);
bytes_view built = ta.build(std::make_tuple(value));
binary_tuple_parser tp(1, built);
single_value_check check(tp);
check(value);
EXPECT_EQ(tp.num_elements(), tp.num_parsed_elements());
}
TEST(tuple, AllTypes) {
static constexpr tuple_num_t NUM_ELEMENTS = 17;
int8_t v1 = 1;
int16_t v2 = 2;
int32_t v3 = 3;
int64_t v4 = 4;
big_integer v5(12345);
big_decimal v6("12345.06789");
float v7 = .5f;
double v8 = .7;
ignite_date v9(2020, 12, 12);
ignite_time v10(23, 59);
ignite_date_time v11(v9, v10);
ignite_timestamp v12(100, 10000);
std::string v13("hello");
uuid v14;
std::string v15_tmp("\1\2\3"s);
bytes_view v15{reinterpret_cast<const std::byte *>(v15_tmp.data()), v15_tmp.size()};
big_decimal v16("-1");
bool v17(false);
binary_tuple_builder tb(NUM_ELEMENTS);
tb.start();
tb.claim_int8(v1);
tb.claim_int16(v2);
tb.claim_int32(v3);
tb.claim_int64(v4);
tb.claim_number(v5);
tb.claim_number(v6);
tb.claim_float(v7);
tb.claim_double(v8);
tb.claim_date(v9);
tb.claim_time(v10);
tb.claim_date_time(v11);
tb.claim_timestamp(v12);
tb.claim_varlen(v13);
tb.claim_uuid(v14);
tb.claim_varlen(v15);
tb.claim_number(v16);
tb.claim_bool(v17);
tb.layout();
tb.append_int8(v1);
tb.append_int16(v2);
tb.append_int32(v3);
tb.append_int64(v4);
tb.append_number(v5);
tb.append_number(v6);
tb.append_float(v7);
tb.append_double(v8);
tb.append_date(v9);
tb.append_time(v10);
tb.append_date_time(v11);
tb.append_timestamp(v12);
tb.append_varlen(v13);
tb.append_uuid(v14);
tb.append_varlen(v15);
tb.append_number(v16);
tb.append_bool(v17);
const std::vector<std::byte> &binary_tuple = tb.build();
binary_tuple_parser tp(NUM_ELEMENTS, binary_tuple);
EXPECT_EQ(v1, get_value<int8_t>(tp.get_next()));
EXPECT_EQ(v2, get_value<int16_t>(tp.get_next()));
EXPECT_EQ(v3, get_value<int32_t>(tp.get_next()));
EXPECT_EQ(v4, get_value<int64_t>(tp.get_next()));
EXPECT_EQ(v5, get_value<big_integer>(tp.get_next()));
EXPECT_EQ(v6, get_decimal(tp.get_next(), v6.get_scale()));
EXPECT_EQ(v7, get_value<float>(tp.get_next()));
EXPECT_EQ(v8, get_value<double>(tp.get_next()));
EXPECT_EQ(v9, get_value<ignite_date>(tp.get_next()));
EXPECT_EQ(v10, get_value<ignite_time>(tp.get_next()));
EXPECT_EQ(v11, get_value<ignite_date_time>(tp.get_next()));
EXPECT_EQ(v12, get_value<ignite_timestamp>(tp.get_next()));
EXPECT_EQ(v13, get_value<std::string>(tp.get_next()));
EXPECT_EQ(v14, get_value<uuid>(tp.get_next()));
EXPECT_EQ(v15, tp.get_next());
EXPECT_EQ(v16, get_decimal(tp.get_next(), v16.get_scale()));
EXPECT_EQ(v17, get_value<bool>(tp.get_next()));
}
TEST(tuple, AllTypesExtended) {
static constexpr tuple_num_t NUM_ELEMENTS = 19;
static constexpr std::size_t COUNT = 1000;
std::random_device rd;
std::uniform_int_distribution<short> dist;
for (std::size_t i = 0; i < COUNT; i++) {
int sign = (i % 2) ? -1 : 1;
std::string big_num;
std::string big_dec;
big_num.resize(i % 100 + 10);
big_dec.resize(i % 100 + 10);
std::generate(big_num.begin(), big_num.end(), [&]() { return '1' + (dist(rd) % 9); });
std::generate(big_dec.begin(), big_dec.end(), [&]() { return '1' + (dist(rd) % 9); });
big_dec.insert(big_dec.end() - (i % 8 + 1), '.');
if (sign == -1) {
big_num.insert(big_num.begin(), '-');
big_dec.insert(big_dec.begin(), '-');
}
std::string buffer;
buffer.resize(i % 100 + 1);
std::generate(buffer.begin(), buffer.end(), [&]() { return char(dist(rd) % 128); });
bool v1 = (i % 2 == 0);
int8_t v2 = int8_t(i % std::numeric_limits<int8_t>::max()) * sign;
int16_t v3 = int16_t(i * i % std::numeric_limits<int16_t>::max()) * sign;
int32_t v4 = int32_t(i * i * i % std::numeric_limits<int32_t>::max()) * sign;
int64_t v5 = int64_t(i * i * i * i) * sign;
float v6 = float(i) * float(i) * M_PI * sign;
double v7 = double(i) * double(i) * M_PI * sign;
big_decimal v8(big_dec);
ignite_date v9(i % 10000, i % 12 + 1, i % 28 + 1);
ignite_time v10(i % 24, i % 60, i % 60, i % 1000000000);
ignite_date_time v11(v9, v10);
ignite_timestamp v12(i, i % 1000000000);
uuid v13(i, i << 1);
bytes_view v14(reinterpret_cast<std::byte *>(buffer.data()), buffer.size());
std::string v15(buffer.data(), buffer.size());
ignite_period v16(i, i, i);
ignite_duration v17(i, i % 1000000000);
big_integer v18(big_num);
binary_tuple_builder tb(NUM_ELEMENTS);
tb.start();
tb.claim_null();
tb.claim_bool(v1);
tb.claim_int8(v2);
tb.claim_int16(v3);
tb.claim_int32(v4);
tb.claim_int64(v5);
tb.claim_float(v6);
tb.claim_double(v7);
tb.claim_number(v8);
tb.claim_date(v9);
tb.claim_time(v10);
tb.claim_date_time(v11);
tb.claim_timestamp(v12);
tb.claim_uuid(v13);
tb.claim_varlen(v14);
tb.claim_varlen(v15);
tb.claim_period(v16);
tb.claim_duration(v17);
tb.claim_number(v18);
tb.layout();
tb.append_null();
tb.append_bool(v1);
tb.append_int8(v2);
tb.append_int16(v3);
tb.append_int32(v4);
tb.append_int64(v5);
tb.append_float(v6);
tb.append_double(v7);
tb.append_number(v8);
tb.append_date(v9);
tb.append_time(v10);
tb.append_date_time(v11);
tb.append_timestamp(v12);
tb.append_uuid(v13);
tb.append_varlen(v14);
tb.append_varlen(v15);
tb.append_period(v16);
tb.append_duration(v17);
tb.append_number(v18);
const std::vector<std::byte> &binary_tuple = tb.build();
binary_tuple_parser tp(NUM_ELEMENTS, binary_tuple);
EXPECT_EQ(bytes_view{}, tp.get_next());
EXPECT_EQ(v1, get_value<bool>(tp.get_next()));
EXPECT_EQ(v2, get_value<int8_t>(tp.get_next()));
EXPECT_EQ(v3, get_value<int16_t>(tp.get_next()));
EXPECT_EQ(v4, get_value<int32_t>(tp.get_next()));
EXPECT_EQ(v5, get_value<int64_t>(tp.get_next()));
EXPECT_EQ(v6, get_value<float>(tp.get_next()));
EXPECT_EQ(v7, get_value<double>(tp.get_next()));
EXPECT_EQ(v8, get_value<big_decimal>(tp.get_next()));
EXPECT_EQ(v9, get_value<ignite_date>(tp.get_next()));
EXPECT_EQ(v10, get_value<ignite_time>(tp.get_next()));
EXPECT_EQ(v11, get_value<ignite_date_time>(tp.get_next()));
EXPECT_EQ(v12, get_value<ignite_timestamp>(tp.get_next()));
EXPECT_EQ(v13, get_value<uuid>(tp.get_next()));
EXPECT_EQ(v14, tp.get_next());
EXPECT_EQ(v15, get_value<std::string>(tp.get_next()));
EXPECT_EQ(v16, get_value<ignite_period>(tp.get_next()));
EXPECT_EQ(v17, get_value<ignite_duration>(tp.get_next()));
EXPECT_EQ(v18, get_value<big_integer>(tp.get_next()));
}
}
TEST(tuple, TwoFixedValues) { // NOLINT(cert-err58-cpp)
{
auto values = std::make_tuple<int32_t, int32_t>(33, -71);
int8_t binary[] = {0, 1, 2, 33, -71};
check_reader_writer_equality(values, binary);
}
{
auto values = std::make_tuple(int32_t{77}, std::nullopt);
int8_t binary[] = {0, 1, 1, 77};
check_reader_writer_equality(values, binary);
}
}
TEST(tuple, FixedAndVarlenValue) { // NOLINT(cert-err58-cpp)
{
auto values = std::make_tuple(int16_t{-33}, std::string{"val"});
int8_t binary[] = {0, 1, 4, -33, 118, 97, 108};
check_reader_writer_equality(values, binary);
}
{
auto values = std::make_tuple(int16_t{33}, std::nullopt);
int8_t binary[] = {0, 1, 1, 33};
check_reader_writer_equality(values, binary);
}
}
TEST(tuple, TwoVarlenValues) { // NOLINT(cert-err58-cpp)
// With key and value.
{
auto values = std::make_tuple("key"s, "val"s);
int8_t binary[] = {0, 3, 6, 107, 101, 121, 118, 97, 108};
check_reader_writer_equality(values, binary);
}
// Null key.
{
auto values = std::make_tuple(std::nullopt, "val"s);
int8_t binary[] = {0, 0, 3, 118, 97, 108};
check_reader_writer_equality(values, binary);
}
// Null value.
{
auto values = std::make_tuple("key"s, std::nullopt);
int8_t binary[] = {0, 3, 3, 107, 101, 121};
check_reader_writer_equality(values, binary);
}
// Null both.
{
auto values = std::make_tuple(std::nullopt, std::nullopt);
int8_t binary[] = {0, 0, 0};
check_reader_writer_equality(values, binary);
}
}
TEST(tuple, VarlenEmptyEscape) {
// Empty value.
{
auto values = std::make_tuple("key"s, ""s);
int8_t binary[] = {0, 3, 4, 107, 101, 121, -128};
check_reader_writer_equality(values, binary);
}
// Normal non-empty value.
{
auto values = std::make_tuple("key"s, "\xff"s);
int8_t binary[] = {0, 3, 4, 107, 101, 121, -1};
check_reader_writer_equality(values, binary);
}
// Clashing non-empty value.
{
auto values = std::make_tuple("key"s, "\x80"s);
int8_t binary[] = {0, 3, 5, 107, 101, 121, -128, -128};
check_reader_writer_equality(values, binary);
}
// Another clashing non-empty value.
{
auto values = std::make_tuple("key"s, "\x80\xff"s);
int8_t binary[] = {0, 3, 6, 107, 101, 121, -128, -128, -1};
check_reader_writer_equality(values, binary);
}
}
TEST(tuple, FourMixedValues) { // NOLINT(cert-err58-cpp)
// With value.
{
auto values = std::make_tuple(int16_t{33}, std::string{"keystr"}, int32_t{73}, std::string{"valstr"});
int8_t binary[] = {0, 1, 7, 8, 14, 33, 107, 101, 121, 115, 116, 114, 73, 118, 97, 108, 115, 116, 114};
check_reader_writer_equality(values, binary);
}
// Null value.
{
auto values = std::make_tuple(int16_t{33}, std::string{"keystr2"}, std::nullopt, std::nullopt);
int8_t binary[] = {0, 1, 8, 8, 8, 33, 107, 101, 121, 115, 116, 114, 50};
check_reader_writer_equality(values, binary);
}
}
TEST(tuple, FixedNullableColumns) { // NOLINT(cert-err58-cpp)
// Last column null.
{
auto values = std::make_tuple(int8_t{11}, int16_t{22}, std::nullopt, int8_t{-44}, int16_t{-66}, std::nullopt);
int8_t binary[] = {0, 1, 2, 2, 3, 4, 4, 11, 22, -44, -66};
check_reader_writer_equality(values, binary);
}
// First column null.
{
auto values = std::make_tuple(std::nullopt, int16_t{22}, int32_t{33}, std::nullopt, int16_t{-55}, int32_t{-66});
int8_t binary[] = {0, 0, 1, 2, 2, 3, 4, 22, 33, -55, -66};
check_reader_writer_equality(values, binary);
}
// Middle column null.
{
auto values = std::make_tuple(int8_t{11}, std::nullopt, int32_t{33}, int8_t{-44}, std::nullopt, int32_t{-66});
int8_t binary[] = {0, 1, 1, 2, 3, 3, 4, 11, 33, -44, -66};
check_reader_writer_equality(values, binary);
}
// All columns null.
{
auto values =
std::make_tuple(std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt);
int8_t binary[] = {0, 0, 0, 0, 0, 0, 0};
check_reader_writer_equality(values, binary);
}
}
TEST(tuple, VarlenNullableColumns) { // NOLINT(cert-err58-cpp)
// Last column null.
{
auto values = std::make_tuple("abc"s, "ascii"s, std::nullopt, "yz"s, "我愛Java"s, std::nullopt);
int8_t binary[] = {0, 3, 8, 8, 10, 20, 20, 97, 98, 99, 97, 115, 99, 105, 105, 121, 122, -26, -120, -111, -26,
-124, -101, 74, 97, 118, 97};
check_reader_writer_equality(values, binary);
}
// First column null.
{
auto values = std::make_tuple(std::nullopt, "ascii"s, "我愛Java"s, std::nullopt, "我愛Java"s, "ascii"s);
int8_t binary[] = {0, 0, 5, 15, 15, 25, 30, 97, 115, 99, 105, 105, -26, -120, -111, -26, -124, -101, 74, 97,
118, 97, -26, -120, -111, -26, -124, -101, 74, 97, 118, 97, 97, 115, 99, 105, 105};
check_reader_writer_equality(values, binary);
}
// Middle column null.
{
auto values = std::make_tuple("abc"s, std::nullopt, "我愛Java"s, "yz"s, std::nullopt, "ascii"s);
int8_t binary[] = {0, 3, 3, 13, 15, 15, 20, 97, 98, 99, -26, -120, -111, -26, -124, -101, 74, 97, 118, 97, 121,
122, 97, 115, 99, 105, 105};
check_reader_writer_equality(values, binary);
}
// All columns null.
{
auto values =
std::make_tuple(std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt);
int8_t binary[] = {0, 0, 0, 0, 0, 0, 0};
check_reader_writer_equality(values, binary);
}
}
TEST(tuple, FixedAndVarlenNullableColumns) { // NOLINT(cert-err58-cpp)
// Check null/non-null all fixed/varlen.
{
auto values = std::make_tuple(
int8_t{11}, int16_t{22}, std::nullopt, std::nullopt, std::nullopt, std::nullopt, "yz"s, "ascii"s);
int8_t binary[] = {0, 1, 2, 2, 2, 2, 2, 4, 9, 11, 22, 121, 122, 97, 115, 99, 105, 105};
check_reader_writer_equality(values, binary);
}
// Check null/non-null single fixed.
{
auto values =
std::make_tuple(std::nullopt, int16_t{22}, "ab"s, "我愛Java"s, int8_t{55}, std::nullopt, "yz"s, "ascii"s);
int8_t binary[] = {0, 0, 1, 3, 13, 14, 14, 16, 21, 22, 97, 98, -26, -120, -111, -26, -124, -101, 74, 97, 118,
97, 55, 121, 122, 97, 115, 99, 105, 105};
check_reader_writer_equality(values, binary);
}
// Check null/non-null single varlen.
{
auto values = std::make_tuple(
int8_t{11}, int16_t{22}, std::nullopt, "我愛Java"s, int8_t{55}, int16_t{66}, "yz"s, std::nullopt);
int8_t binary[] = {0, 1, 2, 2, 12, 13, 14, 16, 16, 11, 22, -26, -120, -111, -26, -124, -101, 74, 97, 118, 97,
55, 66, 121, 122};
check_reader_writer_equality(values, binary);
}
// Check null/non-null mixed.
{
auto values = std::make_tuple(
int8_t{11}, std::nullopt, std::nullopt, "我愛Java"s, std::nullopt, int16_t{22}, "yz"s, std::nullopt);
int8_t binary[] = {
0, 1, 1, 1, 11, 11, 12, 14, 14, 11, -26, -120, -111, -26, -124, -101, 74, 97, 118, 97, 22, 121, 122};
check_reader_writer_equality(values, binary);
}
// Check all null/non-null.
{
auto values = std::make_tuple(
int8_t{11}, int16_t{22}, "ab"s, "我愛Java"s, std::nullopt, std::nullopt, std::nullopt, std::nullopt);
int8_t binary[] = {
0, 1, 2, 4, 14, 14, 14, 14, 14, 11, 22, 97, 98, -26, -120, -111, -26, -124, -101, 74, 97, 118, 97};
check_reader_writer_equality(values, binary);
}
}
TEST(tuple, ZeroLengthVarlen) { // NOLINT(cert-err58-cpp)
// Single zero-length vector of bytes.
{
auto values = std::make_tuple(int32_t{0}, ""s);
int8_t binary[] = {0, 1, 2, 0, -128};
check_reader_writer_equality(values, binary);
}
// Two zero-length vectors of bytes.
{
auto values = std::make_tuple(int32_t{0}, ""s, ""s);
int8_t binary[] = {0, 1, 2, 3, 0, -128, -128};
check_reader_writer_equality(values, binary);
}
// Two zero-length vectors of bytes and single integer value.
{
auto values = std::make_tuple(int32_t{0}, int32_t{123}, ""s, ""s);
int8_t binary[] = {0, 1, 2, 3, 4, 0, 123, -128, -128};
check_reader_writer_equality(values, binary);
}
}
TEST(tuple, SingleVarlen) { // NOLINT(cert-err58-cpp)
auto values = std::make_tuple(int32_t{0}, "\1\2\3"s);
int8_t binary[] = {0, 1, 4, 0, 1, 2, 3};
check_reader_writer_equality(values, binary);
}
TEST(tuple, TinyVarlenFormatOverflowLarge) { // NOLINT(cert-err58-cpp)
static constexpr tuple_num_t NUM_ELEMENTS = 301;
// Flags - 1 zero byte;
// Varlen table - 1 byte for key column + 300 bytes for value columns;
// Key - 1 zero byte.
std::vector<std::byte> reference(303);
std::fill(reference.begin() + 1, reference.end() - 1, std::byte{1});
binary_tuple_parser tp(NUM_ELEMENTS, {reinterpret_cast<std::byte *>(reference.data()), reference.size()});
auto first = tp.get_next();
EXPECT_EQ(1, first.size());
EXPECT_EQ(0, get_value<int8_t>(first));
for (int i = 1; i < NUM_ELEMENTS; i++) {
auto next = tp.get_next();
EXPECT_TRUE(next.empty());
}
}
TEST(tuple, TinyVarlenFormatOverflowMedium) { // NOLINT(cert-err58-cpp)
static constexpr tuple_num_t NUM_ELEMENTS = 301;
// Flags - 1 zero byte;
// Varlen table - 301 bytes;
// Key - 1 zero byte;
// Varlen values - 3 bytes.
std::vector<int8_t> reference(306);
reference[1] = 1;
reference[2] = 2;
reference[3] = 3;
reference[4] = 4;
// Offsets for zero-length arrays.
for (int i = 0; i < 300 - 3; i++) {
reference[5 + i] = 4;
}
// Non-empty arrays:
reference[303] = 1;
reference[304] = 2;
reference[305] = 3;
binary_tuple_parser tp(NUM_ELEMENTS, {reinterpret_cast<std::byte *>(reference.data()), reference.size()});
auto first = tp.get_next();
EXPECT_EQ(1, first.size());
EXPECT_EQ(0, get_value<int8_t>(first));
for (int i = 1; i <= 3; i++) {
auto next = tp.get_next();
EXPECT_EQ(1, next.size());
EXPECT_EQ(i, get_value<int8_t>(next));
}
for (tuple_num_t i = 4; i < NUM_ELEMENTS; i++) {
auto next = tp.get_next();
EXPECT_EQ(0, next.size());
}
}
// Check same binaries that used in testExpectedVarlenTupleBinaries java side test.
TEST(tuple, ExpectedVarlenTupleBinaries) { // NOLINT(cert-err58-cpp)
static constexpr tuple_num_t NUM_ELEMENTS = 7;
// clang-format off
std::vector<int8_t> binary_tiny {
// Flags.
0,
// Offsets for values.
4, 8, 12, 16, 21, 24, 27,
// Key - integer zero.
0, 0, 0, 0,
// Integer values - 1, 2, 3.
1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0,
// Byte[] value.
1, 2, 3, 4, 5,
// Byte[] value.
1, 2, 3,
// String "abc".
97, 98, 99};
// clang-format on
tuple_view tiny = parser(NUM_ELEMENTS, binary_tiny).parse();
EXPECT_EQ(4, tiny[0].size());
EXPECT_EQ(0, get_value<int32_t>(tiny[0]));
EXPECT_EQ(4, tiny[1].size());
EXPECT_EQ(1, get_value<int32_t>(tiny[1]));
EXPECT_EQ(4, tiny[2].size());
EXPECT_EQ(2, get_value<int32_t>(tiny[2]));
EXPECT_EQ(4, tiny[3].size());
EXPECT_EQ(3, get_value<int32_t>(tiny[3]));
bytes_view varlen = tiny[4];
EXPECT_EQ(5, varlen.size());
EXPECT_EQ(1, std::to_integer<int>(varlen[0]));
EXPECT_EQ(2, std::to_integer<int>(varlen[1]));
EXPECT_EQ(3, std::to_integer<int>(varlen[2]));
EXPECT_EQ(4, std::to_integer<int>(varlen[3]));
EXPECT_EQ(5, std::to_integer<int>(varlen[4]));
varlen = tiny[5];
EXPECT_EQ(3, varlen.size());
EXPECT_EQ(1, std::to_integer<int>(varlen[0]));
EXPECT_EQ(2, std::to_integer<int>(varlen[1]));
EXPECT_EQ(3, std::to_integer<int>(varlen[2]));
varlen = tiny[6];
EXPECT_EQ(3, varlen.size());
std::string str(varlen);
EXPECT_EQ("abc", str);
// Make data that doesn't fit to tiny format tuple but fits to medium format tuple.
std::vector<int8_t> medium_value(256 * 2);
for (size_t i = 0; i < medium_value.size(); i++) {
medium_value[i] = (int8_t) ((i * 127) % 256);
}
// Construct reference tuple binary independently of tuple assembler.
// clang-format off
std::vector<int8_t> binary_medium {
// Flags.
1,
// Offsets for values.
4, 0, 8, 0, 12, 0, 16, 0, 21, 0,
int8_t(21 + medium_value.size()), int8_t((21 + medium_value.size()) >> 8),
int8_t(24 + medium_value.size()), int8_t((24 + medium_value.size()) >> 8),
// Key - integer zero.
0, 0, 0, 0,
// Integer values - 1, 2, 3.
1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0,
// Byte[] value.
1, 2, 3, 4, 5,
// Byte[] value -- skipped for now, inserted below.
// String "abc".
97, 98, 99};
// clang-format on
// Copy varlen array that does not fit to tiny format.
binary_medium.insert(binary_medium.end() - 3, medium_value.begin(), medium_value.end());
tuple_view medium = parser(NUM_ELEMENTS, binary_medium).parse();
EXPECT_EQ(4, medium[0].size());
EXPECT_EQ(0, get_value<int32_t>(medium[0]));
EXPECT_EQ(4, medium[1].size());
EXPECT_EQ(1, get_value<int32_t>(medium[1]));
EXPECT_EQ(4, medium[2].size());
EXPECT_EQ(2, get_value<int32_t>(medium[2]));
EXPECT_EQ(4, medium[3].size());
EXPECT_EQ(3, get_value<int32_t>(medium[3]));
varlen = medium[4];
EXPECT_EQ(5, varlen.size());
EXPECT_EQ(1, std::to_integer<int>(varlen[0]));
EXPECT_EQ(2, std::to_integer<int>(varlen[1]));
EXPECT_EQ(3, std::to_integer<int>(varlen[2]));
EXPECT_EQ(4, std::to_integer<int>(varlen[3]));
EXPECT_EQ(5, std::to_integer<int>(varlen[4]));
varlen = medium[5];
EXPECT_TRUE(medium_value
== std::vector<int8_t>(reinterpret_cast<const int8_t *>(varlen.data()),
reinterpret_cast<const int8_t *>(varlen.data() + varlen.size())));
varlen = medium[6];
str = std::string(varlen);
EXPECT_EQ("abc", str);
// Make data that doesn't fit to medium format tuple but fits to large format tuple.
std::vector<int8_t> large_value(64 * 2 * 1024);
for (size_t i = 0; i < large_value.size(); i++) {
large_value[i] = (int8_t) ((i * 127) % 256);
}
// Construct reference tuple binary independently of tuple assembler.
// clang-format off
std::vector<int8_t> binary_large {
// Flags.
2,
// Offsets for values.
4, 0, 0, 0, 8, 0, 0, 0, 12, 0, 0, 0, 16, 0, 0, 0, 21, 0, 0, 0,
int8_t(21 + large_value.size()), int8_t((21 + large_value.size()) >> 8),
int8_t((21 + large_value.size()) >> 16), int8_t((21 + large_value.size()) >> 24),
int8_t(24 + large_value.size()), int8_t((24 + large_value.size()) >> 8),
int8_t((24 + large_value.size()) >> 16), int8_t((24 + large_value.size()) >> 24),
// Key - integer zero.
0, 0, 0, 0,
// Integer values - 1, 2, 3.
1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0,
// Byte[] value.
1, 2, 3, 4, 5,
// Byte[] value -- skipped for now, inserted below.
// String "abc".
97, 98, 99};
// clang-format on
// Copy varlen array that does not fit to tiny and medium format.
binary_large.insert(binary_large.end() - 3, large_value.begin(), large_value.end());
tuple_view large = parser(NUM_ELEMENTS, binary_large).parse();
EXPECT_EQ(4, large[0].size());
EXPECT_EQ(0, get_value<int32_t>(large[0]));
EXPECT_EQ(4, large[1].size());
EXPECT_EQ(1, get_value<int32_t>(large[1]));
EXPECT_EQ(4, large[2].size());
EXPECT_EQ(2, get_value<int32_t>(large[2]));
EXPECT_EQ(4, large[3].size());
EXPECT_EQ(3, get_value<int32_t>(large[3]));
varlen = large[4];
EXPECT_EQ(5, varlen.size());
EXPECT_EQ(1, std::to_integer<int>(varlen[0]));
EXPECT_EQ(2, std::to_integer<int>(varlen[1]));
EXPECT_EQ(3, std::to_integer<int>(varlen[2]));
EXPECT_EQ(4, std::to_integer<int>(varlen[3]));
EXPECT_EQ(5, std::to_integer<int>(varlen[4]));
varlen = large[5];
EXPECT_TRUE(large_value
== std::vector<int8_t>(reinterpret_cast<const int8_t *>(varlen.data()),
reinterpret_cast<const int8_t *>(varlen.data() + varlen.size())));
varlen = large[6];
str = std::string(varlen);
EXPECT_EQ("abc", str);
}
TEST(tuple, StringAfterNull) {
static constexpr tuple_num_t NUM_ELEMENTS = 3;
// 101, null, "Bob"
std::vector<std::byte> tuple;
for (int i : {0, 1, 1, 4, 101, 66, 111, 98}) {
tuple.push_back(static_cast<std::byte>(i));
}
binary_tuple_parser tp(NUM_ELEMENTS, tuple);
EXPECT_EQ(101, get_value<int32_t>(tp.get_next()));
EXPECT_TRUE(tp.get_next().empty());
EXPECT_EQ("Bob", get_value<std::string>(tp.get_next()));
}
TEST(tuple, SingleValueTupleAssembler) { // NOLINT(cert-err58-cpp)
static constexpr tuple_num_t NUM_ELEMENTS = 1;
builder ta(NUM_ELEMENTS);
auto tuple = ta.build(std::tuple<int32_t>(123));
binary_tuple_parser tp(NUM_ELEMENTS, tuple);
auto slice = tp.get_next();
ASSERT_FALSE(slice.empty());
EXPECT_EQ(123, get_value<int32_t>(slice));
}
TEST(tuple, TupleWriteRead) { // NOLINT(cert-err58-cpp)
static constexpr tuple_num_t NUM_ELEMENTS = 6;
for (bool nullable : {false, true}) {
binary_tuple_builder tb(NUM_ELEMENTS);
tb.start();
tb.claim_int32(1234);
tb.claim_double(5.0);
tb.claim_int8(6);
tb.claim_int16(7);
if (nullable) {
tb.claim_null();
} else {
tb.claim_int64(8);
}
tb.claim_int8(9);
tb.layout();
tb.append_int32(1234);
tb.append_double(5.0);
tb.append_int8(6);
tb.append_int16(7);
if (nullable) {
tb.append_null();
} else {
tb.append_int64(8);
}
tb.append_int8(9);
auto &tuple = tb.build();
tuple_view t = parser(NUM_ELEMENTS, tuple).parse();
ASSERT_FALSE(t[0].empty());
EXPECT_EQ(1234, get_value<int32_t>(t[0]));
ASSERT_FALSE(t[1].empty());
EXPECT_EQ(5.0, get_value<double>(t[1]));
ASSERT_FALSE(t[2].empty());
EXPECT_EQ(6, get_value<int8_t>(t[2]));
ASSERT_FALSE(t[3].empty());
EXPECT_EQ(7, get_value<int16_t>(t[3]));
if (nullable) {
EXPECT_TRUE(t[4].empty());
} else {
ASSERT_FALSE(t[4].empty());
EXPECT_EQ(8, get_value<int64_t>(t[4]));
}
ASSERT_FALSE(t[5].empty());
EXPECT_EQ(9, get_value<int8_t>(t[5]));
}
}
TEST(tuple, Int8TupleWriteRead) { // NOLINT(cert-err58-cpp)
static constexpr tuple_num_t NUM_ELEMENTS = 6;
for (bool nullable : {false, true}) {
binary_tuple_builder tb(NUM_ELEMENTS);
tb.start();
tb.claim_int8(0);
tb.claim_int8(1);
tb.claim_int8(2);
tb.claim_int8(3);
if (nullable) {
tb.claim_null();
} else {
tb.claim_int8(4);
}
tb.claim_int8(5);
tb.layout();
tb.append_int8(0);
tb.append_int8(1);
tb.append_int8(2);
tb.append_int8(3);
if (nullable) {
tb.append_null();
} else {
tb.append_int8(4);
}
tb.append_int8(5);
auto &tuple = tb.build();
tuple_view t = parser(NUM_ELEMENTS, tuple).parse();
ASSERT_FALSE(t[0].empty());
EXPECT_EQ(0, get_value<int8_t>(t[0]));
ASSERT_FALSE(t[1].empty());
EXPECT_EQ(1, get_value<int8_t>(t[1]));
ASSERT_FALSE(t[2].empty());
EXPECT_EQ(2, get_value<int8_t>(t[2]));
ASSERT_FALSE(t[3].empty());
EXPECT_EQ(3, get_value<int8_t>(t[3]));
if (nullable) {
EXPECT_TRUE(t[4].empty());
} else {
ASSERT_FALSE(t[4].empty());
EXPECT_EQ(4, get_value<int8_t>(t[4]));
}
ASSERT_FALSE(t[5].empty());
EXPECT_EQ(5, get_value<int8_t>(t[5]));
}
}
TEST(tuple, VarlenLargeTest) { // NOLINT(cert-err58-cpp)
static constexpr tuple_num_t NUM_ELEMENTS = 3;
{
auto values = std::make_tuple(std::string(100'000, 'a'), "b"s, std::nullopt);
builder tuple_assembler(NUM_ELEMENTS);
bytes_view tuple = tuple_assembler.build(values);
binary_tuple_parser tp(NUM_ELEMENTS, tuple);
EXPECT_EQ(std::get<0>(values), get_value<std::string>(tp.get_next()));
EXPECT_EQ(std::get<1>(values), get_value<std::string>(tp.get_next()));
EXPECT_TRUE(tp.get_next().empty());
}
{
auto values = std::make_tuple(std::string(100'000, 'a'), "b"s, "c"s);
builder tuple_assembler(NUM_ELEMENTS);
bytes_view tuple = tuple_assembler.build(values);
binary_tuple_parser tp(NUM_ELEMENTS, tuple);
EXPECT_EQ(std::get<0>(values), get_value<std::string>(tp.get_next()));
EXPECT_EQ(std::get<1>(values), get_value<std::string>(tp.get_next()));
EXPECT_EQ(std::get<2>(values), get_value<std::string>(tp.get_next()));
}
{
auto values = std::make_tuple(std::nullopt, std::string(100'000, 'a'), "b"s);
builder tuple_assembler(NUM_ELEMENTS);
bytes_view tuple = tuple_assembler.build(values);
binary_tuple_parser tp(NUM_ELEMENTS, tuple);
EXPECT_TRUE(tp.get_next().empty());
EXPECT_EQ(std::get<1>(values), get_value<std::string>(tp.get_next()));
EXPECT_EQ(std::get<2>(values), get_value<std::string>(tp.get_next()));
}
}
TEST(tuple, VarlenMediumTest) { // NOLINT(cert-err58-cpp)
static constexpr tuple_num_t NUM_ELEMENTS = 301;
{
binary_tuple_builder tb(NUM_ELEMENTS);
tb.start();
tb.claim_int32(100500);
// Create a 10-char value.
std::string value("0123456789");
for (int i = 1; i < NUM_ELEMENTS; i++) {
tb.claim_varlen(value);
}
tb.layout();
tb.append_int32(100500);
for (int i = 1; i < NUM_ELEMENTS; i++) {
tb.append_varlen(value);
}
bytes_view tuple = tb.build();
// The varlen area will take (10 * 300) = 3000 bytes. So the varlen table entry will take 2 bytes.
// The flags field must be equal to log2(2) = 1.
EXPECT_EQ(std::byte{1}, tuple[0]);
binary_tuple_parser tp(NUM_ELEMENTS, tuple);
EXPECT_EQ(100500, get_value<int32_t>(tp.get_next()));
for (tuple_num_t i = 1; i < NUM_ELEMENTS; i++) {
EXPECT_EQ(value, get_value<std::string>(tp.get_next()));
}
}
{
binary_tuple_builder tb(NUM_ELEMENTS);
tb.start();
tb.claim_int32(100500);
// Create a 300-char value.
std::string value;
for (int i = 0; i < 30; i++) {
value += "0123456789";
}
for (int i = 1; i < NUM_ELEMENTS; i++) {
tb.claim_varlen(value);
}
tb.layout();
tb.append_int32(100500);
for (int i = 1; i < NUM_ELEMENTS; i++) {
tb.append_varlen(value);
}
bytes_view tuple = tb.build();
// The varlen area will take (300 * 300) = 90000 bytes. The size value does not fit to
// one or two bytes. So the varlen table entry will take 4 bytes. The flags field must
// be equal to log2(4) = 2.
EXPECT_EQ(std::byte{2}, tuple[0]);
binary_tuple_parser tp(NUM_ELEMENTS, tuple);
EXPECT_EQ(100500, get_value<int32_t>(tp.get_next()));
for (tuple_num_t i = 1; i < NUM_ELEMENTS; i++) {
EXPECT_EQ(value, get_value<std::string>(tp.get_next()));
}
}
}
class tuple_big_decimal_zeros : public testing::TestWithParam<big_decimal> {};
TEST_P(tuple_big_decimal_zeros, DecimalZerosTest) { // NOLINT(cert-err58-cpp)
int8_t binary[] = {0, 3, 0, 0, 0};
check_reader_writer_equality(std::make_tuple(GetParam()), binary);
}
INSTANTIATE_TEST_SUITE_P(zeros, tuple_big_decimal_zeros,
testing::Values(big_decimal("0"), big_decimal("-0"), big_decimal("0E1000"), big_decimal("0E-1000"), big_decimal(0L),
big_decimal(0, std::int16_t(10))));
class tuple_big_decimal : public testing::TestWithParam<big_decimal> {};
TEST_P(tuple_big_decimal, WriteReadEqualityTest) { // NOLINT(cert-err58-cpp)
check_reader_writer_equality(GetParam());
}
INSTANTIATE_TEST_SUITE_P(positive_ints, tuple_big_decimal,
testing::Values(big_decimal(1L), big_decimal(9L), big_decimal(10L), big_decimal(11L), big_decimal(19L),
big_decimal(123L), big_decimal(1234L), big_decimal(12345L), big_decimal(123456L), big_decimal(1234567L),
big_decimal(12345678L), big_decimal(123456789L), big_decimal(1234567890L), big_decimal(12345678909),
big_decimal(123456789098), big_decimal(1234567890987), big_decimal(12345678909876),
big_decimal(123456789098765), big_decimal(1234567890987654), big_decimal(12345678909876543),
big_decimal(123456789098765432), big_decimal(1234567890987654321), big_decimal(999999999999999999L),
big_decimal(999999999099999999L), big_decimal(1000000000000000000L), big_decimal(1000000000000000001L),
big_decimal(1000000005000000000L), big_decimal(INT64_MAX)));
INSTANTIATE_TEST_SUITE_P(negative_ints, tuple_big_decimal,
testing::Values(big_decimal(-1L), big_decimal(-9L), big_decimal(-10L), big_decimal(-11L), big_decimal(-19L),
big_decimal(-123L), big_decimal(-1234L), big_decimal(-12345L), big_decimal(-123456L), big_decimal(-1234567L),
big_decimal(-12345678L), big_decimal(-123456789L), big_decimal(-1234567890L), big_decimal(-12345678909),
big_decimal(-123456789098), big_decimal(-1234567890987), big_decimal(-12345678909876),
big_decimal(-123456789098765), big_decimal(-1234567890987654), big_decimal(-12345678909876543),
big_decimal(-123456789098765432), big_decimal(-1234567890987654321), big_decimal(-999999999999999999L),
big_decimal(-999999999099999999L), big_decimal(-1000000000000000000L), big_decimal(-1000000000000000001L),
big_decimal(-1000000005000000000L), big_decimal(INT64_MIN)));
INSTANTIATE_TEST_SUITE_P(strings, tuple_big_decimal,
testing::Values(big_decimal("1"), big_decimal("2"), big_decimal("9"), big_decimal("10"), big_decimal("1123"),
big_decimal("64539472569345602304"), big_decimal("2376926357280573482539570263854"),
big_decimal("4078460509739485762306457364875609364258763498578235876432589345693645872686453947256"
"93456023046037490024067294087609279"),
big_decimal("78386624911263451156418774267"), big_decimal("-65281"), big_decimal("-4278190081"),
big_decimal("-78918762577726953281363576967"), big_decimal("-43724369233562317116122583882241974163428"),
big_decimal("-123456654321"), big_decimal("5266375549962187335354865963678516735728443929239383984473"),
big_decimal("1000000000000"), big_decimal("1000000000000000000000000000"),
big_decimal("100000000000000000000000000000000000000000000000000000000000"),
big_decimal("99999999999999"), big_decimal("99999999999999999999999999999999"),
big_decimal("9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"),
big_decimal("-1"), big_decimal("-2"), big_decimal("-9"), big_decimal("-10"), big_decimal("-1123"),
big_decimal("-64539472569345602304"), big_decimal("-2376926357280573482539570263854"),
big_decimal("-407846050973948576230645736487560936425876349857823587643258934569364587268645394725"
"693456023046037490024067294087609279"),
big_decimal("-1391368497633429418536934798133412971345891865982"),
big_decimal("-78918762577726953281363576967"),
big_decimal("-1000000000000"), big_decimal("-1000000000000000000000000000"),
big_decimal("-100000000000000000000000000000000000000000000000000000000000"),
big_decimal("-99999999999999"), big_decimal("-99999999999999999999999999999999"),
big_decimal("-9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"),
big_decimal("0.1"), big_decimal("0.2"), big_decimal("0.3"), big_decimal("0.4"), big_decimal("0.5"),
big_decimal("0.6"), big_decimal("0.7"), big_decimal("0.8"), big_decimal("0.9"), big_decimal("0.01"),
big_decimal("0.001"), big_decimal("0.0001"), big_decimal("0.00001"), big_decimal("0.000001"),
big_decimal("0.0000001"),
big_decimal("0.00000000000000000000000000000000001"), big_decimal("0.10000000000000000000000000000000001"),
big_decimal("0.10101010101010101010101010101010101"), big_decimal("0.99999999999999999999999999999999999"),
big_decimal("0.79287502687354897253590684568634528762"),
big_decimal("0.00000000000000000000000000000000000000000000000000000001"),
big_decimal("0.10000000000000000000000000000000000000000000000000000001"),
big_decimal("0.1111111111111111111111111111111111111111111111111111111111"),
big_decimal("0.9999999999999999999999999999999999999999999999999999999999999999999"),
big_decimal("0.436589746389567836745873648576289634589763845768268457683762864587684635892768346589629"),
big_decimal("0."
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000001"),
big_decimal("0."
"1000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000001"),
big_decimal("0."
"1111111111111111111111111111111111111111111111111111111111111111111111111111111111111"
"11111111111111111111111111111111111111111"),
big_decimal("0."
"9999999999999999999999999999999999999999999999999999999999999999999999999999999999999"
"99999999999999999999999999999999999999999999999999"),
big_decimal("0."
"4365897463895678367458736485762896345897638457682684576837628645876846358927683465493"
"85700256032605603246580726384075680247634627357023645889629"),
big_decimal("-0.1"), big_decimal("-0.2"), big_decimal("-0.3"), big_decimal("-0.4"), big_decimal("-0.5"),
big_decimal("-0.6"), big_decimal("-0.7"), big_decimal("-0.8"), big_decimal("-0.9"), big_decimal("-0.01"),
big_decimal("-0.001"), big_decimal("-0.0001"), big_decimal("-0.00001"), big_decimal("-0.000001"),
big_decimal("-0.0000001"),
big_decimal("-0.00000000000000000000000000000000001"), big_decimal("-0.10000000000000000000000000000000001"),
big_decimal("-0.10101010101010101010101010101010101"), big_decimal("-0.99999999999999999999999999999999999"),
big_decimal("-0.79287502687354897253590684568634528762"),
big_decimal("-0.00000000000000000000000000000000000000000000000000000001"),
big_decimal("-0.10000000000000000000000000000000000000000000000000000001"),
big_decimal("-0.1111111111111111111111111111111111111111111111111111111111"),
big_decimal("-0.9999999999999999999999999999999999999999999999999999999999999999999"),
big_decimal("-0.436589746389567836745873648576289634589763845768268457683762864587684635892768346589629"),
big_decimal("-0."
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000001"),
big_decimal("-0."
"1000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000001"),
big_decimal("-0."
"1111111111111111111111111111111111111111111111111111111111111111111111111111111111111"
"11111111111111111111111111111111111111111"),
big_decimal("-0."
"9999999999999999999999999999999999999999999999999999999999999999999999999999999999999"
"99999999999999999999999999999999999999999999999999"),
big_decimal("-0."
"4365897463895678367458736485762896345897638457682684576837628645876846358927683465493"
"85700256032605603246580726384075680247634627357023645889629"),
big_decimal("1.1"), big_decimal("12.21"), big_decimal("123.321"), big_decimal("1234.4321"),
big_decimal("12345.54321"), big_decimal("123456.654321"), big_decimal("1234567.7654321"),
big_decimal("12345678.87654321"), big_decimal("123456789.987654321"), big_decimal("1234567890.0987654321"),
big_decimal("12345678909.90987654321"), big_decimal("123456789098.890987654321"),
big_decimal("1234567890987.7890987654321"), big_decimal("12345678909876.67890987654321"),
big_decimal("123456789098765.567890987654321"), big_decimal("1234567890987654.4567890987654321"),
big_decimal("12345678909876543.34567890987654321"), big_decimal("123456789098765432.234567890987654321"),
big_decimal("1234567890987654321.1234567890987654321"),
big_decimal("12345678909876543210.01234567890987654321"),
big_decimal("10000000000000000000000000000000000000000000000000000000000000."
"000000000000000000000000000000000000000000000000000000000000001"),
big_decimal("111111111111111111111111111111111111111111111111111111111111111111111."
"11111111111111111111111111111111111111111111111111111111111111"),
big_decimal("99999999999999999999999999999999999999999999999999999999999999999999."
"99999999999999999999999999999999999999999999999999999999999999999999"),
big_decimal("458796987658934265896483756892638456782376482605002747502306790283640563."
"12017054126750641065780784583204650763485718064875683468568360506340563042567"),
big_decimal("-1.1"), big_decimal("-12.21"), big_decimal("-123.321"), big_decimal("-1234.4321"),
big_decimal("-12345.54321"), big_decimal("-123456.654321"), big_decimal("-1234567.7654321"),
big_decimal("-12345678.87654321"), big_decimal("-123456789.987654321"), big_decimal("-1234567890.0987654321"),
big_decimal("-12345678909.90987654321"), big_decimal("-123456789098.890987654321"),
big_decimal("-1234567890987.7890987654321"), big_decimal("-12345678909876.67890987654321"),
big_decimal("-123456789098765.567890987654321"), big_decimal("-1234567890987654.4567890987654321"),
big_decimal("-12345678909876543.34567890987654321"), big_decimal("-123456789098765432.234567890987654321"),
big_decimal("-1234567890987654321.1234567890987654321"),
big_decimal("-12345678909876543210.01234567890987654321"),
big_decimal("-10000000000000000000000000000000000000000000000000000000000000."
"000000000000000000000000000000000000000000000000000000000000001"),
big_decimal("-111111111111111111111111111111111111111111111111111111111111111111111."
"11111111111111111111111111111111111111111111111111111111111111"),
big_decimal("-99999999999999999999999999999999999999999999999999999999999999999999."
"99999999999999999999999999999999999999999999999999999999999999999999"),
big_decimal("-458796987658934265896483756892638456782376482605002747502306790283640563."
"12017054126750641065780784583204650763485718064875683468568360506340563042567")));