mirror of
https://github.com/hanzo-ds/cpp.git
synced 2026-10-30 20:31:26 +00:00
Pure rename applied on top of upstream tag v2.6.2 (8d2415d6), not HEAD.
The fork was cut at 737145d = v2.6.2-57, which still declared version 2.6.2
in version.h; renaming there would have shipped 57 unreleased commits wearing
a 2.6.2 label. Reset to the tag first so this commit changes names only.
clickhouse/ -> datastore/ (public include root)
namespace clickhouse -> namespace datastore
CLICKHOUSE_CPP_VERSION -> DATASTORE_CPP_VERSION
clickhouse-cpp-lib/-ut -> datastore-cpp-lib/-ut (CMake, Bazel)
CH_MAP_BOOL_TO_UINT8 -> DS_MAP_BOOL_TO_UINT8
CLICKHOUSE_* -> DATASTORE_* (test env vars)
doc links -> docs.hanzo.ai/datastore
This client speaks the NATIVE binary protocol only - there is no HTTP path
and no X-ClickHouse-* header anywhere in it, so the header rename that the
HTTP clients required does not apply and nothing here was broken.
The one string that reaches the wire is CLIENT_NAME, sent by both SendHello
and SendQuery's ClientInfo from a single macro, and it lands in
system.query_log.client_name. Both sites still read the one macro, so they
stay consistent and the server's Hello/Query consistency check is satisfied.
Old rows keep the old name; that is a reporting discontinuity, not a
migration, since nothing keys on it.
CI is repointed at our own server: ghcr.io/hanzoai/datastore:26.2.3.2, the
image production runs. Its entrypoint honours DATASTORE_SKIP_USER_SETUP, not
the CLICKHOUSE_ spelling the compose file used, and its config lives in
/etc/hanzo-datastore-server. ci/docker-compose/config.xml is now layered in
as a config.d drop-in so the image keeps its own white-labelling. That file
and users.xml deliberately keep a <clickhouse> root: it must match the roots
of the drop-ins the image ships, and a mismatch fails silently - the server
logs "Merging bypassed" and starts with every drop-in discarded.
The remote-TLS suites used to default to the third-party host
play.clickhouse.com. They now read DATASTORE_SECURE*_HOST and skip when it is
unset rather than point at a host we do not run.
Dropped as upstream infrastructure with no meaning here: AI_POLICY.md
(upstream's policy about their codebase), .travis.yml (dead CI referencing a
third-party apt repo), cross-repo-bug-relay.yml (relays our issues into an
upstream triage repo). LICENSE keeps its copyright notice, as Apache-2.0
requires.
Verified: cmake configure + 115-target build clean; the full suite is green
against ghcr.io/hanzoai/datastore:26.2.3.2 (894 passed, 0 failed); the
pristine v2.6.2 build run against that same server passes the identical set,
and both logged the same 3914 queries under their respective client names.
240 lines
7.3 KiB
C++
240 lines
7.3 KiB
C++
#pragma once
|
|
|
|
#include <datastore/base/socket.h> // for ipv4-ipv6 platform-specific stuff
|
|
#include <datastore/columns/numeric.h>
|
|
#include <datastore/columns/uuid.h>
|
|
|
|
#include "utils.h"
|
|
|
|
#include <vector>
|
|
#include <random>
|
|
#include <algorithm>
|
|
#include <iterator>
|
|
#include <type_traits>
|
|
|
|
inline in_addr MakeIPv4(uint32_t ip) {
|
|
static_assert(sizeof(in_addr) == sizeof(ip));
|
|
in_addr result;
|
|
memcpy(&result, &ip, sizeof(ip));
|
|
|
|
return result;
|
|
}
|
|
|
|
inline in6_addr MakeIPv6(uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3,
|
|
uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7,
|
|
uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11,
|
|
uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15) {
|
|
return in6_addr{{{v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15}}};
|
|
}
|
|
|
|
inline in6_addr MakeIPv6(uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15) {
|
|
return in6_addr{{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, v10, v11, v12, v13, v14, v15}}};
|
|
}
|
|
|
|
std::vector<uint32_t> MakeNumbers();
|
|
std::vector<uint8_t> MakeBools();
|
|
std::vector<std::string> MakeFixedStrings(size_t string_size);
|
|
std::vector<std::string> MakeStrings();
|
|
std::vector<std::string> MakeJSONs();
|
|
std::vector<datastore::Int64> MakeDateTime64s(size_t scale, size_t values_size = 200);
|
|
std::vector<int32_t> MakeDates32();
|
|
std::vector<datastore::Int64> MakeDateTimes();
|
|
std::vector<in_addr> MakeIPv4s();
|
|
std::vector<in6_addr> MakeIPv6s();
|
|
std::vector<datastore::UUID> MakeUUIDs();
|
|
std::vector<datastore::Int128> MakeInt128s();
|
|
std::vector<datastore::UInt128> MakeUInt128s();
|
|
std::vector<datastore::Int128> MakeDecimals(size_t precision, size_t scale);
|
|
|
|
template <typename T, std::enable_if_t<std::is_integral<T>::value, bool> = true>
|
|
inline std::vector<T> MakeNumbers() {
|
|
|
|
std::vector<T> result;
|
|
result.reserve(32);
|
|
|
|
// to reach from in to max in 32 steps, it also has to be lower than 7 to work for int8 values.
|
|
const T step = static_cast<T>(1) << (sizeof(T)*8 - 5);
|
|
|
|
// `- step` to avoid accidential overflow
|
|
for (T i = std::numeric_limits<T>::min(); i <= std::numeric_limits<T>::max() - step; i += step)
|
|
{
|
|
result.push_back(i);
|
|
}
|
|
result.push_back(std::numeric_limits<T>::max());
|
|
|
|
return result;
|
|
}
|
|
|
|
template <typename T, std::enable_if_t<std::is_floating_point<T>::value, bool> = true>
|
|
inline std::vector<T> MakeNumbers() {
|
|
|
|
std::vector<T> result {
|
|
std::numeric_limits<T>::min(),
|
|
std::numeric_limits<T>::max(),
|
|
std::numeric_limits<T>::quiet_NaN(),
|
|
std::numeric_limits<T>::infinity(),
|
|
-std::numeric_limits<T>::infinity(),
|
|
static_cast<T>(0),
|
|
static_cast<T>(0) + std::numeric_limits<T>::epsilon(),
|
|
static_cast<T>(0) - std::numeric_limits<T>::epsilon()
|
|
};
|
|
|
|
const auto total_steps = 100;
|
|
const auto step = std::pow(10, (std::numeric_limits<T>::max_exponent - std::numeric_limits<T>::min_exponent) / total_steps);
|
|
const auto min_value = std::pow(10, std::numeric_limits<T>::min_exponent10);
|
|
|
|
// cover most of the precision ranges
|
|
for (T i = std::numeric_limits<T>::max(); i >= min_value * step; i /= step)
|
|
{
|
|
result.push_back(i);
|
|
result.push_back(-1 * i);
|
|
}
|
|
result.push_back(min_value);
|
|
result.push_back(-min_value);
|
|
|
|
return result;
|
|
}
|
|
|
|
template <size_t size>
|
|
inline std::vector<std::string> MakeFixedStrings() {
|
|
return MakeFixedStrings(size);
|
|
}
|
|
|
|
template <size_t scale>
|
|
inline std::vector<datastore::Int64> MakeDateTime64s() {
|
|
return MakeDateTime64s(scale);
|
|
}
|
|
|
|
template <size_t precision, size_t scale>
|
|
inline std::vector<datastore::Int128> MakeDecimals() {
|
|
return MakeDecimals(precision, scale);
|
|
}
|
|
|
|
std::vector<int32_t> MakeTime();
|
|
|
|
template <size_t Precision>
|
|
inline std::vector<int64_t> MakeTime64() {
|
|
std::vector<int64_t> ret{};
|
|
auto time32 = MakeTime();
|
|
int64_t exp = 1;
|
|
for (size_t i = 0; i < Precision; ++i) {
|
|
exp *= 10;
|
|
}
|
|
std::transform(time32.cbegin(), time32.cend(), std::back_inserter(ret), [exp](int32_t x) {
|
|
return x * exp;
|
|
});
|
|
return ret;
|
|
}
|
|
|
|
template <typename ResultType>
|
|
inline auto MakeDates() {
|
|
std::vector<ResultType> result {0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536 - 1};
|
|
|
|
if constexpr (std::is_same_v<time_t, ResultType>) {
|
|
// in CH Date internally a UInt16 and stores a day number
|
|
// ColumnDate expects values to be seconds, which is then
|
|
// converted to day number internally, hence the `* 86400`.
|
|
std::for_each(result.begin(), result.end(), [](auto& value) {
|
|
value *= 86400;
|
|
});
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
template <typename ValueType, std::vector<ValueType> (*Generator)()>
|
|
inline auto MakeArrays() {
|
|
const auto nested_values = Generator();
|
|
std::vector<std::vector<ValueType>> result;
|
|
result.reserve(nested_values.size());
|
|
|
|
for (size_t i = 0; i < nested_values.size(); ++i)
|
|
{
|
|
result.emplace_back(nested_values.begin(), nested_values.begin() + i);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
std::string FooBarGenerator(size_t i);
|
|
|
|
template <typename ValueType = void, typename Generator>
|
|
auto GenerateVector(size_t items, Generator && gen) {
|
|
using ActualValueType = std::conditional_t<std::is_same_v<void, ValueType>, my_result_of_t<Generator, size_t>, ValueType>;
|
|
std::vector<ActualValueType> result;
|
|
result.reserve(items);
|
|
for (size_t i = 0; i < items; ++i) {
|
|
result.push_back(std::move(gen(i)));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
template <typename T, typename U = T>
|
|
auto SameValueGenerator(const U & value) {
|
|
return [&value](size_t) -> T {
|
|
return value;
|
|
};
|
|
}
|
|
|
|
template <typename ResultType, typename Generator1, typename Generator2>
|
|
auto AlternateGenerators(Generator1 && gen1, Generator2 && gen2) {
|
|
return [&gen1, &gen2](size_t i) -> ResultType {
|
|
if (i % 2 == 0)
|
|
return gen1(i/2);
|
|
else
|
|
return gen2(i/2);
|
|
};
|
|
}
|
|
|
|
template <typename T>
|
|
struct RandomGenerator {
|
|
using uniform_distribution =
|
|
typename std::conditional_t<std::is_floating_point_v<T>, std::uniform_real_distribution<T>,
|
|
typename std::conditional_t<std::is_integral_v<T>, std::uniform_int_distribution<T>, void>>;
|
|
|
|
explicit RandomGenerator(T seed = 0, T value_min = std::numeric_limits<T>::min(), T value_max = std::numeric_limits<T>::max())
|
|
: random_engine(seed)
|
|
, distribution(value_min, value_max)
|
|
{
|
|
}
|
|
|
|
template <typename U>
|
|
T operator()(U) {
|
|
return distribution(random_engine);
|
|
}
|
|
|
|
private:
|
|
std::default_random_engine random_engine;
|
|
uniform_distribution distribution;
|
|
};
|
|
|
|
template <typename T>
|
|
std::vector<T> ConcatSequences(std::vector<T> && vec1, std::vector<T> && vec2) {
|
|
std::vector<T> result(vec1);
|
|
|
|
result.reserve(vec1.size() + vec2.size());
|
|
result.insert(result.end(), vec2.begin(), vec2.end());
|
|
|
|
return result;
|
|
}
|
|
|
|
template <typename T>
|
|
struct FromVectorGenerator {
|
|
const std::vector<T> data;
|
|
RandomGenerator<size_t> random_generator;
|
|
|
|
FromVectorGenerator(std::vector<T> data_)
|
|
: data(std::move(data_)),
|
|
random_generator(0, 0, data.size() - 1)
|
|
{
|
|
if (data.size() == 0)
|
|
throw std::runtime_error("can't generate values from empty vector");
|
|
}
|
|
|
|
auto operator()(size_t pos) {
|
|
return data[random_generator(pos)];
|
|
}
|
|
};
|