clickhouse-native 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/ext/clickhouse_native/client.cpp +112 -28
  3. data/ext/clickhouse_native/extconf.rb +30 -3
  4. data/ext/clickhouse_native/vendor/clickhouse-cpp/.github/workflows/bazel.yml +120 -0
  5. data/ext/clickhouse_native/vendor/clickhouse-cpp/.github/workflows/cross-repo-bug-relay.yml +17 -0
  6. data/ext/clickhouse_native/vendor/clickhouse-cpp/.github/workflows/linux.yml +22 -23
  7. data/ext/clickhouse_native/vendor/clickhouse-cpp/.github/workflows/macos.yml +22 -21
  8. data/ext/clickhouse_native/vendor/clickhouse-cpp/.github/workflows/windows_mingw.yml +29 -36
  9. data/ext/clickhouse_native/vendor/clickhouse-cpp/.github/workflows/windows_msvc.yml +29 -36
  10. data/ext/clickhouse_native/vendor/clickhouse-cpp/.gitignore +6 -0
  11. data/ext/clickhouse_native/vendor/clickhouse-cpp/AI_POLICY.md +13 -0
  12. data/ext/clickhouse_native/vendor/clickhouse-cpp/BUILD.bazel +167 -0
  13. data/ext/clickhouse_native/vendor/clickhouse-cpp/CMakeLists.txt +2 -1
  14. data/ext/clickhouse_native/vendor/clickhouse-cpp/MODULE.bazel +17 -0
  15. data/ext/clickhouse_native/vendor/clickhouse-cpp/MODULE.bazel.lock +503 -0
  16. data/ext/clickhouse_native/vendor/clickhouse-cpp/README.md +32 -6
  17. data/ext/clickhouse_native/vendor/clickhouse-cpp/ci/docker-compose/config.xml +53 -0
  18. data/ext/clickhouse_native/vendor/clickhouse-cpp/ci/docker-compose/users.xml +35 -0
  19. data/ext/clickhouse_native/vendor/clickhouse-cpp/ci/docker-compose.yml +22 -0
  20. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/CMakeLists.txt +11 -0
  21. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/base/sslsocket.cpp +24 -0
  22. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/block.cpp +1 -1
  23. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/block.h +2 -1
  24. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/client.cpp +293 -136
  25. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/client.h +31 -2
  26. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/array.cpp +12 -0
  27. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/array.h +17 -7
  28. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/bool.cpp +79 -0
  29. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/bool.h +62 -0
  30. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/factory.cpp +16 -0
  31. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/itemview.cpp +2 -0
  32. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/itemview.h +6 -2
  33. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/json.cpp +102 -0
  34. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/json.h +82 -0
  35. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/lowcardinality.cpp +2 -1
  36. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/string.cpp +7 -2
  37. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/tuple.cpp +48 -5
  38. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/tuple.h +14 -1
  39. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/query.h +2 -2
  40. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/server_exception.h +0 -3
  41. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/types/type_parser.cpp +43 -0
  42. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/types/type_parser.h +9 -0
  43. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/types/types.cpp +61 -11
  44. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/types/types.h +18 -2
  45. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/version.h +1 -1
  46. data/lib/clickhouse_native/logging.rb +4 -4
  47. data/lib/clickhouse_native/pool.rb +8 -8
  48. data/lib/clickhouse_native/version.rb +1 -1
  49. data/lib/clickhouse_native.rb +1 -0
  50. metadata +15 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d1bf3fdd8bd132c0d19937f50055f56b5ab55f4bf383fafc63a74131ff435545
4
- data.tar.gz: 4e6f233a2e250ee5c2c6c1e46ebf9a961416b69553aee7c2018afea619c1abab
3
+ metadata.gz: d3e2cb4cbe829d9afd7e30e0ac29ea828020896c93634852b4baef007348d3b0
4
+ data.tar.gz: e5f13079f4de6e64e545f49736a8da6832de954dfe82f1a4d105dd1228680887
5
5
  SHA512:
6
- metadata.gz: a79cba4fd6ad33b75ec2eecadf87ec0e9fc163ff46874b2ad687f6d767405f7357fffe04a1af584a6716d0c1dcc3ba7171b201a46b130c327d87e3b5e04c52ad
7
- data.tar.gz: 7ed472036327f17efceda43eac9f41cf7e6675e267711de5f974b2b75de88fcc5e557e7290ef1b0f00b084573fc4a8a5a88e49875d0b4fb83237302262b418f4
6
+ metadata.gz: 9998240b8ca84a4d28ad1fb956c0bf92e1893d4a9ce024fa443eefaa01efb35b657b55d8c2ce92718fd9224a5167fe0201a955f7147ab7499560a331906e2567
7
+ data.tar.gz: d097a39e1fa03b051a30fe1fb273a928b7e2e555e05945d32b22a9dd9dc1deaf280193b80ecae146d7d442d513bbfb6e638ba4b63589f5a58171ce4b25ba5b87
@@ -7,6 +7,7 @@
7
7
  #include <clickhouse/columns/decimal.h>
