duckdb 1.5.2.1 → 1.5.4.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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +40 -0
  3. data/README.md +52 -0
  4. data/ext/duckdb/aggregate_function.c +1 -1
  5. data/ext/duckdb/aggregate_function_set.c +86 -0
  6. data/ext/duckdb/aggregate_function_set.h +14 -0
  7. data/ext/duckdb/appender.c +62 -4
  8. data/ext/duckdb/arrow_array_stream.c +226 -0
  9. data/ext/duckdb/arrow_array_stream.h +61 -0
  10. data/ext/duckdb/arrow_import.c +165 -0
  11. data/ext/duckdb/arrow_import.h +6 -0
  12. data/ext/duckdb/blob.c +1 -1
  13. data/ext/duckdb/blob.h +1 -2
  14. data/ext/duckdb/config.c +1 -1
  15. data/ext/duckdb/config.h +1 -1
  16. data/ext/duckdb/connection.c +26 -3
  17. data/ext/duckdb/converter.h +1 -0
  18. data/ext/duckdb/conveter.c +39 -9
  19. data/ext/duckdb/data_chunk.c +10 -0
  20. data/ext/duckdb/data_chunk.h +1 -0
  21. data/ext/duckdb/duckdb.c +14 -11
  22. data/ext/duckdb/error.c +1 -1
  23. data/ext/duckdb/error.h +1 -3
  24. data/ext/duckdb/extconf.rb +28 -13
  25. data/ext/duckdb/function_executor.c +308 -2
  26. data/ext/duckdb/function_executor.h +44 -0
  27. data/ext/duckdb/prepared_statement.c +38 -0
  28. data/ext/duckdb/result.c +49 -53
  29. data/ext/duckdb/result.h +11 -0
  30. data/ext/duckdb/ruby-duckdb.h +4 -0
  31. data/ext/duckdb/scalar_function.c +97 -29
  32. data/ext/duckdb/scalar_function.h +2 -4
  33. data/ext/duckdb/scalar_function_bind_info.c +13 -13
  34. data/ext/duckdb/scalar_function_bind_info.h +1 -1
  35. data/ext/duckdb/scalar_function_set.c +9 -9
  36. data/ext/duckdb/scalar_function_set.h +2 -2
  37. data/ext/duckdb/table_description.c +19 -19
  38. data/ext/duckdb/table_description.h +1 -1
  39. data/ext/duckdb/table_function.c +94 -28
  40. data/ext/duckdb/table_function.h +2 -2
  41. data/ext/duckdb/table_function_bind_info.c +20 -20
  42. data/ext/duckdb/table_function_bind_info.h +2 -2
  43. data/ext/duckdb/table_function_function_info.c +5 -5
  44. data/ext/duckdb/table_function_function_info.h +2 -2
  45. data/ext/duckdb/table_function_init_info.c +70 -5
  46. data/ext/duckdb/table_function_init_info.h +2 -2
  47. data/lib/duckdb/aggregate_function.rb +7 -1
  48. data/lib/duckdb/aggregate_function_set.rb +29 -0
  49. data/lib/duckdb/appender.rb +97 -0
  50. data/lib/duckdb/arrow_array_stream.rb +33 -0
  51. data/lib/duckdb/connection.rb +139 -9
  52. data/lib/duckdb/prepared_statement.rb +35 -0
  53. data/lib/duckdb/result.rb +39 -2
  54. data/lib/duckdb/scalar_function.rb +9 -4
  55. data/lib/duckdb/scalar_function_set.rb +0 -1
  56. data/lib/duckdb/table_description.rb +7 -0
  57. data/lib/duckdb/table_name_parser.rb +58 -0
  58. data/lib/duckdb/version.rb +1 -1
  59. data/lib/duckdb.rb +3 -0
  60. metadata +11 -2
