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.
212 lines
6.5 KiB
C++
212 lines
6.5 KiB
C++
#pragma once
|
|
|
|
#include <datastore/base/platform.h>
|
|
#include <datastore/base/uuid.h>
|
|
|
|
#include "datastore/columns/itemview.h"
|
|
#include "datastore/query.h"
|
|
#include "utils_meta.h"
|
|
#include "utils_comparison.h"
|
|
|
|
#include <iterator>
|
|
#include <optional>
|
|
#include <ostream>
|
|
#include <ratio>
|
|
#include <string_view>
|
|
#include <system_error>
|
|
#include <type_traits>
|
|
#include <vector>
|
|
#include <cmath>
|
|
|
|
#include <time.h>
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
namespace datastore {
|
|
class Client;
|
|
class Block;
|
|
class Type;
|
|
struct ServerInfo;
|
|
struct Profile;
|
|
struct QuerySettingsField;
|
|
struct Progress;
|
|
}
|
|
|
|
template <typename ResultType = std::string>
|
|
auto getEnvOrDefault(const std::string& env, const char * default_val) {
|
|
const char* v = std::getenv(env.c_str());
|
|
if (!v && !default_val)
|
|
throw std::runtime_error("Environment var '" + env + "' is not set.");
|
|
|
|
const std::string value = v ? v : default_val;
|
|
|
|
if constexpr (std::is_same_v<ResultType, std::string>) {
|
|
return value;
|
|
} else if constexpr (std::is_integral_v<ResultType>) {
|
|
// since std::from_chars is not available on GCC-7 on linux
|
|
if constexpr (std::is_signed_v<ResultType>) {
|
|
if constexpr (sizeof(ResultType) <= sizeof(int))
|
|
return std::stoi(value);
|
|
else if constexpr (sizeof(ResultType) <= sizeof(long))
|
|
return std::stol(value);
|
|
else if constexpr (sizeof(ResultType) <= sizeof(long long))
|
|
return std::stoll(value);
|
|
} else if constexpr (std::is_unsigned_v<ResultType>) {
|
|
if constexpr (sizeof(ResultType) <= sizeof(unsigned long))
|
|
// For cases when ResultType is unsigned int.
|
|
return static_cast<ResultType>(std::stoul(value));
|
|
else if constexpr (sizeof(ResultType) <= sizeof(unsigned long long))
|
|
return std::stoull(value);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
template <typename R>
|
|
inline const char * getPrefix() {
|
|
const char * prefix = "?";
|
|
if constexpr (std::ratio_equal_v<R, std::nano>) {
|
|
prefix = "n";
|
|
} else if constexpr (std::ratio_equal_v<R, std::micro>) {
|
|
prefix = "u";
|
|
} else if constexpr (std::ratio_equal_v<R, std::milli>) {
|
|
prefix = "m";
|
|
} else if constexpr (std::ratio_equal_v<R, std::centi>) {
|
|
prefix = "c";
|
|
} else if constexpr (std::ratio_equal_v<R, std::deci>) {
|
|
prefix = "d";
|
|
} else if constexpr (std::ratio_equal_v<R, std::ratio<1, 1>>) {
|
|
prefix = "";
|
|
} else {
|
|
static_assert("Unsupported ratio");
|
|
}
|
|
|
|
return prefix;
|
|
}
|
|
|
|
template <typename T, size_t index = std::tuple_size_v<T> >
|
|
inline std::ostream & printTuple(std::ostream & ostr, [[maybe_unused]] const T & t) {
|
|
static_assert(index <= std::tuple_size_v<T>);
|
|
if constexpr (index == 0) {
|
|
return ostr << "( ";
|
|
} else {
|
|
printTuple<T, index - 1>(ostr, t);
|
|
using ElementType = std::tuple_element_t<index - 1, T>;
|
|
if constexpr (is_container_v<ElementType>) {
|
|
ostr << PrintContainer{std::get<index - 1>(t)};
|
|
} else {
|
|
ostr << std::get<0>(t);
|
|
}
|
|
if constexpr (index == std::tuple_size_v<T>) {
|
|
return ostr << " )";
|
|
} else {
|
|
return ostr << ", ";
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace std {
|
|
template <typename R, typename P>
|
|
inline ostream & operator<<(ostream & ostr, const chrono::duration<R, P> & d) {
|
|
return ostr << d.count() << ::getPrefix<P>() << "s";
|
|
}
|
|
|
|
template <typename F, typename S>
|
|
inline ostream & operator<<(ostream & ostr, const pair<F, S> & t) {
|
|
return ostr << "{ " << t.first << ", " << t.second << " }";
|
|
}
|
|
|
|
template <typename ... T>
|
|
inline ostream & operator<<(ostream & ostr, const tuple<T...> & t) {
|
|
return printTuple(ostr, t);
|
|
}
|
|
|
|
template <typename T>
|
|
inline ostream & operator<<(ostream & ostr, const optional<T> & t) {
|
|
if (t.has_value()) {
|
|
return ostr << *t;
|
|
} else {
|
|
return ostr << "NULL";
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
struct in_addr;
|
|
struct in6_addr;
|
|
// Helper for pretty-printing of the Block
|
|
struct PrettyPrintBlock {
|
|
const datastore::Block & block;
|
|
};
|
|
|
|
namespace datastore {
|
|
std::ostream& operator<<(std::ostream & ostr, const Block & block);
|
|
std::ostream& operator<<(std::ostream & ostr, const Type & type);
|
|
std::ostream & operator<<(std::ostream & ostr, const ServerInfo & server_info);
|
|
std::ostream & operator<<(std::ostream & ostr, const Profile & profile);
|
|
std::ostream & operator<<(std::ostream & ostr, const Progress & progress);
|
|
std::ostream & operator<<(std::ostream& ostr, const ItemView& item_view);
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream & ostr, const PrettyPrintBlock & block);
|
|
std::ostream& operator<<(std::ostream& ostr, const in_addr& addr);
|
|
std::ostream& operator<<(std::ostream& ostr, const in6_addr& addr);
|
|
|
|
|
|
template <typename Container>
|
|
struct PrintContainer {
|
|
const Container & container_;
|
|
|
|
explicit PrintContainer(const Container& container)
|
|
: container_(container)
|
|
{}
|
|
};
|
|
|
|
template <typename T>
|
|
std::ostream& operator<<(std::ostream & ostr, const PrintContainer<T>& print_container) {
|
|
ostr << "[";
|
|
|
|
const auto & container = print_container.container_;
|
|
for (auto i = std::begin(container); i != std::end(container); /*intentionally no ++i*/) {
|
|
const auto & elem = *i;
|
|
|
|
if constexpr (is_string_v<decltype(elem)>) {
|
|
ostr << '"' << elem << '"';
|
|
}
|
|
else if constexpr (is_container_v<std::decay_t<decltype(elem)>>) {
|
|
ostr << PrintContainer{elem};
|
|
} else {
|
|
ostr << elem;
|
|
}
|
|
|
|
if (++i != std::end(container)) {
|
|
ostr << ", ";
|
|
}
|
|
}
|
|
|
|
return ostr << "] (" << std::size(container) << " items)";
|
|
}
|
|
|
|
inline uint64_t versionNumber(
|
|
uint64_t version_major,
|
|
uint64_t version_minor,
|
|
uint64_t version_patch = 0,
|
|
uint64_t revision = 0) {
|
|
|
|
// in this case version_major can be up to 1000
|
|
static auto revision_decimal_places = 8;
|
|
static auto patch_decimal_places = 4;
|
|
static auto minor_decimal_places = 4;
|
|
|
|
auto const result = version_major * static_cast<uint64_t>(std::pow(10, minor_decimal_places + patch_decimal_places + revision_decimal_places))
|
|
+ version_minor * static_cast<uint64_t>(std::pow(10, patch_decimal_places + revision_decimal_places))
|
|
+ version_patch * static_cast<uint64_t>(std::pow(10, revision_decimal_places))
|
|
+ revision;
|
|
|
|
return result;
|
|
}
|
|
|
|
uint64_t versionNumber(const datastore::ServerInfo & server_info);
|
|
|
|
std::string ToString(const datastore::UUID& v);
|