duckdb 1.5.4.0 → 1.5.5.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: c9c37c59f2e64ac10b72765250ec674ef40e82d83a7499a6c9e1117ee8e9e9d0
4
- data.tar.gz: e9510873a0de444b35bb7c3de2d26f8d9a9ebcd01466a95383fa16d38d277e97
3
+ metadata.gz: 534e22d8df0424b7551b9ca68678d4da9f2e7a8055272dabe7c31d9f63c7b5b4
4
+ data.tar.gz: 5a1a9289dd5b20de755dd2c5c17242a353fe695ff27e47e5c862bc62004d1875
5
5
  SHA512:
6
- metadata.gz: 2ab204dc5d6034b846d3267ca78fd4d47f75f000e3d6c97e5673ca9791618c84e7130230cd1ad7634858ff25fd5cc5952bac500263ef228225767a730684749c
7
- data.tar.gz: f55e20a3dc6a97aea0606dca4b047746da44941c4f84145a48c45248d150fd58ef800ca617adc7921ae6418ac0f8275bf29e24405f3cdbf2e917377029b8641f
6
+ metadata.gz: 5afc359f5b6f5c972a34f0662e0f94360d91a12fd6a3db3e116f54eea486436c2855e0ee8f1949d8aff42c7b171e2efbeded84989b5bf335b57c7b9e7d5ee497
7
+ data.tar.gz: 7f5d628c60766814253cf9971b90f3fc1911d63d376cbce414dcff92f8e550dbccc676832435349b925c26449aa18d2dff394bd0e33d300ee1e57cc8ff8f5f5f
data/CHANGELOG.md CHANGED
@@ -4,6 +4,42 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  # Unreleased
6
6
 