@@ -0,0 +1,165 @@
1
+ #include "ruby-duckdb.h"
2
+
3
+ /*
4
+ * Internal helpers backing DuckDB::Connection#append_arrow. They consume an
5
+ * Arrow producer's struct ArrowArrayStream (given by its address) and convert
6
+ * each chunk into a DuckDB::DataChunk using DuckDB's unstable Arrow C API. The
7
+ * Ruby layer owns the loop, the appender lifecycle, and error handling; these
8
+ * primitives only do the raw-pointer / C-API work.
9
+ */
10
+
11
+ static VALUE cDuckDBArrowConvertedSchema;
12
+
13
+ typedef struct {
14
+ duckdb_arrow_converted_schema converted_schema;
15
+ } rubyDuckDBArrowConvertedSchema;
16
+
17
+ static void deallocate(void *ctx);
18
+ static VALUE allocate(VALUE klass);
19
+ static size_t memsize(const void *p);
20
+ static void raise_error_data(duckdb_error_data error_data);
21
+
22
+ static VALUE connection__arrow_converted_schema(VALUE self, VALUE address);
23
+ static VALUE connection__arrow_next_chunk(VALUE self, VALUE address, VALUE converted);
24
+ static VALUE connection__arrow_release(VALUE self, VALUE address);
25
+
26
+ static const rb_data_type_t arrow_converted_schema_data_type = {
27
+ "DuckDB/ArrowConvertedSchema",
28
+ {NULL, deallocate, memsize,},
29
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
30
+ };
31
+
32
+ static void deallocate(void *ctx) {
33
+ rubyDuckDBArrowConvertedSchema *p = (rubyDuckDBArrowConvertedSchema *)ctx;
34
+
35
+ if (p->converted_schema) {
36
+ duckdb_destroy_arrow_converted_schema(&(p->converted_schema));
37
+ }
38
+ xfree(p);
39
+ }
40
+
41
+ static VALUE allocate(VALUE klass) {
42
+ rubyDuckDBArrowConvertedSchema *ctx = xcalloc((size_t)1, sizeof(rubyDuckDBArrowConvertedSchema));
43
+ return TypedData_Wrap_Struct(klass, &arrow_converted_schema_data_type, ctx);
44
+ }
45
+
46
+ static size_t memsize(const void *p) {
47
+ return sizeof(rubyDuckDBArrowConvertedSchema);
48
+ }
49
+
50
+ static void raise_error_data(duckdb_error_data error_data) {
51
+ VALUE message;
52
+
53
+ if (error_data == NULL) {
54
+ return;
55
+ }
56
+ if (!duckdb_error_data_has_error(error_data)) {
57
+ duckdb_destroy_error_data(&error_data);
58
+ return;
59
+ }
60
+ message = rb_str_new_cstr(duckdb_error_data_message(error_data));
61
+ duckdb_destroy_error_data(&error_data);
62
+ rb_raise(eDuckDBError, "%s", StringValueCStr(message));
63
+ }
64
+
65
+ static struct ArrowArrayStream *stream_from_address(VALUE address) {
66
+ return (struct ArrowArrayStream *)(uintptr_t)NUM2ULL(address);
67
+ }
68
+
69
+ /* :nodoc: */
70
+ static VALUE connection__arrow_converted_schema(VALUE self, VALUE address) {
71
+ rubyDuckDBConnection *ctx;
72
+ struct ArrowArrayStream *stream;
73
+ struct ArrowSchema schema;
74
+ duckdb_arrow_converted_schema converted_schema = NULL;
75
+ duckdb_error_data error_data;
76
+ VALUE obj;
77
+ rubyDuckDBArrowConvertedSchema *schema_ctx;
78
+ int rc;
79
+
80
+ ctx = rbduckdb_get_struct_connection(self);
81
+ stream = stream_from_address(address);
82
+ if (stream == NULL) {
83
+ rb_raise(eDuckDBError, "Arrow producer returned a NULL stream");
84
+ }
85
+
86
+ memset(&schema, 0, sizeof(schema));
87
+ rc = stream->get_schema(stream, &schema);
88
+ if (rc != 0) {
89
+ const char *err = stream->get_last_error(stream);
90
+ rb_raise(eDuckDBError, "failed to get Arrow schema: %s", err ? err : "unknown error");
91
+ }
92
+
93
+ error_data = duckdb_schema_from_arrow(ctx->con, &schema, &converted_schema);
94
+ if (schema.release != NULL) {
95
+ schema.release(&schema);
96
+ }
97
+ raise_error_data(error_data);
98
+
99
+ obj = allocate(cDuckDBArrowConvertedSchema);
100
+ TypedData_Get_Struct(obj, rubyDuckDBArrowConvertedSchema, &arrow_converted_schema_data_type, schema_ctx);
101
+ schema_ctx->converted_schema = converted_schema;
102
+ return obj;
103
+ }
104
+
105
+ /* :nodoc: */
106
+ static VALUE connection__arrow_next_chunk(VALUE self, VALUE address, VALUE converted) {
107
+ rubyDuckDBConnection *ctx;
108
+ rubyDuckDBArrowConvertedSchema *schema_ctx;
109
+ struct ArrowArrayStream *stream;
110
+ struct ArrowArray array;
111
+ duckdb_data_chunk chunk = NULL;
112
+ duckdb_error_data error_data;
113
+ int rc;
114
+
115
+ ctx = rbduckdb_get_struct_connection(self);
116
+ TypedData_Get_Struct(converted, rubyDuckDBArrowConvertedSchema, &arrow_converted_schema_data_type, schema_ctx);
117
+ stream = stream_from_address(address);
118
+
119
+ memset(&array, 0, sizeof(array));
120
+ rc = stream->get_next(stream, &array);
121
+ if (rc != 0) {
122
+ const char *err = stream->get_last_error(stream);
123
+ rb_raise(eDuckDBError, "failed to get next Arrow chunk: %s", err ? err : "unknown error");
124
+ }
125
+ /* End of stream: a released array (release == NULL). */
126
+ if (array.release == NULL) {
127
+ return Qnil;
128
+ }
129
+
130
+ /* duckdb_data_chunk_from_arrow takes ownership of the array (nulls its
131
+ * release). On error before that, we still own it and must release it. */
132
+ error_data = duckdb_data_chunk_from_arrow(ctx->con, &array, schema_ctx->converted_schema, &chunk);
133
+ if (error_data != NULL && duckdb_error_data_has_error(error_data)) {
134
+ if (array.release != NULL) {
135
+ array.release(&array);
136
+ }
137
+ raise_error_data(error_data);
138
+ } else if (error_data != NULL) {
139
+ duckdb_destroy_error_data(&error_data);
140
+ }
141
+
142
+ return rbduckdb_create_data_chunk(chunk, true);
143
+ }
144
+
145
+ /* :nodoc: */
146
+ static VALUE connection__arrow_release(VALUE self, VALUE address) {
147
+ struct ArrowArrayStream *stream = stream_from_address(address);
148
+
149
+ if (stream != NULL && stream->release != NULL) {
150
+ stream->release(stream);
151
+ }
152
+ return Qnil;
153
+ }
154
+
155
+ void rbduckdb_init_arrow_import(void) {
156
+ #if 0
157
+ VALUE mDuckDB = rb_define_module("DuckDB");
158
+ #endif
159
+ cDuckDBArrowConvertedSchema = rb_define_class_under(mDuckDB, "ArrowConvertedSchema", rb_cObject);
160
+ rb_define_alloc_func(cDuckDBArrowConvertedSchema, allocate);
161
+
162
+ rb_define_private_method(cDuckDBConnection, "_arrow_converted_schema", connection__arrow_converted_schema, 1);
163
+ rb_define_private_method(cDuckDBConnection, "_arrow_next_chunk", connection__arrow_next_chunk, 2);
164
+ rb_define_private_method(cDuckDBConnection, "_arrow_release", connection__arrow_release, 1);
165
+ }
@@ -0,0 +1,6 @@
1
+ #ifndef RUBY_DUCKDB_ARROW_IMPORT_H
2
+ #define RUBY_DUCKDB_ARROW_IMPORT_H
3
+
4
+ void rbduckdb_init_arrow_import(void);
5
+
6
+ #endif
data/ext/duckdb/blob.c CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  VALUE cDuckDBBlob;
4
4
 
