chdb-ruby 0.1.0.rc.2 → 0.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 77408619eae7f84800fa14da51844d0180ea5d4cb7513d2f2c7f2c273f287787
4
- data.tar.gz: 5cff1f1590fa5a70241d1a2e1ee1068e965487c6741ad7523921b5be0a35a8e8
3
+ metadata.gz: 4b53978c961a9a237f689559adad514d7b95ad435ddfa83284bd78dbf985a339
4
+ data.tar.gz: 4d5d284e83f4f52800739f39ed2185b629182a39e10f359f3c884e4fc27c9de5
5
5
  SHA512:
6
- metadata.gz: 1a501dd7c418c3af1edd49e77e69a50b6229cd8610121d7200d5e04633c61eeafe4fc87615f24c4e6d68a99bda3daa912575a6ecf919960e1398bef253d02855
7
- data.tar.gz: 07752df52ce67356c9f32b37d6444bdcdb5d49c274d61d67e26c7752694aedcd53184a682bea3408057d217152a5584e4c71c6230559b70bf289162bcaa7744e
6
+ metadata.gz: 05d288d130263d52120d1741351e081d05c072c992b9f7f05cc91be3454b2f423971295dfb670acee179cd1905017b24ead943fc9cc67b4747f155edc6541c41
7
+ data.tar.gz: 4607787c66d0f16b3a74377d1e6e43a6cf3ab7a5aac60b27b30fccfaa2fc6a5eff09f780d611e690a9805278a5a104a99eab5f458b97718949f45446b4b5ccb3
data/README.md CHANGED
@@ -20,69 +20,111 @@ Note that this module is only compatible with ChDB 3.0.0 or newer.
20
20
 
21
21
  ## Quick start
22
22
 
23
- ``` ruby
23
+ Before using chdb-ruby, install the gem first. This will download the libchdb C++ library dependencies, so please be patient:
24
+ ```bash
25
+ gem install chdb-ruby
26
+ ```
27
+
28
+ Below are examples of common interfaces usage:
29
+
30
+ ```ruby
24
31
  require 'chdb'
25
32
 
26
33
  # Open a database
27
- db = ChDB::Database.new('test_db', results_as_hash: true)
34
+ # Parameter explanation:
35
+ # 1. path supports two formats:
36
+ # - ":memory:" in-memory temporary database (data destroyed on close)
37
+ # - "file:/path/to/db" file-based persistent database
38
+ # Configuration parameters can be appended via URL-style query (e.g. 'file:test.db?results_as_hash=true')
39
+ # 2. options hash supports:
40
+ # - results_as_hash: controls whether result sets return as hashes (default: arrays)
41
+ db = ChDB::Database.new('file:test.db', results_as_hash: true)
42
+
43
+ # Create a database
44
+ db.execute('CREATE DATABASE IF NOT EXISTS test')
28
45
 
29
46
  # Create a table
47
+ db.execute('DROP TABLE IF EXISTS test.test_table')
30
48
  rows = db.execute <<-SQL
31
- CREATE TABLE test_table(
49
+ CREATE TABLE test.test_table(
32
50
  id Int32,
33
51
  name String)
34
52
  ENGINE = MergeTree()
35
- ORDER BY id);
53
+ ORDER BY id
36
54
  SQL
37
55
 
38
56
  # Execute a few inserts
39
57
  {
40
- 1 => 'Alice',
41
- 2 => 'Bob'
58
+ 1 => 'Alice',
59
+ 2 => 'Bob'
42
60
  }.each do |pair|
43
- db.execute 'INSERT INTO test_table VALUES ( ?, ? )', pair
61
+ db.execute 'INSERT INTO test.test_table VALUES ( ?, ? )', pair
44
62
  end
45
63
 
46
64
  # Find a few rows
47
- db.execute('SELECT * FROM test_table ORDER BY id') do |row|
65
+ db.execute('SELECT * FROM test.test_table ORDER BY id') do |row|
48
66
  p row
49
67
  end
50
68
  # [{ 'id' => '1', 'name' => 'Alice' },
51
69
  # { 'id' => '2', 'name' => 'Bob' }]
52
70
 
71
+ # When you need to open another database, you must first close the previous database
72
+ db.close()
73
+
53
74
  # Open another database
