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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +40 -0
- data/README.md +52 -0
- data/ext/duckdb/aggregate_function.c +1 -1
- data/ext/duckdb/aggregate_function_set.c +86 -0
- data/ext/duckdb/aggregate_function_set.h +14 -0
- data/ext/duckdb/appender.c +62 -4
- data/ext/duckdb/arrow_array_stream.c +226 -0
- data/ext/duckdb/arrow_array_stream.h +61 -0
- data/ext/duckdb/arrow_import.c +165 -0
- data/ext/duckdb/arrow_import.h +6 -0
- data/ext/duckdb/blob.c +1 -1
- data/ext/duckdb/blob.h +1 -2
- data/ext/duckdb/config.c +1 -1
- data/ext/duckdb/config.h +1 -1
- data/ext/duckdb/connection.c +26 -3
- data/ext/duckdb/converter.h +1 -0
- data/ext/duckdb/conveter.c +39 -9
- data/ext/duckdb/data_chunk.c +10 -0
- data/ext/duckdb/data_chunk.h +1 -0
- data/ext/duckdb/duckdb.c +14 -11
- data/ext/duckdb/error.c +1 -1
- data/ext/duckdb/error.h +1 -3
- data/ext/duckdb/extconf.rb +28 -13
- data/ext/duckdb/function_executor.c +308 -2
- data/ext/duckdb/function_executor.h +44 -0
- data/ext/duckdb/prepared_statement.c +38 -0
- data/ext/duckdb/result.c +49 -53
- data/ext/duckdb/result.h +11 -0
- data/ext/duckdb/ruby-duckdb.h +4 -0
- data/ext/duckdb/scalar_function.c +97 -29
- data/ext/duckdb/scalar_function.h +2 -4
- data/ext/duckdb/scalar_function_bind_info.c +13 -13
- data/ext/duckdb/scalar_function_bind_info.h +1 -1
- data/ext/duckdb/scalar_function_set.c +9 -9
- data/ext/duckdb/scalar_function_set.h +2 -2
- data/ext/duckdb/table_description.c +19 -19
- data/ext/duckdb/table_description.h +1 -1
- data/ext/duckdb/table_function.c +94 -28
- data/ext/duckdb/table_function.h +2 -2
- data/ext/duckdb/table_function_bind_info.c +20 -20
- data/ext/duckdb/table_function_bind_info.h +2 -2
- data/ext/duckdb/table_function_function_info.c +5 -5
- data/ext/duckdb/table_function_function_info.h +2 -2
- data/ext/duckdb/table_function_init_info.c +70 -5
- data/ext/duckdb/table_function_init_info.h +2 -2
- data/lib/duckdb/aggregate_function.rb +7 -1
- data/lib/duckdb/aggregate_function_set.rb +29 -0
- data/lib/duckdb/appender.rb +97 -0
- data/lib/duckdb/arrow_array_stream.rb +33 -0
- data/lib/duckdb/connection.rb +139 -9
- data/lib/duckdb/prepared_statement.rb +35 -0
- data/lib/duckdb/result.rb +39 -2
- data/lib/duckdb/scalar_function.rb +9 -4
- data/lib/duckdb/scalar_function_set.rb +0 -1
- data/lib/duckdb/table_description.rb +7 -0
- data/lib/duckdb/table_name_parser.rb +58 -0
- data/lib/duckdb/version.rb +1 -1
- data/lib/duckdb.rb +3 -0
- 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
|
+
}
|
data/ext/duckdb/blob.c
CHANGED
data/ext/duckdb/blob.h
CHANGED
data/ext/duckdb/config.c
CHANGED
data/ext/duckdb/config.h
CHANGED
data/ext/duckdb/connection.c
CHANGED
|
@@ -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 =
|
|
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 =
|
|
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 =
|
|
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);
|
data/ext/duckdb/converter.h
CHANGED
|
@@ -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);
|
data/ext/duckdb/conveter.c
CHANGED
|
@@ -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
|
-
*
|
|
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
|
|
160
|
-
* no bignum arithmetic or intermediate allocation.
|
|
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
|
|
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
|
-
|
|
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),
|
data/ext/duckdb/data_chunk.c
CHANGED
|
@@ -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;
|
data/ext/duckdb/data_chunk.h
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
52
|
+
rbduckdb_init_blob();
|
|
53
53
|
rbduckdb_init_appender();
|
|
54
|
-
|
|
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
|
-
|
|
60
|
-
|
|
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
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
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
data/ext/duckdb/error.h
CHANGED
data/ext/duckdb/extconf.rb
CHANGED
|
@@ -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
|
|