5
- void rbduckdb_init_duckdb_blob(void) {
5
+ void rbduckdb_init_blob(void) {
6
6
  #if 0
7
7
  VALUE mDuckDB = rb_define_module("DuckDB");
8
8
  #endif
data/ext/duckdb/blob.h CHANGED
@@ -1,7 +1,6 @@
1
1
  #ifndef RUBY_DUCKDB_BLOB_H
2
2
  #define RUBY_DUCKDB_BLOB_H
3
3
 
4
- void rbduckdb_init_duckdb_blob(void);
4
+ void rbduckdb_init_blob(void);
5
5
 
6
6
  #endif
7
-
data/ext/duckdb/config.c CHANGED
@@ -79,7 +79,7 @@ static VALUE config_set_config(VALUE self, VALUE key, VALUE value) {
79
79
  return self;
80
80
  }
81
81
 
82
- void rbduckdb_init_duckdb_config(void) {
82
+ void rbduckdb_init_config(void) {
83
83
  #if 0
84
84
  VALUE mDuckDB = rb_define_module("DuckDB");
85
85
  #endif
data/ext/duckdb/config.h CHANGED
@@ -9,6 +9,6 @@ typedef struct _rubyDuckDBConfig rubyDuckDBConfig;
9
9
 
10
10
  rubyDuckDBConfig *get_struct_config(VALUE obj);
11
11
 
12
- void rbduckdb_init_duckdb_config(void);
12
+ void rbduckdb_init_config(void);
13
13
 
14
14
  #endif
@@ -15,6 +15,7 @@ static VALUE connection__register_logical_type(VALUE self, VALUE logical_type);
15
15
  static VALUE connection__register_scalar_function(VALUE self, VALUE scalar_function);
16
16
  static VALUE connection__register_scalar_function_set(VALUE self, VALUE scalar_function_set);
17
17
  static VALUE connection__register_aggregate_function(VALUE self, VALUE aggregate_function);
18
+ static VALUE connection__register_aggregate_function_set(VALUE self, VALUE aggregate_function_set);
18
19
  static VALUE connection__register_table_function(VALUE self, VALUE table_function);
19
20
 
20
21
  static const rb_data_type_t connection_data_type = {
@@ -230,7 +231,7 @@ static VALUE connection__register_scalar_function(VALUE self, VALUE scalar_funct
230
231
  duckdb_state state;
231
232
 
232
233
  ctxcon = rbduckdb_get_struct_connection(self);
233
- ctxsf = get_struct_scalar_function(scalar_function);
234
+ ctxsf = rbduckdb_get_struct_scalar_function(scalar_function);
234
235
 
235
236
  state = duckdb_register_scalar_function(ctxcon->con, ctxsf->scalar_function);
236
237
 
@@ -251,7 +252,7 @@ static VALUE connection__register_scalar_function_set(VALUE self, VALUE scalar_f
251
252
  duckdb_state state;
252
253
 
253
254
  ctxcon = rbduckdb_get_struct_connection(self);
254
- ctxsfs = get_struct_scalar_function_set(scalar_function_set);
255
+ ctxsfs = rbduckdb_get_struct_scalar_function_set(scalar_function_set);
255
256
 
256
257
  state = duckdb_register_scalar_function_set(ctxcon->con, ctxsfs->scalar_function_set);
257
258
 
@@ -286,13 +287,34 @@ static VALUE connection__register_aggregate_function(VALUE self, VALUE aggregate
286
287
  return self;
287
288
  }
288
289
 
290
+ /* :nodoc: */
291
+ static VALUE connection__register_aggregate_function_set(VALUE self, VALUE aggregate_function_set) {
292
+ rubyDuckDBConnection *ctxcon;
293
+ rubyDuckDBAggregateFunctionSet *ctxafs;
294
+ duckdb_state state;
295
+
296
+ ctxcon = rbduckdb_get_struct_connection(self);
297
+ ctxafs = rbduckdb_get_struct_aggregate_function_set(aggregate_function_set);
298
+
299
+ state = duckdb_register_aggregate_function_set(ctxcon->con, ctxafs->aggregate_function_set);
300
+
301
+ if (state == DuckDBError) {
302
+ rb_raise(eDuckDBError, "Failed to register aggregate function set");
303
+ }
304
+
305
+ /* Keep reference to prevent GC while connection is alive */
306
+ rb_ary_push(ctxcon->registered_functions, aggregate_function_set);
307
+
308
+ return self;
309
+ }
310
+
289
311
  static VALUE connection__register_table_function(VALUE self, VALUE table_function) {
290
312
  rubyDuckDBConnection *ctxcon;
291
313
  rubyDuckDBTableFunction *ctxtf;
292
314
  duckdb_state state;
293
315
 
294
316
  ctxcon = rbduckdb_get_struct_connection(self);
295
- ctxtf = get_struct_table_function(table_function);
317
+ ctxtf = rbduckdb_get_struct_table_function(table_function);
296
318
 
297
319
  state = duckdb_register_table_function(ctxcon->con, ctxtf->table_function);
298
320
 
@@ -320,6 +342,7 @@ void rbduckdb_init_connection(void) {
320
342
  rb_define_private_method(cDuckDBConnection, "_register_scalar_function", connection__register_scalar_function, 1);
321
343
  rb_define_private_method(cDuckDBConnection, "_register_scalar_function_set", connection__register_scalar_function_set, 1);
322
344
  rb_define_private_method(cDuckDBConnection, "_register_aggregate_function", connection__register_aggregate_function, 1);
345
+ rb_define_private_method(cDuckDBConnection, "_register_aggregate_function_set", connection__register_aggregate_function_set, 1);
323
346
  rb_define_private_method(cDuckDBConnection, "_register_table_function", connection__register_table_function, 1);
324
347
  rb_define_private_method(cDuckDBConnection, "_connect", connection__connect, 1);
325
348
  rb_define_private_method(cDuckDBConnection, "_query_sql", connection__query_sql, 1);
@@ -19,6 +19,7 @@ extern ID id__decimal_to_unscaled;
19
19
  VALUE rbduckdb_uuid_to_ruby(duckdb_hugeint h);
20
20
  VALUE rbduckdb_uuid_uhugeint_to_ruby(duckdb_uhugeint h);
21
21
  void rbduckdb_uuid_str_to_hugeint(VALUE uuid_str, duckdb_hugeint *out);
22
+ void rbduckdb_uuid_str_to_uhugeint(VALUE uuid_str, duckdb_uhugeint *out);
22
23
  VALUE rbduckdb_interval_to_ruby(duckdb_interval i);
23
24
  VALUE rbduckdb_hugeint_to_ruby(duckdb_hugeint h);
24
25
  VALUE rbduckdb_uhugeint_to_ruby(duckdb_uhugeint h);
@@ -153,22 +153,21 @@ static int hex_nibble(unsigned char c)
153
153
 
154
154
  /*
155
155
  * Parse a canonical UUID string ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx") into
156
- * a duckdb_hugeint. Returns true on success, false on invalid input.
156
+ * two uint64_t halves. Returns true on success, false on invalid input.
157
157
  *
158
158
  * Iterates the 36-character string, skipping the four dash positions. The 32
159
- * hex nibbles are accumulated directly into two uint64_t halves (hi, lo) with
160
- * no bignum arithmetic or intermediate allocation. The sign-bit flip is applied
161
- * to hi before storing in upper, matching DuckDB's internal UUID representation.
159
+ * hex nibbles are accumulated directly into hi (upper 64 bits) and lo (lower
160
+ * 64 bits) with no bignum arithmetic or intermediate allocation.
162
161
  */
163
- static bool uuid_str_to_hugeint(const char *str, long len, duckdb_hugeint *out)
162
+ static bool parse_uuid_string(const char *str, long len, uint64_t *hi, uint64_t *lo)
164
163
  {
165
- // Expected format: 8-4-4-4-12 = 36 characters with dashes at fixed positions
166
164
  if (len != 36 ||
167
165
  str[8] != '-' || str[13] != '-' || str[18] != '-' || str[23] != '-') {
168
166
  return false;
169
167
  }
170
168
 
171
- uint64_t hi = 0, lo = 0;
169
+ *hi = 0;
170
+ *lo = 0;
172
171
  int nibble_idx = 0;
173
172
 
174
173
  for (int string_idx = 0; string_idx < 36; string_idx++) {
@@ -176,13 +175,27 @@ static bool uuid_str_to_hugeint(const char *str, long len, duckdb_hugeint *out)
176
175
  int nib = hex_nibble((unsigned char)str[string_idx]);
177
176
  if (nib < 0) return false;
178
177
  if (nibble_idx < 16) {
179
- hi = (hi << 4) | (uint64_t)nib;
178
+ *hi = (*hi << 4) | (uint64_t)nib;
180
179
  } else {
181
- lo = (lo << 4) | (uint64_t)nib;
180
+ *lo = (*lo << 4) | (uint64_t)nib;
182
181
  }
183
182
  nibble_idx++;
184
183
  }
185
184
 
185
+ return true;
186
+ }
187
+
188
+ /*
189
+ * Parse a canonical UUID string ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx") into
190
+ * a duckdb_hugeint. Returns true on success, false on invalid input.
191
+ *
192
+ * The sign-bit flip is applied to hi before storing in upper, matching
193
+ * DuckDB's internal UUID representation.
194
+ */
195
+ static bool uuid_str_to_hugeint(const char *str, long len, duckdb_hugeint *out)
196
+ {
197
+ uint64_t hi, lo;
198
+ if (!parse_uuid_string(str, len, &hi, &lo)) return false;
186
199
  // Apply the sign-bit flip to match DuckDB's internal UUID representation
187
200
  out->upper = (int64_t)(hi ^ DUCKDB_UUID_SIGN_BIT);
188
201
  out->lower = lo;
@@ -203,6 +216,23 @@ void rbduckdb_uuid_str_to_hugeint(VALUE uuid_str, duckdb_hugeint *out)
203
216
  }
204
217
  }
205
218
 
219
+ /*
220
+ * Ruby-callable wrapper: parse a UUID string VALUE into a duckdb_uhugeint
221
+ * (no sign-bit flip), raising ArgumentError on invalid input.
222
+ */
223
+ void rbduckdb_uuid_str_to_uhugeint(VALUE uuid_str, duckdb_uhugeint *out)
224
+ {
225
+ StringValue(uuid_str);
226
+ const char *str = RSTRING_PTR(uuid_str);
227
+ long len = RSTRING_LEN(uuid_str);
228
+ uint64_t hi, lo;
229
+ if (!parse_uuid_string(str, len, &hi, &lo)) {
230
+ rb_raise(rb_eArgError, "Invalid UUID format: %"PRIsVALUE, uuid_str);
231
+ }
232
+ out->upper = hi;
233
+ out->lower = lo;
234
+ }
235
+
206
236
  VALUE rbduckdb_interval_to_ruby(duckdb_interval i) {
207
237
  return rb_funcall(mDuckDBConverter, id__to_interval_from_vector, 3,
208
238
  INT2NUM(i.months),
@@ -44,6 +44,16 @@ rubyDuckDBDataChunk *rbduckdb_get_struct_data_chunk(VALUE obj) {
44
44
  return ctx;
45
45
  }
46
46
 
47
+ VALUE rbduckdb_create_data_chunk(duckdb_data_chunk chunk, bool owned) {
48
+ VALUE obj = allocate(cDuckDBDataChunk);
49
+ rubyDuckDBDataChunk *ctx;
50
+
51
+ TypedData_Get_Struct(obj, rubyDuckDBDataChunk, &data_chunk_data_type, ctx);
52
+ ctx->data_chunk = chunk;
53
+ ctx->owned = owned;
54
+ return obj;
55
+ }
56
+
47
57
  static VALUE data_chunk_initialize(int argc, VALUE *argv, VALUE self) {
48
58
  rubyDuckDBDataChunk *ctx;
49
59
  VALUE logical_types;
@@ -9,6 +9,7 @@ struct _rubyDuckDBDataChunk {
9
9
  typedef struct _rubyDuckDBDataChunk rubyDuckDBDataChunk;
10
10
 
11
11
  rubyDuckDBDataChunk *rbduckdb_get_struct_data_chunk(VALUE obj);
12
+ VALUE rbduckdb_create_data_chunk(duckdb_data_chunk chunk, bool owned);
12
13
  void rbduckdb_init_data_chunk(void);
13
14
 
14
15
  #endif
data/ext/duckdb/duckdb.c CHANGED
@@ -41,7 +41,7 @@ Init_duckdb_native(void) {
41
41
  rb_define_singleton_method(mDuckDB, "library_version", duckdb_s_library_version, 0);
42
42
  rb_define_singleton_method(mDuckDB, "vector_size", duckdb_s_vector_size, 0);
43
43
 
44
- rbduckdb_init_duckdb_error();
44
+ rbduckdb_init_error();
45
45
  rbduckdb_init_database();
46
46
  rbduckdb_init_connection();
47
47
  rbduckdb_init_result();
@@ -49,27 +49,30 @@ Init_duckdb_native(void) {
49
49
  rbduckdb_init_logical_type();
50
50
  rbduckdb_init_prepared_statement();
51
51
  rbduckdb_init_pending_result();
52
- rbduckdb_init_duckdb_blob();
52
+ rbduckdb_init_blob();
53
53
  rbduckdb_init_appender();
54
- rbduckdb_init_duckdb_config();
54
+ rbduckdb_init_config();
55
55
  rbduckdb_init_converter();
56
56
  rbduckdb_init_extracted_statements();
57
57
  rbduckdb_init_instance_cache();
58
58
  rbduckdb_init_value();
59
- rbduckdb_init_duckdb_scalar_function();
60
- rbduckdb_init_duckdb_scalar_function_set();
59
+ rbduckdb_init_scalar_function();
60
+ rbduckdb_init_scalar_function_set();
61
61
  rbduckdb_init_aggregate_function();
62
+ rbduckdb_init_aggregate_function_set();
62
63
  rbduckdb_init_expression();
63
64
  rbduckdb_init_client_context();
64
- rbduckdb_init_duckdb_scalar_function_bind_info();
65
+ rbduckdb_init_scalar_function_bind_info();
65
66
  rbduckdb_init_vector();
66
67
  rbduckdb_init_data_chunk();
67
68
  rbduckdb_init_memory_helper();
68
- rbduckdb_init_duckdb_table_function();
69
- rbduckdb_init_duckdb_table_function_bind_info();
70
- rbduckdb_init_duckdb_table_function_init_info();
71
- rbduckdb_init_duckdb_table_function_function_info();
69
+ rbduckdb_init_table_function();
70
+ rbduckdb_init_table_function_bind_info();
71
+ rbduckdb_init_table_function_init_info();
72
+ rbduckdb_init_table_function_function_info();
72
73
  #ifdef HAVE_DUCKDB_H_GE_V1_5_0
73
- rbduckdb_init_duckdb_table_description();
74
+ rbduckdb_init_table_description();
74
75
  #endif
76
+ rbduckdb_init_arrow_array_stream();
77
+ rbduckdb_init_arrow_import();
75
78
  }
data/ext/duckdb/error.c CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  VALUE eDuckDBError;
4
4
 
5
- void rbduckdb_init_duckdb_error(void) {
5
+ void rbduckdb_init_error(void) {
6
6
  #if 0
7
7
  VALUE mDuckDB = rb_define_module("DuckDB");
8
8
  #endif
data/ext/duckdb/error.h CHANGED
@@ -1,8 +1,6 @@
1
1
  #ifndef RUBY_DUCKDB_ERROR_H
2
2
  #define RUBY_DUCKDB_ERROR_H
3
3
 
4
- void rbduckdb_init_duckdb_error(void);
4
+ void rbduckdb_init_error(void);
5
5
 
6
6
  #endif
7
-
8
-
@@ -4,13 +4,34 @@ require 'mkmf'
4
4
 
5
5
  DUCKDB_REQUIRED_VERSION = '1.4.0'
6
6
 
7
+ def brew_prefix(formula = nil)
8
+ cmd = formula ? "brew --prefix #{formula} 2>/dev/null" : 'brew --prefix 2>/dev/null'
9
+ prefix = `#{cmd}`.chomp
10
+ prefix.empty? ? nil : prefix
11
+ end
12
+
13
+ FALLBACK_PREFIXES = %w[/opt/homebrew /opt/homebrew/opt/duckdb /opt/local].freeze
14
+
15
+ def brew_dirs(subdir)
16
+ dirs = []
17
+ dirs << "#{brew_prefix('duckdb')}/#{subdir}" if brew_prefix('duckdb')
18
+ if (prefix = brew_prefix)
19
+ dirs << "#{prefix}/#{subdir}"
20
+ dirs << "#{prefix}/opt/duckdb/#{subdir}"
21
+ end
22
+ dirs
23
+ end
24
+
25
+ def homebrew_include_dirs
26
+ (brew_dirs('include') + FALLBACK_PREFIXES.map { |p| "#{p}/include" }).uniq
27
+ end
28
+
29
+ def homebrew_lib_dirs
30
+ (brew_dirs('lib') + FALLBACK_PREFIXES.map { |p| "#{p}/lib" }).uniq
31
+ end
32
+
7
33
  def check_duckdb_header(header, version)
8
- found = find_header(
9
- header,
10
- '/opt/homebrew/include',
11
- '/opt/homebrew/opt/duckdb/include',
12
- '/opt/local/include'
13
- )
34
+ found = find_header(header, *homebrew_include_dirs)
14
35
  return if found
15
36
 
16
37
  msg = "#{header} is not found. Install #{header} of duckdb >= #{version}."
@@ -19,13 +40,7 @@ def check_duckdb_header(header, version)
19
40
  end
20
41
 
21
42
  def check_duckdb_library(library, func, version)
22
- found = find_library(
23
- library,
24
- func,
25
- '/opt/homebrew/lib',
26
- '/opt/homebrew/opt/duckdb/lib',
27
- '/opt/local/lib'
28
- )
43
+ found = find_library(library, func, *homebrew_lib_dirs)
29
44
  have_func(func, 'duckdb.h')
30
45
  return if found
31
46