8
8
  #include <clickhouse/columns/enum.h>
9
9
  #include <clickhouse/columns/factory.h>
10
+ #include <clickhouse/columns/json.h>
10
11
  #include <clickhouse/columns/lowcardinality.h>
11
12
  #include <clickhouse/columns/map.h>
12
13
  #include <clickhouse/columns/numeric.h>
@@ -188,6 +189,17 @@ static VALUE value_at(const ColumnRef& col, size_t idx, const std::string& decla
188
189
  return rb_utf8_str_new(sv.data(), sv.size());
189
190
  }
190
191
 
192
+ case Type::JSON: {
193
+ // clickhouse-cpp's ColumnJSON is string-backed (it relies on the
194
+ // server's output_format_native_write_json_as_string). Decode the
195
+ // raw JSON text into a Ruby object so a JSON column reads back like
196
+ // Map does — a Hash — rather than a string the caller must re-parse.
197
+ auto sv = col->As<ColumnJSON>()->At(idx);
198
+ VALUE str = rb_utf8_str_new(sv.data(), sv.size());
199
+ VALUE rb_mJSON = rb_const_get(rb_cObject, rb_intern("JSON"));
200
+ return rb_funcall(rb_mJSON, rb_intern("parse"), 1, str);
201
+ }
202
+
191
203
  case Type::Date: {
192
204
  // Return a Ruby Date so as_json/to_s gives "YYYY-MM-DD" instead of
193
205
  // a full ISO8601 timestamp. CH Date is days since 1970-01-01 UTC.
@@ -327,6 +339,8 @@ static void append_default(const ColumnRef& col) {
327
339
  case Type::Float64: col->As<ColumnFloat64>()->Append(0); return;
328
340
  case Type::String: col->As<ColumnString>()->Append(std::string_view()); return;
329
341
  case Type::FixedString: col->As<ColumnFixedString>()->Append(std::string_view()); return;
342
+ // CH rejects an empty string as JSON; the empty value is "{}".
343
+ case Type::JSON: col->As<ColumnJSON>()->Append(std::string_view("{}")); return;
330
344
  case Type::Date: col->As<ColumnDate>()->Append(0); return;
331
345
  case Type::Date32: col->As<ColumnDate32>()->Append(0); return;
332
346
  case Type::DateTime: col->As<ColumnDateTime>()->Append(0); return;
@@ -490,6 +504,19 @@ static void append_value(const ColumnRef& col, VALUE value) {
490
504
  return;
491
505
  }
492
506
 
507
+ case Type::JSON: {
508
+ // A String is taken as already-serialized JSON text and passed
509
+ // through verbatim; anything else (Hash / Array / ...) is rendered
510
+ // via #to_json. nil is handled earlier via append_default ("{}").
511
+ VALUE str = RB_TYPE_P(value, T_STRING)
512
+ ? value
513
+ : rb_funcall(value, rb_intern("to_json"), 0);
514
+ StringValue(str);
515
+ col->As<ColumnJSON>()->Append(
516
+ std::string_view(RSTRING_PTR(str), RSTRING_LEN(str)));
517
+ return;
518
+ }
519
+
493
520
  case Type::Date: col->As<ColumnDate>()->Append(static_cast<std::time_t>(coerce_to_date_epoch(value))); return;
494
521
  case Type::Date32: col->As<ColumnDate32>()->Append(static_cast<std::time_t>(coerce_to_date_epoch(value))); return;
495
522
  case Type::DateTime: {
@@ -694,6 +721,50 @@ static CompressionMethod kwarg_compression(VALUE kwargs) {
694
721
  rb_id2name(sym));
695
722
  }
696
723
 
724
+ // Stringify a Ruby setting value for the binary protocol's QuerySettings
725
+ // payload (which is wire-string-typed). Bool maps to "1"/"0" the way the
726
+ // HTTP gem rendered it; everything else goes through #to_s.
727
+ static std::string stringify_setting_value(VALUE v) {
728
+ if (v == Qtrue) return "1";
729
+ if (v == Qfalse) return "0";
730
+ VALUE s = rb_funcall(v, rb_intern("to_s"), 0);
731
+ StringValue(s);
732
+ return std::string(RSTRING_PTR(s), RSTRING_LEN(s));
733
+ }
734
+
735
+ static int apply_settings_cb(VALUE key, VALUE val, VALUE arg) {
736
+ auto* q = reinterpret_cast<Query*>(arg);
737
+ VALUE k = SYMBOL_P(key) ? rb_sym2str(key) : key;
738
+ StringValue(k);
739
+ q->SetSetting(
740
+ std::string(RSTRING_PTR(k), RSTRING_LEN(k)),
741
+ QuerySettingsField{stringify_setting_value(val), 0});
742
+ return ST_CONTINUE;
743
+ }
744
+
745
+ // Read a `settings:` Hash out of the parsed kwargs and stamp each entry
746
+ // onto `q` as a per-query setting. No-op if kwargs is nil or settings is
747
+ // missing/empty. Raises TypeError if settings is not a Hash.
748
+ static void apply_settings(Query& q, VALUE kwargs) {
749
+ if (NIL_P(kwargs)) return;
750
+ VALUE settings = rb_hash_lookup2(kwargs, ID2SYM(rb_intern("settings")), Qnil);
751
+ if (NIL_P(settings)) return;
752
+ Check_Type(settings, T_HASH);
753
+ rb_hash_foreach(settings, apply_settings_cb, reinterpret_cast<VALUE>(&q));
754
+ }
755
+
756
+ // Same as apply_settings, but first defaults
757
+ // output_format_native_write_json_as_string=1 so JSON columns come back as
758
+ // strings (clickhouse-cpp's ColumnJSON can only read them that way). The flag
759
+ // is 0 (not "important"), so servers that don't know the setting ignore it
760
+ // instead of erroring. User-supplied settings are applied afterwards and win,
761
+ // so callers can still override it.
762
+ static void apply_read_settings(Query& q, VALUE kwargs) {
763
+ q.SetSetting("output_format_native_write_json_as_string",
764
+ QuerySettingsField{"1", 0});
765
+ apply_settings(q, kwargs);
766
+ }
767
+
697
768
  // Client.new(host:, port:, database:, user:, password:)
698
769
  static VALUE ch_client_initialize(int argc, VALUE* argv, VALUE self) {
699
770
  VALUE kwargs = Qnil;
@@ -734,7 +805,7 @@ static VALUE ch_client_initialize(int argc, VALUE* argv, VALUE self) {
734
805
  namespace {
735
806
  struct ExecuteNoGVL {
736
807
  Client* client;
737
- std::string sql;
808
+ const Query* query;
738
809
  std::exception_ptr err;
739
810
  };
740
811
  } // namespace
@@ -742,7 +813,7 @@ struct ExecuteNoGVL {
742
813
  static void* execute_no_gvl(void* data) {
743
814
  auto* a = static_cast<ExecuteNoGVL*>(data);
744
815
  try {
745
- a->client->Execute(Query(a->sql));
816
+ a->client->Execute(*a->query);
746
817
  } catch (...) {
747
818
  a->err = std::current_exception();
748
819
  }
@@ -756,12 +827,17 @@ static void execute_unblock(void* data) {
756
827
  try { a->client->ResetConnection(); } catch (...) {}
757
828
  }
758
829
 
759
- static VALUE ch_client_execute(VALUE self, VALUE rb_sql) {
830
+ static VALUE ch_client_execute(int argc, VALUE* argv, VALUE self) {
831
+ VALUE rb_sql, kwargs = Qnil;
832
+ rb_scan_args(argc, argv, "1:", &rb_sql, &kwargs);
760
833
  Check_Type(rb_sql, T_STRING);
761
834
  CHClient* c = as_client(self);
762
835
  if (!c->client) rb_raise(err_connection, "clickhouse-native: client is closed");
763
836
 
764
- ExecuteNoGVL args{c->client.get(), std::string(StringValueCStr(rb_sql)), nullptr};
837
+ Query q(std::string(RSTRING_PTR(rb_sql), RSTRING_LEN(rb_sql)));
838
+ apply_settings(q, kwargs);
839
+
840
+ ExecuteNoGVL args{c->client.get(), &q, nullptr};
765
841
  rb_thread_call_without_gvl(execute_no_gvl, &args, execute_unblock, &args);
766
842
  if (args.err) {
767
843
  // clickhouse-cpp may leave the read stream partially consumed when the
@@ -779,16 +855,19 @@ static VALUE ch_client_execute(VALUE self, VALUE rb_sql) {
779
855
  // See query_each below for a streaming, GVL-releasing variant.
780
856
  // ------------------------------------------------------------------
781
857
 
782
- static VALUE ch_client_query(VALUE self, VALUE rb_sql) {
858
+ static VALUE ch_client_query(int argc, VALUE* argv, VALUE self) {
859
+ VALUE rb_sql, kwargs = Qnil;
860
+ rb_scan_args(argc, argv, "1:", &rb_sql, &kwargs);
783
861
  Check_Type(rb_sql, T_STRING);
784
862
  CHClient* c = as_client(self);
785
863
  if (!c->client) rb_raise(err_connection, "clickhouse-native: client is closed");
786
864
 
787
- std::string sql(StringValueCStr(rb_sql));
788
865
  VALUE rows = rb_ary_new();
789
866
  try {
790
867
  std::vector<ID> col_ids;
791
- c->client->Select(sql, [&](const Block& block) {
868
+ Query q(std::string(RSTRING_PTR(rb_sql), RSTRING_LEN(rb_sql)));
869
+ apply_read_settings(q, kwargs);
870
+ q.OnData([&](const Block& block) {
792
871
  size_t ncols = block.GetColumnCount();
793
872
  size_t nrows = block.GetRowCount();
794
873
  if (nrows == 0) return;
@@ -808,6 +887,7 @@ static VALUE ch_client_query(VALUE self, VALUE rb_sql) {
808
887
  rb_ary_push(rows, h);
809
888
  }
810
889
  });
890
+ c->client->Execute(q);
811
891
  return rows;
812
892
  } catch (const std::exception& e) {
813
893
  try { c->client->ResetConnection(); } catch (...) {}
@@ -820,21 +900,25 @@ static VALUE ch_client_query(VALUE self, VALUE rb_sql) {
820
900
  // query_value — returns the first cell of the first row, or nil
821
901
  // ------------------------------------------------------------------
822
902
 
823
- static VALUE ch_client_query_value(VALUE self, VALUE rb_sql) {
903
+ static VALUE ch_client_query_value(int argc, VALUE* argv, VALUE self) {
904
+ VALUE rb_sql, kwargs = Qnil;
905
+ rb_scan_args(argc, argv, "1:", &rb_sql, &kwargs);
824
906
  Check_Type(rb_sql, T_STRING);
825
907
  CHClient* c = as_client(self);
826
908
  if (!c->client) rb_raise(err_connection, "clickhouse-native: client is closed");
827
909
 
828
- std::string sql(StringValueCStr(rb_sql));
829
910
  try {
830
911
  VALUE out = Qnil;
831
912
  bool seen = false;
832
- c->client->Select(sql, [&](const Block& block) {
913
+ Query q(std::string(RSTRING_PTR(rb_sql), RSTRING_LEN(rb_sql)));
914
+ apply_read_settings(q, kwargs);
915
+ q.OnData([&](const Block& block) {
833
916
  if (seen) return;
834
917
  if (block.GetRowCount() == 0 || block.GetColumnCount() == 0) return;
835
918
  out = value_at(block[0], 0, block.GetColumnType(0));
836
919
  seen = true;
837
920
  });
921
+ c->client->Execute(q);
838
922
  return out;
839
923
  } catch (const std::exception& e) {
840
924
  try { c->client->ResetConnection(); } catch (...) {}
@@ -958,7 +1042,7 @@ struct YieldBlockArgs {
958
1042
 
959
1043
  struct QueryEachNoGVL {
960
1044
  Client* client;
961
- std::string sql;
1045
+ const Query* query;
962
1046
  QueryEachState* state;
963
1047
  std::exception_ptr err;
964
1048
  };
@@ -1003,12 +1087,7 @@ static void* with_gvl_yield(void* data) {
1003
1087
  static void* query_each_no_gvl(void* data) {
1004
1088
  auto* a = static_cast<QueryEachNoGVL*>(data);
1005
1089
  try {
1006
- a->client->SelectCancelable(a->sql, [&](const Block& block) -> bool {
1007
- if (a->state->aborted) return false;
1008
- YieldBlockArgs ya{&block, a->state};
1009
- rb_thread_call_with_gvl(with_gvl_yield, &ya);
1010
- return !a->state->aborted;
1011
- });
1090
+ a->client->Execute(*a->query);
1012
1091
  } catch (...) {
1013
1092
  a->err = std::current_exception();
1014
1093
  }
@@ -1021,19 +1100,24 @@ static void query_each_unblock(void* data) {
1021
1100
  try { a->client->ResetConnection(); } catch (...) {}
1022
1101
  }
1023
1102
 
1024
- static VALUE ch_client_query_each(VALUE self, VALUE rb_sql) {
1103
+ static VALUE ch_client_query_each(int argc, VALUE* argv, VALUE self) {
1025
1104
  rb_need_block();
1105
+ VALUE rb_sql, kwargs = Qnil;
1106
+ rb_scan_args(argc, argv, "1:", &rb_sql, &kwargs);
1026
1107
  Check_Type(rb_sql, T_STRING);
1027
1108
  CHClient* c = as_client(self);
1028
1109
  if (!c->client) rb_raise(err_connection, "clickhouse-native: client is closed");
1029
1110
 
1030
1111
  QueryEachState state{rb_block_proc(), {}, 0, false};
1031
- QueryEachNoGVL args{
1032
- c->client.get(),
1033
- std::string(RSTRING_PTR(rb_sql), RSTRING_LEN(rb_sql)),
1034
- &state,
1035
- nullptr,
1036
- };
1112
+ Query q(std::string(RSTRING_PTR(rb_sql), RSTRING_LEN(rb_sql)));
1113
+ apply_read_settings(q, kwargs);
1114
+ q.OnDataCancelable([&state](const Block& block) -> bool {
1115
+ if (state.aborted) return false;
1116
+ YieldBlockArgs ya{&block, &state};
1117
+ rb_thread_call_with_gvl(with_gvl_yield, &ya);
1118
+ return !state.aborted;
1119
+ });
1120
+ QueryEachNoGVL args{c->client.get(), &q, &state, nullptr};
1037
1121
 
1038
1122
  rb_thread_call_without_gvl(query_each_no_gvl, &args, query_each_unblock, &args);
1039
1123
 
@@ -1139,13 +1223,13 @@ extern "C" void Init_clickhouse_native(void) {
1139
1223
  rb_define_method(rb_cClient, "initialize",
1140
1224
  reinterpret_cast<VALUE (*)(ANYARGS)>(ch_client_initialize), -1);
1141
1225
  rb_define_method(rb_cClient, "execute",
1142
- reinterpret_cast<VALUE (*)(ANYARGS)>(ch_client_execute), 1);
1226
+ reinterpret_cast<VALUE (*)(ANYARGS)>(ch_client_execute), -1);
1143
1227
  rb_define_method(rb_cClient, "query",
1144
- reinterpret_cast<VALUE (*)(ANYARGS)>(ch_client_query), 1);
1228
+ reinterpret_cast<VALUE (*)(ANYARGS)>(ch_client_query), -1);
1145
1229
  rb_define_method(rb_cClient, "query_value",
1146
- reinterpret_cast<VALUE (*)(ANYARGS)>(ch_client_query_value), 1);
1230
+ reinterpret_cast<VALUE (*)(ANYARGS)>(ch_client_query_value), -1);
1147
1231
  rb_define_method(rb_cClient, "query_each",
1148
- reinterpret_cast<VALUE (*)(ANYARGS)>(ch_client_query_each), 1);
1232
+ reinterpret_cast<VALUE (*)(ANYARGS)>(ch_client_query_each), -1);
1149
1233
  rb_define_method(rb_cClient, "insert_block",
1150
1234
  reinterpret_cast<VALUE (*)(ANYARGS)>(ch_client_insert_block), 3);
1151
1235
  rb_define_method(rb_cClient, "ping",
@@ -22,16 +22,39 @@ def fatal(msg)
22
22
  abort "clickhouse-native: cannot build extension"
23
23
  end
24
24
 
25
+ # Bundler `git:` installs don't fetch submodules unless the Gemfile sets
26
+ # `submodules: true`, which leaves vendor/clickhouse-cpp empty. When we're
27
+ # sitting in a git checkout, fetch it ourselves so the build can proceed
28
+ # without every consumer having to remember that flag. Released gems and
29
+ # `submodules: recursive` checkouts already have the tree, so this is a no-op
30
+ # there.
31
+ unless File.exist?(File.join(VENDOR, "CMakeLists.txt"))
32
+ in_git_checkout = system(
33
+ "git", "-C", EXT_DIR, "rev-parse", "--is-inside-work-tree",
34
+ out: File::NULL, err: File::NULL
35
+ )
36
+ if in_git_checkout
37
+ warn "clickhouse-native: vendored clickhouse-cpp is missing; " \
38
+ "running `git submodule update --init --recursive`…"
39
+ system("git", "-C", EXT_DIR, "submodule", "update", "--init", "--recursive")
40
+ end
41
+ end
42
+
25
43
  unless File.exist?(File.join(VENDOR, "CMakeLists.txt"))
26
44
  fatal <<~MSG
27
45
  clickhouse-cpp submodule not found at:
28
46
  #{VENDOR}
29
47
 
30
- If you cloned this gem's repo, run:
48
+ Installing from a git source? Bundler skips submodules unless you add
49
+ `submodules: true` to the gem line:
50
+
51
+ gem "clickhouse-native", git: "...", submodules: true
52
+
53
+ From a manual clone, run:
31
54
  git submodule update --init --recursive
32
55
 
33
- If you see this during `gem install`, please report a bug — the
34
- gemspec should have bundled the submodule tree.
56
+ If you see this while installing a released gem from RubyGems, please
57
+ report a bug the published .gem should bundle the submodule tree.
35
58
  MSG
36
59
  end
37
60
 
@@ -97,6 +120,10 @@ configure_args = [
97
120
  "-DBUILD_BENCHMARK=OFF",
98
121
  "-DBUILD_TESTS=OFF",
99
122
  "-DWITH_OPENSSL=OFF",
123
+ # clickhouse-cpp v2.6.2 added a distinct Bool column; this gem relies on
124
+ # Bool normalising to UInt8 (see the declared-type handling in client.cpp).
125
+ # Pin the upstream default ON so a future default flip can't break us.
126
+ "-DCH_MAP_BOOL_TO_UINT8=ON",
100
127
  "-DCMAKE_POSITION_INDEPENDENT_CODE=ON",
101
128
  "-DCMAKE_BUILD_TYPE=Release"
102
129
  ]
@@ -0,0 +1,120 @@
1
+ name: Bazel
2
+
3
+ on:
4
+ schedule:
5
+ - cron: '0 0 * * 1'
6
+ push:
7
+ branches: [ '*' ]
8
+ pull_request:
9
+ branches: [ master ]
10
+
11
+ release:
12
+ types:
13
+ - published
14
+ - prereleased
15
+
16
+ permissions:
17
+ contents: read
18
+
19
+ jobs:
20
+ build:
21
+ strategy:
22
+ fail-fast: false
23
+ matrix:
24
+ os: [ubuntu-24.04, macos-latest, windows-latest]
25
+ tls: [boringssl, openssl, 'no']
26
+
27
+ runs-on: ${{ matrix.os }}
28
+
29
+ steps:
30
+ - uses: actions/checkout@v6
31
+ with:
32
+ fetch-depth: 100
33
+ fetch-tags: true
34
+
35
+ - name: Setup Bazel
36
+ uses: bazel-contrib/setup-bazel@0.15.0
37
+ with:
38
+ bazelisk-cache: true
39
+ disk-cache: true
40
+ repository-cache: true
41
+
42
+ - name: Build project
43
+ run: bazel build //... --@clickhouse-cpp-client//:tls=${{ matrix.tls }}
44
+
45
+ - name: Run unit tests
46
+ run: bazel test //ut:unit_tests --@clickhouse-cpp-client//:tls=${{ matrix.tls }} --test_output=errors
47
+
48
+ # //ut:e2e_tests is tagged `manual`, so `bazel build //...` above
49
+ # skips it; build it explicitly so the run step below doesn't pay
50
+ # for compilation under the running-server timeout.
51
+ - name: Build e2e tests
52
+ run: bazel build //ut:e2e_tests --@clickhouse-cpp-client//:tls=${{ matrix.tls }}
53
+
54
+ # The e2e suite needs a live server on localhost:9000. Each OS starts
55
+ # one the same way the CMake build's per-OS workflows do, since hosted
56
+ # runners can't all run a Linux container the same way:
57
+ # * Linux — docker-compose (linux.yml)
58
+ # * macOS — the native ClickHouse build run as a process (macos.yml)
59
+ # * Windows — the Linux container under WSL2 + podman (windows_msvc.yml)
60
+ - name: Start ClickHouse (Linux, docker-compose)
61
+ if: runner.os == 'Linux'
62
+ uses: hoverkraft-tech/compose-action@v2.0.1
63
+ with:
64
+ compose-file: ci/docker-compose.yml
65
+ down-flags: --volumes
66
+
67
+ - name: Start ClickHouse (macOS, native binary)
68
+ if: runner.os == 'macOS'
69
+ working-directory: ${{ runner.temp }}
70
+ run: |
71
+ curl https://builds.clickhouse.com/25.12/macos-aarch64/clickhouse -o clickhouse
72
+ chmod +x ./clickhouse
73
+ sudo mkdir -p /var/lib/clickhouse /var/log/clickhouse-server
74
+ sudo chown -R "$USER" /var/lib/clickhouse /var/log/clickhouse-server
75
+ nohup ./clickhouse server --config-file="$GITHUB_WORKSPACE/ci/docker-compose/config.xml" > clickhouse.log 2>&1 &
76
+ for i in {1..60}; do
77
+ if curl -fsS http://localhost:8123/ > /dev/null; then
78
+ echo "ClickHouse is ready"
79
+ exit 0
80
+ fi
81
+ sleep 1
82
+ done
83
+ echo "ClickHouse failed to start"
84
+ tail -200 clickhouse.log || true
85
+ exit 1
86
+
87
+ - name: Enable WSL (Windows)
88
+ if: runner.os == 'Windows'
89
+ uses: Vampire/setup-wsl@v5
90
+ with:
91
+ distribution: Ubuntu-24.04
92
+ additional-packages:
93
+ podman
94
+ podman-compose
95
+
96
+ - name: Start ClickHouse (Windows, WSL + podman)
97
+ if: runner.os == 'Windows'
98
+ shell: wsl-bash {0}
99
+ run: |
100
+ cd $(wslpath -u "${{ github.workspace }}/ci/")
101
+ podman-compose up -d
102
+ timeout 60s bash -c \
103
+ 'until curl -s -o /dev/null -w "%{http_code}" http://localhost:8123 | grep -q "200"; do sleep 2; done'
104
+ curl -s http://localhost:8123/?query=SELECT%20VERSION%28%29
105
+
106
+ - name: Wait for ClickHouse (Linux)
107
+ if: runner.os == 'Linux'
108
+ run: |
109
+ for i in {1..60}; do
110
+ if curl -fsS http://localhost:8123/ > /dev/null; then
111
+ echo "ClickHouse is ready"
112
+ exit 0
113
+ fi
114
+ sleep 1
115
+ done
116
+ echo "ClickHouse failed to start"
117
+ exit 1
118
+
119
+ - name: Run e2e tests
120
+ run: bazel test //ut:e2e_tests --@clickhouse-cpp-client//:tls=${{ matrix.tls }} --test_output=errors
@@ -0,0 +1,17 @@
1
+ name: Relay bugs for cross-repo investigation
2
+
3
+ # Relays newly-opened issues to ClickHouse/integrations-ai-playground for
4
+ # cross-repo investigation.
5
+
6
+ on:
7
+ issues:
8
+ types: [opened]
9
+
10
+ permissions: {}
11
+
12
+ jobs:
13
+ relay:
14
+ uses: ClickHouse/integrations-shared-workflows/.github/workflows/cross-repo-bug-relay.yml@main
15
+ secrets:
16
+ WORKFLOW_AUTH_PUBLIC_APP_ID: ${{ secrets.WORKFLOW_AUTH_PUBLIC_APP_ID }}
17
+ WORKFLOW_AUTH_PUBLIC_PRIVATE_KEY: ${{ secrets.WORKFLOW_AUTH_PUBLIC_PRIVATE_KEY }}
@@ -15,10 +15,9 @@ on:
15
15
 
16
16
  env:
17
17
  BUILD_TYPE: Release
18
- CLICKHOUSE_SERVER_IMAGE: "clickhouse/clickhouse-server:25.10"
19
- CLICKHOUSE_SECURE_HOST: ${{ secrets.INTEGRATIONS_TEAM_TESTS_CLOUD_HOST_SMT_PROD }}
20
- CLICKHOUSE_SECURE_USER: default
21
- CLICKHOUSE_SECURE_PASSWORD: ${{ secrets.INTEGRATIONS_TEAM_TESTS_CLOUD_PASSWORD_SMT_PROD }}
18
+
19
+ permissions:
20
+ contents: read
22
21
 
23
22
  jobs:
24
23
  build:
@@ -83,7 +82,7 @@ jobs:
83
82
  runs-on: ${{matrix.os}}
84
83
 
85
84
  steps:
86
- - uses: actions/checkout@v4
85
+ - uses: actions/checkout@v6
87
86
  with:
88
87
  fetch-depth: 100
89
88
  fetch-tags: true
@@ -96,22 +95,13 @@ jobs:
96
95
  ${{matrix.COMPILER_INSTALL}} \
97
96
  ${{matrix.DEPENDENCIES_INSTALL}}
98
97
 
99
- - name: Install dependencies - Docker
100
- run: |
101
- sudo apt remove -y docker docker-engine docker.io containerd runc
102
- sudo apt install -y apt-transport-https ca-certificates curl gnupg lsb-release
103
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
104
- echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
105
- sudo apt update -q
106
- sudo apt install docker-ce docker-ce-cli containerd.io
107
- sudo docker run hello-world
108
-
109
98
  - name: Configure project
110
99
  run: |
111
100
  cmake \
112
101
  -D CMAKE_C_COMPILER=${{matrix.C_COMPILER}} \
113
102
  -D CMAKE_CXX_COMPILER=${{matrix.CXX_COMPILER}} \
114
103
  -D CMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
104
+ -D CH_MAP_BOOL_TO_UINT8=OFF \
115
105
  -D BUILD_TESTS=ON \
116
106
  ${{matrix.SSL_CMAKE_OPTION}} \
117
107
  ${{matrix.DEPENDENCIES_CMAKE_OPTIONS}} \
@@ -125,15 +115,24 @@ jobs:
125
115
  --config ${{env.BUILD_TYPE}} \
126
116
  --target all
127
117
 
128
- - name: Test - Start ClickHouse server in background
129
- run: |
130
- docker pull ${CLICKHOUSE_SERVER_IMAGE}
131
- docker run -d --name clickhouse -p 9000:9000 -e CLICKHOUSE_SKIP_USER_SETUP=1 ${CLICKHOUSE_SERVER_IMAGE}
132
- docker ps -a
133
- docker stats -a --no-stream
134
- ## Check and wait until CH is ready to accept connections
135
- docker exec clickhouse bash -c 'for i in {1..10}; do echo checking if clickhouse server is started attempt \#$i; if ( grep -q "<Information> Application: Ready for connections." /var/log/clickhouse-server/clickhouse-server.log ); then echo seems like clickhouse server is started; exit 0; fi; sleep 1; done; exit -1'
118
+ - name: Start ClickHouse in Docker
119
+ uses: hoverkraft-tech/compose-action@v2.0.1
120
+ with:
121
+ compose-file: ci/docker-compose.yml
122
+ down-flags: --volumes
136
123
 
124
+ - name: Check if ClickHouse is available
125
+ run: |
126
+ for i in {1..60}; do
127
+ if curl -fsS http://localhost:8123/ > /dev/null; then
128
+ echo "ClickHouse is ready"
129
+ exit 0
130
+ fi
131
+ sleep 1
132
+ done
133
+ echo "ClickHouse failed to start"
134
+ exit 1
135
+
137
136
  - name: Test
138
137
  working-directory: ${{github.workspace}}/build/ut
139
138
  run: ./clickhouse-cpp-ut
@@ -14,13 +14,9 @@ on:
14
14
 
15
15
  env:
16
16
  BUILD_TYPE: Release
17
- CLICKHOUSE_USER: default
18
- CLICKHOUSE_PASSWORD: ${{ secrets.INTEGRATIONS_TEAM_TESTS_CLOUD_PASSWORD_SMT_PROD }}
19
- CLICKHOUSE_SECURE_HOST: ${{ secrets.INTEGRATIONS_TEAM_TESTS_CLOUD_HOST_SMT_PROD }}
20
- CLICKHOUSE_SECURE_PORT: 9440
21
- CLICKHOUSE_SECURE_USER: default
22
- CLICKHOUSE_SECURE_PASSWORD: ${{ secrets.INTEGRATIONS_TEAM_TESTS_CLOUD_PASSWORD_SMT_PROD }}
23
- CLICKHOUSE_SECURE_DB: default
17
+
18
+ permissions:
19
+ contents: read
24
20
 
25
21
  jobs:
26
22
  build:
@@ -40,7 +36,7 @@ jobs:
40
36
  SSL_INSTALL: openssl
41
37
 
42
38
  steps:
43
- - uses: actions/checkout@v4
39
+ - uses: actions/checkout@v6
44
40
  with:
45
41
  fetch-depth: 100
46
42
  fetch-tags: true
@@ -55,6 +51,7 @@ jobs:
55
51
  run: |
56
52
  cmake \
57
53
  -D CMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
54
+ -D CH_MAP_BOOL_TO_UINT8=OFF \
58
55
  -D BUILD_TESTS=ON \
59
56
  ${{matrix.SSL_CMAKE_OPTION}} \
60
57
  -S ${{github.workspace}} \
@@ -67,21 +64,25 @@ jobs:
67
64
  --config ${{env.BUILD_TYPE}} \
68
65
  --target all
69
66
 
70
- - name: Start tls offoader proxy
71
- # that mimics non-secure clickhouse running on localhost
72
- # by tunneling queries to remote tls server
73
- # (needed because we can't start real clickhouse instance on macOS)
67
+ - name: Install and start ClickHouse
68
+ working-directory: ${{ runner.temp }}
74
69
  run: |
75
- wget https://github.com/filimonov/go-tlsoffloader/releases/download/v0.1.2/go-tlsoffloader_0.1.2_Darwin_x86_64.tar.gz
76
- tar -xvzf go-tlsoffloader_0.1.2_Darwin_x86_64.tar.gz
77
- ./go-tlsoffloader -l localhost:9000 -b ${{ secrets.INTEGRATIONS_TEAM_TESTS_CLOUD_HOST_SMT_PROD }}:9440 &
70
+ curl https://builds.clickhouse.com/25.12/macos-aarch64/clickhouse -o clickhouse
71
+ chmod +x ./clickhouse
72
+ sudo mkdir -p /var/lib/clickhouse /var/log/clickhouse-server
73
+ sudo chown -R "$USER" /var/lib/clickhouse /var/log/clickhouse-server
74
+ nohup ./clickhouse server --config-file="$GITHUB_WORKSPACE/ci/docker-compose/config.xml" > clickhouse.log 2>&1 &
75
+ for i in {1..60}; do
76
+ if curl -fsS http://localhost:8123/ > /dev/null; then
77
+ echo "ClickHouse is ready"
78
+ exit 0
79
+ fi
80
+ sleep 1
81
+ done
82
+ echo "ClickHouse failed to start"
83
+ tail -200 clickhouse.log || true
84
+ exit 1
78
85
 
79
86
  - name: Test
80
87
  working-directory: ${{github.workspace}}/build/ut
81
- env:
82
- # It is impossible to start CH server in docker on macOS due to github actions limitations,
83
- # so we use remote server to execute tests, some do not allow some features for anonymoust/free users:
84
- # - system.query_log used by 'Client/ClientCase.Query_ID' and 'Client/ClientCase.ClientName'
85
- # - system.opentelemetry_span_log is used by 'Client/ClientCase.TracingContext'
86
- GTEST_FILTER: "-Client/ClientCase.Query_ID*:Client/ClientCase.TracingContext/*:Client/ClientCase.ClientName/*"
87
88
  run: ./clickhouse-cpp-ut ${GTEST_FILTER}