54
- db = ChDB::Database.new 'test2.db'
75
+ db = ChDB::Database.new 'file:test.db'
55
76
 
56
77
  # Create another table
78
+ db.execute('DROP TABLE IF EXISTS test.test2_table')
57
79
  rows = db.execute <<-SQL
58
- CREATE TABLE test2_table(
80
+ CREATE TABLE test.test2_table(
59
81
  id Int32,
60
82
  name String)
61
83
  ENGINE = MergeTree()
62
- ORDER BY id");
84
+ ORDER BY id
63
85
  SQL
64
86
 
65
87
  # Execute inserts with parameter markers
66
- db.execute('INSERT INTO test2_table (id, name)
88
+ db.execute('INSERT INTO test.test2_table (id, name)
67
89
  VALUES (?, ?)', [3, 'Charlie'])
68
90
 
69
- db.execute2('SELECT * FROM test2_table') do |row|
91
+ # Find rows with the first row displaying column names
92
+ db.execute2('SELECT * FROM test.test2_table') do |row|
70
93
  p row
71
94
  end
72
- # [['id', 'name'], [3, 'Charlie']],
95
+ # ["id", "name"]
96
+ # ["3", "Charlie"]
97
+
98
+ # Close the database
99
+ db.close()
100
+
101
+ # Use ChDB::Database.open to automatically close the database connection:
102
+ ChDB::Database.open('file:test.db') do |db|
103
+ result = db.execute('SELECT 1')
104
+ p result.to_a # => [["1"]]
105
+ end
106
+
107
+ # Query with specific output formats (CSV, JSON, etc.):
108
+ # See more details at https://clickhouse.com/docs/interfaces/formats.
109
+ ChDB::Database.open(':memory:') do |db|
110
+ csv_data = db.query_with_format('SELECT 1 as a, 2 as b', 'CSV')
111
+ p csv_data
112
+ # "1,2\n"
113
+
114
+ json_data = db.query_with_format('SELECT 1 as a, 2 as b', 'JSON')
115
+ p json_data
116
+ end
73
117
  ```
74
118
 
75
119
  ## Thread Safety
76
120
 
77
- When using `ChDB::Database.new` to open a session, all read/write operations within that session are thread-safe. However, currently only one active session is allowed per process. Therefore, when you need to open another session, you must first close the previous session.
78
-
79
- For example, the following code is fine because only the database
80
- instance is shared among threads:
121
+ When using `ChDB::Database.new` or `ChDB::Database.open` to open a database connection, all read/write operations within that session are thread-safe. However, currently only one active database connection is allowed per process. Therefore, when you need to open another database connection, you must first close the previous connection.
122
+ **Please note that `ChDB::Database.new`, `ChDB::Database.open`, and `ChDB::Database.close` methods themselves are not thread-safe.** If used in multi-threaded environments, external synchronization must be implemented to prevent concurrent calls to these methods, which could lead to undefined behavior.
81
123
 
82
124
  ```ruby
83
125
  require 'chdb'
84
126
 
85
- db = ChDB::Database.new ":memory:'
127
+ db = ChDB::Database.new ':memory:'
86
128
 
87
129
  latch = Queue.new
88
130
 
@@ -95,6 +137,9 @@ ts = 10.times.map {
95
137
  10.times { latch << nil }
96
138
 
97
139
  p ts.map(&:value)
140
+ # [[["1"]], [["1"]], [["1"]], [["1"]], [["1"]], [["1"]], [["1"]], [["1"]], [["1"]], [["1"]]]
141
+
142
+ db.close()
98
143
  ```
99
144
 
100
145
  Other instances can be shared among threads, but they require that you provide
data/ext/chdb/chdb.c CHANGED
@@ -7,17 +7,6 @@
7
7
  #include "exception.h"
8
8
  #include "local_result.h"
9
9
 
10
- void init_chdb_constants()
11
- {
12
- VALUE mChDB = rb_define_module("ChDB");
13
- VALUE mChDBConstants = rb_define_module_under(mChDB, "Constants");
14
- VALUE mmChDBOpen = rb_define_module_under(mChDBConstants, "Open");
15
-
16
- rb_define_const(mmChDBOpen, "READONLY", INT2FIX(CHDB_OPEN_READONLY));
17
- rb_define_const(mmChDBOpen, "READWRITE", INT2FIX(CHDB_OPEN_READWRITE));
18
- rb_define_const(mmChDBOpen, "CREATE", INT2FIX(CHDB_OPEN_CREATE));
19
- }
20
-
21
10
  void Init_chdb_native()
22
11
  {
23
12
  DEBUG_PRINT("Initializing chdb extension");
@@ -2,30 +2,43 @@
2
2
 
3
3
  #include <dlfcn.h>
4
4
  #include <ruby.h>
5
-
5
+ #include "constants.h"
6
6
  #include "exception.h"
7
7
 
8
8
  void *chdb_handle = NULL;
9
9
  connect_chdb_func connect_chdb_ptr = NULL;
10
10
  close_conn_func close_conn_ptr = NULL;
11
11
  query_conn_func query_conn_ptr = NULL;
12
+ free_result_v2_func free_result_v2_ptr = NULL;
12
13
 
13
- VALUE get_chdb_rb_path(void)
14
+ VALUE get_chdb_rb_path()
14
15
  {
15
16
  VALUE chdb_module = rb_const_get(rb_cObject, rb_intern("ChDB"));
16
17
  return rb_funcall(chdb_module, rb_intern("lib_file_path"), 0);
17
18
  }
18
19
 
20
+ void close_chdb_handle()
21
+ {
22
+ if (chdb_handle)
23
+ {
24
+ dlclose(chdb_handle);
25
+ chdb_handle = NULL;
26
+ DEBUG_PRINT("Close chdb handle");
27
+ }
28
+ }
29
+
19
30
  void init_chdb_handle()
20
31
  {
21
32
  VALUE rb_path = get_chdb_rb_path();
22
33
  VALUE lib_dir = rb_file_dirname(rb_file_dirname(rb_path));
23
34
  VALUE lib_path = rb_str_cat2(lib_dir, "/lib/chdb/lib/libchdb.so");
24
- // printf("chdb.rb path from Ruby: %s\n", StringValueCStr(lib_path));
35
+
36
+ DEBUG_PRINT("chdb.rb path from Ruby: %s\n", StringValueCStr(lib_path));
25
37
 
26
38
  connect_chdb_ptr = NULL;
27
39
  close_conn_ptr = NULL;
28
40
  query_conn_ptr = NULL;
41
+ free_result_v2_ptr = NULL;
29
42
 
30
43
  chdb_handle = dlopen(RSTRING_PTR(lib_path), RTLD_LAZY | RTLD_GLOBAL);
31
44
  if (!chdb_handle)
@@ -37,13 +50,20 @@ void init_chdb_handle()
37
50
  connect_chdb_ptr = (connect_chdb_func)dlsym(chdb_handle, "connect_chdb");
38
51
  close_conn_ptr = (close_conn_func)dlsym(chdb_handle, "close_conn");
39
52
  query_conn_ptr = (query_conn_func)dlsym(chdb_handle, "query_conn");
53
+ free_result_v2_ptr = (free_result_v2_func)dlsym(chdb_handle, "free_result_v2");
40
54
 
41
- if (!connect_chdb_ptr || !close_conn_ptr || !query_conn_ptr)
55
+ if (!connect_chdb_ptr || !close_conn_ptr || !query_conn_ptr || !free_result_v2_ptr)
42
56
  {
43
- rb_raise(cChDBError, "Symbol loading failed: %s\nMissing functions: connect_chdb(%p) close_conn(%p) query_conn(%p)",
57
+ close_chdb_handle();
58
+
59
+ rb_raise(cChDBError,
60
+ "Symbol loading failed: %s\nMissing functions: connect_chdb(%p) close_conn(%p) query_conn(%p), free_result_v2(%p)",
44
61
  dlerror(),
45
62
  (void*)connect_chdb_ptr,
46
63
  (void*)close_conn_ptr,
47
- (void*)query_conn_ptr);
64
+ (void*)query_conn_ptr,
65
+ (void*)free_result_v2_ptr);
48
66
  }
49
- }
67
+
68
+ rb_set_end_proc(close_chdb_handle, 0);
69
+ }
@@ -4,13 +4,15 @@
4
4
  typedef struct chdb_conn **(*connect_chdb_func)(int, char**);
5
5
  typedef void (*close_conn_func)(struct chdb_conn**);
6
6
  typedef struct local_result_v2 *(*query_conn_func)(struct chdb_conn*, const char*, const char*);
7
+ typedef void (*free_result_v2_func)(struct local_result_v2*);
7
8
 
8
9
  extern connect_chdb_func connect_chdb_ptr;
9
10
  extern close_conn_func close_conn_ptr;
10
11
  extern query_conn_func query_conn_ptr;
12
+ extern free_result_v2_func free_result_v2_ptr;
11
13
 
12
14
  extern void *chdb_handle;
13
15
 
14
16
  void init_chdb_handle();
15
17
 
16
- #endif
18
+ #endif
@@ -6,10 +6,11 @@
6
6
  #include "include/chdb.h"
7
7
  #include "local_result.h"
8
8
 
9
- static void connection_free(void *ptr)
9
+ void connection_free(void *ptr)
10
10
  {
11
11
  Connection *conn = (Connection *)ptr;
12
- DEBUG_PRINT("Closing connection: %p", (void*)conn->c_conn);
12
+ DEBUG_PRINT("Closing connection in connection_free: %p", (void*)conn->c_conn);
13
+
13
14
  if (conn->c_conn)
14
15
  {
15
16
  close_conn_ptr(conn->c_conn);
@@ -67,7 +68,6 @@ VALUE connection_initialize(VALUE self, VALUE argc, VALUE argv)
67
68
  }
68
69
 
69
70
  xfree(c_argv);
70
- rb_gc_unregister_address(&argv);
71
71
  return self;
72
72
  }
73
73
 
@@ -93,6 +93,7 @@ VALUE connection_query(VALUE self, VALUE query, VALUE format)
93
93
  if (c_result->error_message)
94
94
  {
95
95
  VALUE error_message = rb_str_new_cstr(c_result->error_message);
96
+ free_result_v2_ptr(c_result);
96
97
  rb_raise(cChDBError, "CHDB error: %s", StringValueCStr(error_message));
97
98
  }
98
99
 
@@ -108,8 +109,9 @@ VALUE connection_close(VALUE self)
108
109
  {
109
110
  Connection *conn;
110
111
  TypedData_Get_Struct(self, Connection, &ConnectionType, conn);
112
+ DEBUG_PRINT("Closing connection in connection_close: %p", (void*)conn->c_conn);
111
113
 
112
- if (conn->c_conn)
114
+ if (conn && conn->c_conn)
113
115
  {
114
116
  close_conn_ptr(conn->c_conn);
115
117
  conn->c_conn = NULL;
@@ -0,0 +1,14 @@
1
+ #include "constants.h"
2
+
3
+ #include <ruby.h>
4
+
5
+ void init_chdb_constants()
6
+ {
7
+ VALUE mChDB = rb_define_module("ChDB");
8
+ VALUE mChDBConstants = rb_define_module_under(mChDB, "Constants");
9
+ VALUE mmChDBOpen = rb_define_module_under(mChDBConstants, "Open");
10
+
11
+ rb_define_const(mmChDBOpen, "READONLY", INT2FIX(CHDB_OPEN_READONLY));
12
+ rb_define_const(mmChDBOpen, "READWRITE", INT2FIX(CHDB_OPEN_READWRITE));
13
+ rb_define_const(mmChDBOpen, "CREATE", INT2FIX(CHDB_OPEN_CREATE));
14
+ }
data/ext/chdb/constants.h CHANGED
@@ -12,4 +12,6 @@
12
12
  #define DEBUG_PRINT(fmt, ...) ((void)0)
13
13
  #endif
14
14
 
15
+ void init_chdb_constants();
16
+
15
17
  #endif
data/ext/chdb/exception.c CHANGED
@@ -12,5 +12,6 @@ void init_exception()
12
12
  else
13
13
  {
14
14
  cChDBError = rb_define_class_under(mChDB, "Exception", rb_eStandardError);
15
+ rb_global_variable(&cChDBError);
15
16
  }
16
17
  }
@@ -2,16 +2,18 @@
2
2
 
3
3
  #include "constants.h"
4
4
  #include "include/chdb.h"
5
+ #include "chdb_handle.h"
5
6
 
6
7
  VALUE cLocalResult;
7
8
 
8
- static void local_result_free(void *ptr)
9
+ void local_result_free(void *ptr)
9
10
  {
10
11
  LocalResult *result = (LocalResult *)ptr;
11
12
  DEBUG_PRINT("Freeing LocalResult: %p", (void*)result);
12
13
  if (result->c_result)
13
14
  {
14
- free_result_v2(result->c_result);
15
+ DEBUG_PRINT("Freeing local_result_v2: %p", (void*)result->c_result);
16
+ free_result_v2_ptr(result->c_result);
15
17
  }
16
18
  free(result);
17
19
  }
@@ -23,7 +23,7 @@ module ChDB
23
23
 
24
24
  def generate_arguments # rubocop:disable Metrics/MethodLength
25
25
  args = ['clickhouse', "--path=#{@dir_path}"]
26
- excluded_keys = %i[results_as_hash readonly readwrite flags]
26
+ excluded_keys = %w[results_as_hash readonly readwrite flags]
27
27
 
28
28
  @query_params.each do |key, value|
29
29
  next if excluded_keys.include?(key)
@@ -72,8 +72,7 @@ module ChDB
72
72
  end
73
73
 
74
74
  def merge_options(options)
75
- @query_params = @query_params.merge(options)
76
- # @query_params = @query_params.merge(options.transform_keys(&:to_s))
75
+ @query_params = @query_params.merge(options.transform_keys(&:to_s))
77
76
  end
78
77
 
79
78
  def directory_path(path)
@@ -87,31 +86,29 @@ module ChDB
87
86
  end
88
87
 
89
88
  def ensure_directory_exists
90
- if @mode.nobits?(Constants::Open::CREATE)
91
- raise DirectoryNotFoundException, "Directory #{@dir_path} required" unless Dir.exist?(@dir_path)
89
+ return if Dir.exist?(@dir_path)
92
90
 
93
- return
94
- end
91
+ raise DirectoryNotFoundException, "Directory #{@dir_path} required" if @mode.nobits?(Constants::Open::CREATE)
95
92
 
96
93
  FileUtils.mkdir_p(@dir_path, mode: 0o755)
97
94
  end
98
95
 
99
96
  def check_params # rubocop:disable Metrics/MethodLength
100
97
  @mode = Constants::Open::READWRITE | Constants::Open::CREATE
101
- @mode = Constants::Open::READONLY if @query_params[:readonly]
98
+ @mode = Constants::Open::READONLY if @query_params['readonly']
102
99
 
103
- if @query_params[:readwrite]
104
- raise InvalidArgumentException, 'conflicting options: readonly and readwrite' if @query_params[:readonly]
100
+ if @query_params['readwrite']
101
+ raise InvalidArgumentException, 'conflicting options: readonly and readwrite' if @query_params['readonly']
105
102
 
106
103
  @mode = Constants::Open::READWRITE
107
104
  end
108
105
 
109
- return unless @query_params[:flags]
110
- if @query_params[:readonly] || @query_params[:readwrite]
106
+ return unless @query_params['flags']
107
+ if @query_params['readonly'] || @query_params['readwrite']
111
108
  raise InvalidArgumentException, 'conflicting options: flags with readonly and/or readwrite'
112
109
  end
113
110
 
114
- @mode = @query_params[:flags]
111
+ @mode = @query_params['flags']
115
112
  end
116
113
 
117
114
  def remove_file_prefix(str)
data/lib/chdb/database.rb CHANGED
@@ -13,6 +13,8 @@ module ChDB
13
13
  # Represents a database connection and provides methods to interact with the database.
14
14
  class Database # rubocop:disable Metrics/ClassLength
15
15
  class << self
16
+ @@instance = nil # rubocop:disable Style/ClassVars
17
+
16
18
  # Without block works exactly as new.
17
19
  # With block, like new closes the database at the end, but unlike new
18
20
  # returns the result of the block instead of the database instance.
@@ -36,16 +38,20 @@ module ChDB
36
38
  attr_accessor :results_as_hash, :conn
37
39
 
38
40
  def initialize(file, options = {}) # rubocop:disable Metrics/MethodLength
41
+ raise InternalException, 'Existing database instance is not closed' if @@instance
42
+
39
43
  file = file.to_path if file.respond_to? :to_path
40
44
 
41
45
  @data_path = DataPath.new(file, options)
42
- @results_as_hash = @data_path.query_params[:results_as_hash]
46
+ @results_as_hash = @data_path.query_params['results_as_hash'] || false
43
47
  @readonly = @data_path.mode & Constants::Open::READONLY != 0
44
48
 
45
49
  argv = @data_path.generate_arguments
46
50
  @conn = ChDB::Connection.new(argv.size, argv)
47
51
  @closed = false
48
52
 
53
+ @@instance = self # rubocop:disable Style/ClassVars
54
+
49
55
  return unless block_given?
50
56
 
51
57
  begin
@@ -61,6 +67,8 @@ module ChDB
61
67
  @data_path.close if @data_path.respond_to?(:close)
62
68
  @conn.close if @conn.respond_to?(:close)
63
69
  @closed = true
70
+
71
+ @@instance = nil # rubocop:disable Style/ClassVars
64
72
  end
65
73
 
66
74
  def closed?
@@ -111,7 +119,7 @@ module ChDB
111
119
  end
112
120
  end
113
121
 
114
- def query_with_format(sql, bind_vars = [], format = 'CSV')
122
+ def query_with_format(sql, format = 'CSV', bind_vars = [])
115
123
  result = prepare(sql).execute_with_format(bind_vars, format)
116
124
  if block_given?
117
125
  yield result
@@ -11,14 +11,8 @@ module ChDB
11
11
  def bind_params(*bind_vars)
12
12
  index = 1
13
13
  bind_vars.flatten.each do |var|
14
- if var.is_a?(Hash)
15
- # TODO: Hash-style parameter binding not yet implemented
16
- # Currently using positional parameters instead of named parameters
17
- var.each { |key, val| bind_param key, val }
18
- else
19
- bind_param index, var
20
- index += 1
21
- end
14
+ bind_param index, var
15
+ index += 1
22
16
  end
23
17
  end
24
18
  end
@@ -1,10 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'chdb/errors'
4
+
3
5
  module ChDB
4
6
  # This module provides functionality for processing SQL queries,
5
7
  # including binding variables and escaping values.
6
8
  module SQLProcessor
7
9
  def process_sql
10
+ placeholders = @sql.scan(/(?<!\\)\?/).size
11
+ if placeholders != @bind_vars.size
12
+ raise ChDB::SQLException, "Wrong number of bind variables (#{@bind_vars.size} for #{placeholders})"
13
+ end
14
+
8
15
  escaped_values = @bind_vars.map { |v| escape(v) }
9
16
  sql = @sql.dup
10
17
  sql.gsub(/(?<!\\)\?/) { escaped_values.shift or '?' }
@@ -107,8 +107,8 @@ module ChDB
107
107
  private
108
108
 
109
109
  def validate_inputs(db, sql_str)
110
- raise ArgumentError, 'SQL statement cannot be nil' if sql_str.nil?
111
- raise ArgumentError, 'prepare called on a closed database' if db.nil? || db.closed?
110
+ raise InvalidArgumentException, 'SQL statement cannot be nil' if sql_str.nil?
111
+ raise InvalidArgumentException, 'prepare called on a closed database' if db.nil? || db.closed?
112
112
  end
113
113
 
114
114
  def encode_sql(sql_str)
data/lib/chdb/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  module ChDB
4
4
  # (String) the version of the chdb gem, e.g. "0.1.0"
5
- VERSION = '0.1.0.rc.2'
5
+ VERSION = '0.1.0'
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chdb-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.rc.2
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Xiaozhe Yu
8
8
  - Auxten Wang
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-04-01 00:00:00.000000000 Z
11
+ date: 2025-04-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: csv
@@ -41,6 +41,7 @@ files:
41
41
  - ext/chdb/chdb_handle.h
42
42
  - ext/chdb/connection.c
43
43
  - ext/chdb/connection.h
44
+ - ext/chdb/constants.c
44
45
  - ext/chdb/constants.h
45
46
  - ext/chdb/exception.c
46
47
  - ext/chdb/exception.h