7
+ # 1.5.5.0 - 2026-07-27
8
+
9
+ - bump up DuckDB 1.5.5 on CI.
10
+ - support TIME_NS columns in `DuckDB::ScalarFunction` and `DuckDB::AggregateFunction`: TIME_NS can now be used as parameter and return type (with `DuckDB::LogicalType::TIME_NS`). Requires DuckDB >= 1.5.0 for full TIME_NS support in the C API.
11
+ - bump Ruby to 3.4.10 on CI.
12
+ - add `DuckDB::Connection#table_names(sql, qualified: false)` returning the table names referenced by a SQL query without executing it (binds `duckdb_get_table_names`). With `qualified: true`, names are returned as written in the query (including schema/catalog prefixes and aliases). Result order is unspecified.
13
+ - add `DuckDB::Value.create_list(child_type, values)` and `DuckDB::Value.create_array(child_type, values)` to create LIST/ARRAY values from an element type (a Symbol like `:integer` or a `DuckDB::LogicalType`) and an Array of `DuckDB::Value` elements. The created values can be bound to prepared statements with `#bind_value`.
14
+ - add `DuckDB::Value#list_size` and `DuckDB::Value#list_child(index)` to read LIST value elements as `DuckDB::Value`.
15
+ - add `DuckDB::Value#to_ruby` converting a `DuckDB::Value` to a Ruby object. LIST/ARRAY values are converted to Ruby Arrays recursively; NULL becomes `nil`.
16
+ - add `DuckDB::Value.create_struct(struct_type, values)` to create STRUCT values from a field spec (a Hash like `{ a: :integer, b: :varchar }` or a STRUCT `DuckDB::LogicalType`) and an Array of `DuckDB::Value` field values (positional, matching field order).
17
+ - add `DuckDB::Value#struct_child(index)` to read STRUCT fields as `DuckDB::Value`. `DuckDB::Value#to_ruby` converts STRUCT values to a Hash with Symbol keys recursively.
18
+ - add `DuckDB::Value.create_map(map_type, entries)` to create MAP values from a type spec (a one-pair Hash like `{ varchar: :integer }` or a MAP `DuckDB::LogicalType`) and a Hash of `DuckDB::Value` keys to `DuckDB::Value` values.
19
+ - add `DuckDB::Value#map_size`, `#map_key(index)` and `#map_value(index)` to read MAP entries as `DuckDB::Value`. `DuckDB::Value#to_ruby` converts MAP values to a Hash recursively (keys keep their natural Ruby type).
20
+ - add `DuckDB::PreparedStatement#column_count`, `#column_name(col_index)`, `#column_type(col_index)` and `#column_logical_type(col_index)` to get the result-set column metadata of a prepared statement without executing it (column index is 0-based). Useful for PG-style statement caching where column types must be known before execution.
21
+ - add `DuckDB::Error#error_type` returning the DuckDB error category as a Symbol (e.g. `:constraint`, `:catalog`, `:parser`), or `nil` for errors not originating from a query result. Helps the ActiveRecord adapter map failures to `RecordNotUnique` / `NotNullViolation` etc. without parsing error messages.
22
+ - add `DuckDB::PreparedStatement#param_logical_type(param_index)` returning the `DuckDB::LogicalType` of a bind parameter (1-based index), giving richer type information than `#param_type` (e.g. decimal width/scale, nested types).
23
+ - add `DuckDB::Value.create_date(value)` to create DATE values from a Date, a Time, or a parseable String (same lenient input as `Appender#append_date`).
24
+ - add `DuckDB::Value.create_time(value)` to create TIME values (microsecond precision) from a Time or a parseable String.
25
+ - add `DuckDB::Value.create_time_ns(value)` to create TIME_NS values (nanosecond precision) from a Time or a parseable String. TIME_NS values are now converted to Ruby Time with full nanosecond precision (previously truncated to microseconds).
26
+ - add `DuckDB::Value.create_time_tz(value)` to create TIMETZ values from a Time (the UTC offset is taken from the Time) or a parseable String with offset.
27
+ - add `DuckDB::Value.create_timestamp(value)` to create TIMESTAMP values (microsecond precision) from a Time, a Date, or a parseable String (same lenient input as `Appender#append_timestamp`).
28
+ - add `DuckDB::Value.create_timestamp_s(value)` to create TIMESTAMP_S values (second precision; sub-second input is truncated).
29
+ - add `DuckDB::Value.create_timestamp_ms(value)` to create TIMESTAMP_MS values (millisecond precision).
30
+ - add `DuckDB::Value.create_timestamp_ns(value)` to create TIMESTAMP_NS values (nanosecond precision). TIMESTAMP_NS values (including query results) are now converted to Ruby Time with full nanosecond precision (previously truncated to microseconds).
31
+ - add `DuckDB::Value.create_timestamp_tz(value)` to create TIMESTAMP WITH TIME ZONE values; the instant is stored correctly regardless of the input UTC offset.
32
+ - add `DuckDB::Value.create_interval(value)` to create INTERVAL values from a `DuckDB::Interval`.
33
+ - add `DuckDB::Value.create_enum(enum_type, member)` to create ENUM values from an Array of member names (or an ENUM `DuckDB::LogicalType`) and a member name or 0-based index.
34
+ - `DuckDB::Value#to_ruby` converts ENUM values to the member String.
35
+ - add `DuckDB::Value.create_union(union_type, tag, value)` to create UNION values from a member spec Hash like `{ num: :integer, str: :varchar }` (or a UNION `DuckDB::LogicalType`), a member tag, and a `DuckDB::Value`. `DuckDB::Value#to_ruby` converts UNION values to the member value.
36
+ - add `DuckDB::Value.create_bit(value)` to create BIT values from a String of '0'/'1' characters.
37
+ - `DuckDB::Value#to_ruby` converts BIT values to a String of '0'/'1' characters.
38
+ - add `DuckDB::Value.create_bignum(value)` to create BIGNUM (arbitrary-precision integer) values from a Ruby Integer.
39
+ - `DuckDB::Value#to_ruby` converts BIGNUM values to a Ruby Integer.
40
+ - `DuckDB::Value#to_ruby` converts BLOB values to a BINARY-encoded String.
41
+ - `DuckDB::Value#to_ruby` converts DECIMAL values to a BigDecimal.
42
+
7
43
  # 1.5.4.0 - 2026-06-20
