Files
cpp/ut/itemview_ut.cpp
zeekay 286f257aae De-brand the client: clickhouse-cpp -> datastore-cpp
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.
2026-07-26 11:44:39 -07:00

237 lines
10 KiB
C++

#include <datastore/columns/itemview.h>
#include <datastore/columns/numeric.h>
#include <gtest/gtest.h>
#include "utils.h"
#include <string_view>
#include <limits>
namespace
{
using namespace datastore;
}
TEST(ItemView, StorableTypes) {
/// Validate that is it possible to store proper value of a proper type into a ItemView
/// and get it back with corresponding ItemView::get<T>
#define TEST_ITEMVIEW_TYPE_VALUE(TypeCode, NativeType, NativeValue) \
EXPECT_EQ(static_cast<NativeType>(NativeValue), ItemView(TypeCode, static_cast<NativeType>(NativeValue)).get<NativeType>()) \
<< " TypeCode:" << #TypeCode << " NativeType: " << #NativeType;
#define TEST_ITEMVIEW_TYPE_VALUES(TypeCode, NativeType) \
TEST_ITEMVIEW_TYPE_VALUE(TypeCode, NativeType, std::numeric_limits<NativeType>::min()); \
TEST_ITEMVIEW_TYPE_VALUE(TypeCode, NativeType, std::numeric_limits<NativeType>::min() + 1); \
TEST_ITEMVIEW_TYPE_VALUE(TypeCode, NativeType, -1); \
TEST_ITEMVIEW_TYPE_VALUE(TypeCode, NativeType, 0); \
TEST_ITEMVIEW_TYPE_VALUE(TypeCode, NativeType, 1); \
TEST_ITEMVIEW_TYPE_VALUE(TypeCode, NativeType, std::numeric_limits<NativeType>::max() - 1); \
TEST_ITEMVIEW_TYPE_VALUE(TypeCode, NativeType, std::numeric_limits<NativeType>::max());
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::Bool, int8_t);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::Bool, bool);
TEST_ITEMVIEW_TYPE_VALUE(Type::Code::Bool, bool, false);
TEST_ITEMVIEW_TYPE_VALUE(Type::Code::Bool, bool, true);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::Int8, int8_t);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::Int16, int16_t);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::Int32, int32_t);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::Int64, int64_t);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::Int128, Int128);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::UInt8, uint8_t);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::UInt16, uint16_t);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::UInt32, uint32_t);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::UInt64, uint64_t);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::Float32, float);
TEST_ITEMVIEW_TYPE_VALUE(Type::Code::Float32, float, 0.5);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::Float64, double);
TEST_ITEMVIEW_TYPE_VALUE(Type::Code::Float64, double, 0.5);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::Time, int32_t);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::Time64, int64_t);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::Date, uint16_t);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::DateTime, uint32_t);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::DateTime64, int64_t);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::Decimal, int32_t);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::Decimal, int64_t);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::Decimal, Int128);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::Decimal, uint32_t);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::Decimal, uint64_t);
// TEST_ITEMVIEW_TYPE_VALUES(Type::Code::Decimal, UInt128);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::Decimal32, int32_t);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::Decimal64, int64_t);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::Decimal128, Int128);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::Enum8, uint8_t);
TEST_ITEMVIEW_TYPE_VALUES(Type::Code::Enum16, uint16_t);
TEST_ITEMVIEW_TYPE_VALUE(Type::Code::String, std::string_view, "");
TEST_ITEMVIEW_TYPE_VALUE(Type::Code::String, std::string_view, "here is a string");
TEST_ITEMVIEW_TYPE_VALUE(Type::Code::FixedString, std::string_view, "");
TEST_ITEMVIEW_TYPE_VALUE(Type::Code::FixedString, std::string_view, "here is a string");
TEST_ITEMVIEW_TYPE_VALUE(Type::Code::JSON, std::string_view, "{}");
TEST_ITEMVIEW_TYPE_VALUE(Type::Code::JSON, std::string_view, R"({"key": "value"})");
}
#define EXPECT_ITEMVIEW_ERROR(TypeCode, NativeType) \
EXPECT_THROW(ItemView(TypeCode, static_cast<NativeType>(0)), AssertionError) \
<< " TypeCode:" << #TypeCode << " NativeType: " << #NativeType;
TEST(ItemView, ErrorTypes) {
// Types that is impossible to store certain Type::Code into an ItemView.
EXPECT_ITEMVIEW_ERROR(Type::Code::Array, int);
EXPECT_ITEMVIEW_ERROR(Type::Code::Nullable, int);
EXPECT_ITEMVIEW_ERROR(Type::Code::Tuple, int);
EXPECT_ITEMVIEW_ERROR(Type::Code::LowCardinality, int);
EXPECT_ITEMVIEW_ERROR(Type::Code::Map, int);
}
TEST(ItemView, TypeSizeMismatch) {
// Validate that it is impossible to initialize ItemView with mismatching Type::Code and native value.
EXPECT_ITEMVIEW_ERROR(Type::Code::Int8, int16_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Int8, int32_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Int8, int64_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Int8, Int128);
EXPECT_ITEMVIEW_ERROR(Type::Code::Int16, int8_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Int16, int32_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Int16, int64_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Int16, Int128);
EXPECT_ITEMVIEW_ERROR(Type::Code::Int32, int8_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Int32, int16_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Int32, int64_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Int32, Int128);
EXPECT_ITEMVIEW_ERROR(Type::Code::Int64, int8_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Int64, int16_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Int64, int32_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Int64, Int128);
EXPECT_ITEMVIEW_ERROR(Type::Code::Int128, int8_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Int128, int16_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Int128, int32_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Int128, int64_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::UInt8, int16_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::UInt8, int32_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::UInt8, int64_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::UInt8, Int128);
EXPECT_ITEMVIEW_ERROR(Type::Code::UInt16, int8_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::UInt16, int32_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::UInt16, int64_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::UInt16, Int128);
EXPECT_ITEMVIEW_ERROR(Type::Code::UInt32, int8_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::UInt32, int16_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::UInt32, int64_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::UInt32, Int128);
EXPECT_ITEMVIEW_ERROR(Type::Code::UInt64, int8_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::UInt64, int16_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::UInt64, int32_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::UInt64, Int128);
EXPECT_ITEMVIEW_ERROR(Type::Code::Float32, int8_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Float32, int16_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Float32, int64_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Float32, Int128);
EXPECT_ITEMVIEW_ERROR(Type::Code::Float32, double);
EXPECT_ITEMVIEW_ERROR(Type::Code::Float64, int8_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Float64, int16_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Float64, int32_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Float64, Int128);
EXPECT_ITEMVIEW_ERROR(Type::Code::Float64, float);
EXPECT_ITEMVIEW_ERROR(Type::Code::Time, int8_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Time, int16_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Time, int64_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Time, Int128);
EXPECT_ITEMVIEW_ERROR(Type::Code::Time64, int8_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Time64, int16_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Time64, int32_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Time64, Int128);
EXPECT_ITEMVIEW_ERROR(Type::Code::Date, int8_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Date, int32_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Date, int64_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Date, Int128);
EXPECT_ITEMVIEW_ERROR(Type::Code::DateTime, int8_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::DateTime, int16_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::DateTime, int64_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::DateTime, Int128);
EXPECT_ITEMVIEW_ERROR(Type::Code::DateTime64, int8_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::DateTime64, int16_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::DateTime64, int32_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::DateTime64, Int128);
EXPECT_ITEMVIEW_ERROR(Type::Code::Decimal, int8_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Decimal, int8_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Decimal32, int8_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Decimal32, int16_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Decimal32, int64_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Decimal32, Int128);
EXPECT_ITEMVIEW_ERROR(Type::Code::Decimal64, int8_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Decimal64, int16_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Decimal64, int32_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Decimal64, Int128);
EXPECT_ITEMVIEW_ERROR(Type::Code::Decimal128, int8_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Decimal128, int16_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Decimal128, int32_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Decimal128, int64_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Enum8, int16_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Enum8, int32_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Enum8, int64_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Enum8, Int128);
EXPECT_ITEMVIEW_ERROR(Type::Code::Enum16, int8_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Enum16, int32_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Enum16, int64_t);
EXPECT_ITEMVIEW_ERROR(Type::Code::Enum16, Int128);
}
TEST(ItemView, Int128_values) {
const auto vals = {
std::numeric_limits<Int128>::min() + 2,
std::numeric_limits<Int128>::min() + 1,
std::numeric_limits<Int128>::min(),
absl::MakeInt128(0xffffffffffffffffll - 2, 0),
absl::MakeInt128(0xffffffffffffffffll - 1, 0),
absl::MakeInt128(0xffffffffffffffffll, 0),
absl::MakeInt128(0xffffffffffffffffll, 0xffffffffffffffffll),
absl::MakeInt128(0, 0xffffffffffffffffll - 2),
absl::MakeInt128(0, 0xffffffffffffffffll - 1),
absl::MakeInt128(0, 0xffffffffffffffffll),
Int128(-1),
Int128(0),
Int128(1),
std::numeric_limits<Int128>::max() - 2,
std::numeric_limits<Int128>::max() - 1,
std::numeric_limits<Int128>::max(),
};
for (size_t i = 0; i < vals.size(); ++i)
{
const auto value = vals.begin()[i];
const ItemView item_view(Type::Code::Decimal128, value);
EXPECT_EQ(value, item_view.get<Int128>()) << "# index: " << i << " Int128 value: " << value;
}
}