8
44
  - bump up DuckDB 1.5.4 and 1.4.5 on CI.
9
45
  - add experimental `DuckDB::Result#arrow_c_stream` returning `DuckDB::ArrowArrayStream` to export a query result as an Arrow C stream (Arrow C Data Interface). The stream can be consumed directly by ruby-polars (`Polars::DataFrame.new(result)`) and red-arrow (`Arrow::RecordBatchReader.import(stream.to_i)`).
data/CLAUDE.md ADDED
@@ -0,0 +1,4 @@
1
+ ## Orchestration workflow
2
+ You (Fable) are the orchestrator. Plan, decompose, synthesize.
3
+ Reasoning-heavy phases → deep-reasoner
4
+ Mechanical work → fast-worker
data/duckdb.gemspec CHANGED
@@ -32,6 +32,6 @@ Gem::Specification.new do |spec|
32
32
 
33
33
  spec.require_paths = ['lib']
34
34
  spec.extensions = ['ext/duckdb/extconf.rb']
35
- spec.required_ruby_version = '>= 3.2.0'
35
+ spec.required_ruby_version = '>= 3.3.0'
36
36
  spec.add_dependency 'bigdecimal', '>= 3.1.4'
37
37
  end
@@ -17,6 +17,7 @@ static VALUE connection__register_scalar_function_set(VALUE self, VALUE scalar_f
17
17
  static VALUE connection__register_aggregate_function(VALUE self, VALUE aggregate_function);
18
18
  static VALUE connection__register_aggregate_function_set(VALUE self, VALUE aggregate_function_set);
19
19
  static VALUE connection__register_table_function(VALUE self, VALUE table_function);
20
+ static VALUE connection__get_table_names(VALUE self, VALUE query, VALUE qualified);
20
21
 
21
22
  static const rb_data_type_t connection_data_type = {
22
23
  "DuckDB/Connection",
@@ -198,11 +199,31 @@ static VALUE connection__query_sql(VALUE self, VALUE str) {
198
199
  RB_GC_GUARD(str);
199
200
 
200
201
  if (args.retval == DuckDBError) {
201
- rb_raise(eDuckDBError, "%s", duckdb_result_error(&(ctxr->result)));
202
+ rbduckdb_raise_result_error(&(ctxr->result));
202
203
  }
203
204
  return result;
204
205
  }
205
206
 
207
+ /* :nodoc: */
208
+ static VALUE connection__get_table_names(VALUE self, VALUE query, VALUE qualified) {
209
+ rubyDuckDBConnection *ctx;
210
+ duckdb_value table_names;
211
+
212
+ ctx = rbduckdb_get_struct_connection(self);
213
+
214
+ if (!(ctx->con)) {
215
+ rb_raise(eDuckDBError, "Database connection closed");
216
+ }
217
+
218
+ table_names = duckdb_get_table_names(ctx->con, StringValueCStr(query), RTEST(qualified));
219
+
220
+ if (!table_names) {
221
+ rb_raise(eDuckDBError, "Failed to get table names from query");
222
+ }
223
+
224
+ return rbduckdb_value_new(table_names);
225
+ }
226
+
206
227
  /* :nodoc: */
207
228
  static VALUE connection__register_logical_type(VALUE self, VALUE logical_type) {
208
229
  rubyDuckDBConnection *ctxcon;
@@ -346,4 +367,5 @@ void rbduckdb_init_connection(void) {
346
367
  rb_define_private_method(cDuckDBConnection, "_register_table_function", connection__register_table_function, 1);
347
368
  rb_define_private_method(cDuckDBConnection, "_connect", connection__connect, 1);
348
369
  rb_define_private_method(cDuckDBConnection, "_query_sql", connection__query_sql, 1);
370
+ rb_define_private_method(cDuckDBConnection, "_get_table_names", connection__get_table_names, 2);
349
371
  }
data/ext/duckdb/error.c CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  VALUE eDuckDBError;
4
4
 
5
+ /* Raises DuckDB::Error from a failed result. C only reads the message and error
6
+ * type id off the result (the result is destroyed before Ruby sees it) and passes
7
+ * them to DuckDB::Error.new(message, error_type_id). */
8
+ void rbduckdb_raise_result_error(duckdb_result *result) {
9
+ const char *msg = duckdb_result_error(result);
10
+ if (!msg) {
11
+ msg = "DuckDB error";
12
+ }
13
+ VALUE exc = rb_funcall(eDuckDBError, rb_intern("new"), 2, rb_str_new_cstr(msg), INT2FIX(duckdb_result_error_type(result)));
14
+ rb_exc_raise(exc);
15
+ }
16
+
5
17
  void rbduckdb_init_error(void) {
6
18
  #if 0
7
19
  VALUE mDuckDB = rb_define_module("DuckDB");
data/ext/duckdb/error.h CHANGED
@@ -2,5 +2,6 @@
2
2
  #define RUBY_DUCKDB_ERROR_H
3
3
 
4
4
  void rbduckdb_init_error(void);
5
+ NORETURN(void rbduckdb_raise_result_error(duckdb_result *result));
5
6
 
6
7
  #endif
@@ -137,6 +137,20 @@ void rbduckdb_vector_set_value_at(duckdb_vector vector, duckdb_logical_type elem
137
137
  ((duckdb_time *)vector_data)[index] = time;
138
138
  break;
139
139
  }
140
+ case DUCKDB_TYPE_TIME_NS: {
141
+ if (!rb_obj_is_kind_of(value, rb_cTime)) {
142
+ rb_raise(rb_eTypeError, "Expected Time object for TIME_NS");
143
+ }
144
+
145
+ VALUE hour = rb_funcall(value, rb_intern("hour"), 0);
146
+ VALUE min = rb_funcall(value, rb_intern("min"), 0);
147
+ VALUE sec = rb_funcall(value, rb_intern("sec"), 0);
148
+ VALUE nsec = rb_funcall(value, rb_intern("nsec"), 0);
149
+
150
+ duckdb_time_ns time_ns = rbduckdb_to_duckdb_time_ns_from_value(hour, min, sec, nsec);
151
+ ((duckdb_time_ns *)vector_data)[index] = time_ns;
152
+ break;
153
+ }
140
154
  case DUCKDB_TYPE_TIME_TZ: {
141
155
  if (!rb_obj_is_kind_of(value, rb_cTime)) {
142
156
  rb_raise(rb_eTypeError, "Expected Time object for TIME_TZ");
@@ -14,6 +14,7 @@ static idx_t check_index(VALUE vidx);
14
14
 
15
15
  static VALUE prepared_statement_bind_parameter_index(VALUE self, VALUE name);
16
16
  static VALUE prepared_statement_parameter_name(VALUE self, VALUE vidx);
17
+ static VALUE prepared_statement_param_logical_type(VALUE self, VALUE vidx);
17
18
  static VALUE prepared_statement_clear_bindings(VALUE self);
18
19
  static VALUE prepared_statement_bind_bool(VALUE self, VALUE vidx, VALUE val);
19
20
  static VALUE prepared_statement_bind_int8(VALUE self, VALUE vidx, VALUE val);
@@ -27,6 +28,10 @@ static VALUE prepared_statement_bind_blob(VALUE self, VALUE vidx, VALUE blob);
27
28
  static VALUE prepared_statement_bind_null(VALUE self, VALUE vidx);
28
29
  static VALUE prepared_statement__statement_type(VALUE self);
29
30
  static VALUE prepared_statement__param_type(VALUE self, VALUE vidx);
31
+ static VALUE prepared_statement_column_count(VALUE self);
32
+ static VALUE prepared_statement_column_name(VALUE self, VALUE vidx);
33
+ static VALUE prepared_statement__column_type(VALUE self, VALUE vidx);
34
+ static VALUE prepared_statement_column_logical_type(VALUE self, VALUE vidx);
30
35
  static VALUE prepared_statement__bind_uint8(VALUE self, VALUE vidx, VALUE val);
31
36
  static VALUE prepared_statement__bind_uint16(VALUE self, VALUE vidx, VALUE val);
32
37
  static VALUE prepared_statement__bind_uint32(VALUE self, VALUE vidx, VALUE val);
@@ -129,7 +134,6 @@ static VALUE prepared_statement_execute(VALUE self) {
129
134
  rubyDuckDBResult *ctxr;
130
135
  const char *error;
131
136
  VALUE result = rbduckdb_create_result();
132
- VALUE msg;
133
137
 
134
138
  TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
135
139
  ctxr = rbduckdb_get_struct_result(result);
@@ -146,11 +150,10 @@ static VALUE prepared_statement_execute(VALUE self) {
146
150
  if (state == DuckDBError) {
147
151
  error = duckdb_prepare_error(args.prepared_statement);
148
152
  if (error == NULL) {
149
- error = duckdb_result_error(args.out_result);
153
+ /* error originates from the result, which carries an error type */
154
+ rbduckdb_raise_result_error(args.out_result);
150
155
  }
151
- msg = rb_str_new2(error ? error : "Failed to execute prepared statement.");
152
-
153
- rb_raise(eDuckDBError, "%s", StringValuePtr(msg));
156
+ rb_raise(eDuckDBError, "%s", error);
154
157
  }
155
158
 
156
159
  return result;
@@ -206,6 +209,28 @@ static VALUE prepared_statement_parameter_name(VALUE self, VALUE vidx) {
206
209
  return vname;
207
210
  }
208
211
 
212
+ /*
213
+ * call-seq:
214
+ * prepared_statement.param_logical_type(param_index) -> DuckDB::LogicalType
215
+ *
216
+ * Returns the logical type of the parameter at the given (1-based) index.
217
+ * This provides richer type information than #param_type, e.g. decimal
218
+ * width/scale, nested types.
219
+ */
220
+ static VALUE prepared_statement_param_logical_type(VALUE self, VALUE vidx) {
221
+ rubyDuckDBPreparedStatement *ctx;
222
+ duckdb_logical_type logical_type;
223
+ idx_t idx = check_index(vidx);
224
+
225
+ TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
226
+
227
+ logical_type = duckdb_param_logical_type(ctx->prepared_statement, idx);
228
+ if (logical_type == NULL) {
229
+ rb_raise(eDuckDBError, "fail to get logical type of the parameter at %llu. parameter index is out of range.", (unsigned long long)idx);
230
+ }
231
+ return rbduckdb_create_logical_type(logical_type);
232
+ }
233
+
209
234
  /*
210
235
  * call-seq:
211
236
  * prepared_statement.clear_bindings -> DuckDB::PreparedStatement
@@ -360,6 +385,91 @@ static VALUE prepared_statement__statement_type(VALUE self) {
360
385
  return INT2FIX(duckdb_prepared_statement_type(ctx->prepared_statement));
361
386
  }
362
387
 
388
+ /*
389
+ * call-seq:
390
+ * prepared_statement.column_count -> Integer
391
+ *
392
+ * Returns the number of columns in the result set of the prepared statement
393
+ * without executing it.
394
+ *
395
+ * require 'duckdb'
396
+ * db = DuckDB::Database.open
397
+ * con = db.connect
398
+ * stmt = con.prepared_statement('SELECT 1 AS a, 2 AS b')
399
+ * stmt.column_count # => 2
400
+ */
401
+ static VALUE prepared_statement_column_count(VALUE self) {
402
+ rubyDuckDBPreparedStatement *ctx;
403
+ TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
404
+ return ULL2NUM(duckdb_prepared_statement_column_count(ctx->prepared_statement));
405
+ }
406
+
407
+ /*
408
+ * call-seq:
409
+ * prepared_statement.column_name(col_index) -> String
410
+ *
411
+ * Returns the name of the column at the specified index (0-based) of the
412
+ * result set of the prepared statement without executing it.
413
+ * Raises DuckDB::Error if the column index is out of range.
414
+ *
415
+ * require 'duckdb'
416
+ * db = DuckDB::Database.open
417
+ * con = db.connect
418
+ * stmt = con.prepared_statement('SELECT 1 AS a, 2 AS b')
419
+ * stmt.column_name(1) # => 'b'
420
+ */
421
+ static VALUE prepared_statement_column_name(VALUE self, VALUE vidx) {
422
+ rubyDuckDBPreparedStatement *ctx;
423
+ VALUE vname;
424
+ const char *name;
425
+ idx_t idx = NUM2ULL(vidx);
426
+
427
+ TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
428
+
429
+ name = duckdb_prepared_statement_column_name(ctx->prepared_statement, idx);
430
+ if (name == NULL) {
431
+ rb_raise(eDuckDBError, "fail to get column name at %llu. column index is out of range.", (unsigned long long)idx);
432
+ }
433
+ vname = rb_str_new2(name);
434
+ duckdb_free((void *)name);
435
+ return vname;
436
+ }
437
+
438
+ /* :nodoc: */
439
+ static VALUE prepared_statement__column_type(VALUE self, VALUE vidx) {
440
+ rubyDuckDBPreparedStatement *ctx;
441
+ TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
442
+ return INT2FIX(duckdb_prepared_statement_column_type(ctx->prepared_statement, NUM2ULL(vidx)));
443
+ }
444
+
445
+ /*
446
+ * call-seq:
447
+ * prepared_statement.column_logical_type(col_index) -> DuckDB::LogicalType
448
+ *
449
+ * Returns the logical type of the column at the specified index (0-based) of
450
+ * the result set of the prepared statement without executing it.
451
+ * Raises DuckDB::Error if the column index is out of range.
452
+ *
453
+ * require 'duckdb'
454
+ * db = DuckDB::Database.open
455
+ * con = db.connect
456
+ * stmt = con.prepared_statement('SELECT 1.5::DECIMAL(9, 4) AS a')
457
+ * stmt.column_logical_type(0).type # => :decimal
458
+ */
459
+ static VALUE prepared_statement_column_logical_type(VALUE self, VALUE vidx) {
460
+ rubyDuckDBPreparedStatement *ctx;
461
+ duckdb_logical_type logical_type;
462
+ idx_t idx = NUM2ULL(vidx);
463
+
464
+ TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
465
+
466
+ logical_type = duckdb_prepared_statement_column_logical_type(ctx->prepared_statement, idx);
467
+ if (logical_type == NULL) {
468
+ rb_raise(eDuckDBError, "fail to get column logical type at %llu. column index is out of range.", (unsigned long long)idx);
469
+ }
470
+ return rbduckdb_create_logical_type(logical_type);
471
+ }
472
+
363
473
  /* :nodoc: */
364
474
  static VALUE prepared_statement__param_type(VALUE self, VALUE vidx) {
365
475
  rubyDuckDBPreparedStatement *ctx;
@@ -613,7 +723,11 @@ void rbduckdb_init_prepared_statement(void) {
613
723
  rb_define_method(cDuckDBPreparedStatement, "nparams", prepared_statement_nparams, 0);
614
724
  rb_define_method(cDuckDBPreparedStatement, "bind_parameter_index", prepared_statement_bind_parameter_index, 1);
615
725
  rb_define_method(cDuckDBPreparedStatement, "parameter_name", prepared_statement_parameter_name, 1);
726
+ rb_define_method(cDuckDBPreparedStatement, "param_logical_type", prepared_statement_param_logical_type, 1);
616
727
  rb_define_method(cDuckDBPreparedStatement, "clear_bindings", prepared_statement_clear_bindings, 0);
728
+ rb_define_method(cDuckDBPreparedStatement, "column_count", prepared_statement_column_count, 0);
729
+ rb_define_method(cDuckDBPreparedStatement, "column_name", prepared_statement_column_name, 1);
730
+ rb_define_method(cDuckDBPreparedStatement, "column_logical_type", prepared_statement_column_logical_type, 1);
617
731
  rb_define_method(cDuckDBPreparedStatement, "bind_bool", prepared_statement_bind_bool, 2);
618
732
  rb_define_method(cDuckDBPreparedStatement, "bind_int8", prepared_statement_bind_int8, 2);
619
733
  rb_define_method(cDuckDBPreparedStatement, "bind_int16", prepared_statement_bind_int16, 2);
@@ -630,6 +744,7 @@ void rbduckdb_init_prepared_statement(void) {
630
744
  rb_define_private_method(cDuckDBPreparedStatement, "_bind_uint64", prepared_statement__bind_uint64, 2);
631
745
  rb_define_private_method(cDuckDBPreparedStatement, "_statement_type", prepared_statement__statement_type, 0);
632
746
  rb_define_private_method(cDuckDBPreparedStatement, "_param_type", prepared_statement__param_type, 1);
747
+ rb_define_private_method(cDuckDBPreparedStatement, "_column_type", prepared_statement__column_type, 1);
633
748
  rb_define_private_method(cDuckDBPreparedStatement, "_bind_date", prepared_statement__bind_date, 4);
634
749
  rb_define_private_method(cDuckDBPreparedStatement, "_bind_time", prepared_statement__bind_time, 5);
635
750
  rb_define_private_method(cDuckDBPreparedStatement, "_bind_timestamp", prepared_statement__bind_timestamp, 8);
data/ext/duckdb/util.c CHANGED
@@ -21,6 +21,14 @@ duckdb_time rbduckdb_to_duckdb_time_from_value(VALUE hour, VALUE min, VALUE sec,
21
21
  return duckdb_to_time(time_st);
22
22
  }
23
23
 
24
+ duckdb_time_ns rbduckdb_to_duckdb_time_ns_from_value(VALUE hour, VALUE min, VALUE sec, VALUE nanos) {
25
+ duckdb_time_ns time_ns;
26
+
27
+ time_ns.nanos = ((NUM2LL(hour) * 60 + NUM2LL(min)) * 60 + NUM2LL(sec)) * 1000000000LL + NUM2LL(nanos);
28
+
29
+ return time_ns;
30
+ }
31
+
24
32
  duckdb_timestamp rbduckdb_to_duckdb_timestamp_from_time_value(VALUE time_obj) {
25
33
  if (!rb_obj_is_kind_of(time_obj, rb_cTime)) {
26
34
  rb_raise(rb_eTypeError, "Expected Time object");
data/ext/duckdb/util.h CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  duckdb_date rbduckdb_to_duckdb_date_from_value(VALUE year, VALUE month, VALUE day);
5
5
  duckdb_time rbduckdb_to_duckdb_time_from_value(VALUE hour, VALUE min, VALUE sec, VALUE micros);
6
+ duckdb_time_ns rbduckdb_to_duckdb_time_ns_from_value(VALUE hour, VALUE min, VALUE sec, VALUE nanos);
6
7
  duckdb_timestamp rbduckdb_to_duckdb_timestamp_from_time_value(VALUE time_obj);
7
8
  duckdb_timestamp rbduckdb_to_duckdb_timestamp_from_value(VALUE year, VALUE month, VALUE day, VALUE hour, VALUE min, VALUE sec, VALUE micros);
8
9
  void rbduckdb_to_duckdb_interval_from_value(duckdb_interval* interval, VALUE months, VALUE days, VALUE micros);