duckdb 1.4.2.0 → 1.4.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/.github/copilot-instructions.md +169 -0
- data/.github/workflows/linter.yml +30 -0
- data/.github/workflows/test_on_macos.yml +7 -2
- data/.github/workflows/test_on_ubuntu.yml +7 -2
- data/.github/workflows/test_on_windows.yml +8 -3
- data/.rubocop.yml +34 -0
- data/CHANGELOG.md +74 -0
- data/Dockerfile +2 -2
- data/Gemfile +12 -0
- data/Gemfile.lock +70 -7
- data/Rakefile +8 -6
- data/bin/console +4 -3
- data/duckdb.gemspec +2 -6
- data/ext/duckdb/bind_info.c +243 -0
- data/ext/duckdb/bind_info.h +13 -0
- data/ext/duckdb/connection.c +60 -2
- data/ext/duckdb/connection.h +1 -0
- data/ext/duckdb/data_chunk.c +137 -0
- data/ext/duckdb/data_chunk.h +13 -0
- data/ext/duckdb/duckdb.c +7 -0
- data/ext/duckdb/function_info.c +65 -0
- data/ext/duckdb/function_info.h +13 -0
- data/ext/duckdb/init_info.c +65 -0
- data/ext/duckdb/init_info.h +13 -0
- data/ext/duckdb/logical_type.c +42 -0
- data/ext/duckdb/memory_helper.c +339 -0
- data/ext/duckdb/memory_helper.h +8 -0
- data/ext/duckdb/result.c +8 -9
- data/ext/duckdb/result.h +1 -0
- data/ext/duckdb/ruby-duckdb.h +7 -0
- data/ext/duckdb/scalar_function.c +336 -1
- data/ext/duckdb/scalar_function.h +2 -0
- data/ext/duckdb/table_function.c +403 -0
- data/ext/duckdb/table_function.h +16 -0
- data/ext/duckdb/vector.c +201 -0
- data/ext/duckdb/vector.h +13 -0
- data/lib/duckdb/appender.rb +21 -11
- data/lib/duckdb/bind_info.rb +32 -0
- data/lib/duckdb/casting.rb +35 -0
- data/lib/duckdb/connection.rb +123 -2
- data/lib/duckdb/converter.rb +32 -47
- data/lib/duckdb/data_chunk.rb +114 -0
- data/lib/duckdb/extracted_statements.rb +1 -1
- data/lib/duckdb/function_info.rb +21 -0
- data/lib/duckdb/init_info.rb +22 -0
- data/lib/duckdb/instance_cache.rb +0 -4
- data/lib/duckdb/interval.rb +1 -1
- data/lib/duckdb/logical_type.rb +46 -5
- data/lib/duckdb/prepared_statement.rb +22 -8
- data/lib/duckdb/result.rb +1 -0
- data/lib/duckdb/scalar_function.rb +119 -0
- data/lib/duckdb/table_function.rb +191 -0
- data/lib/duckdb/vector.rb +20 -0
- data/lib/duckdb/version.rb +1 -1
- data/lib/duckdb.rb +8 -0
- data/sample/async_query.rb +2 -0
- data/sample/async_query_stream.rb +2 -0
- data/sample/issue922.rb +54 -0
- data/sample/issue922_benchmark.rb +169 -0
- data/sample/issue930.rb +49 -0
- data/sample/issue930_benchmark.rb +70 -0
- metadata +30 -57
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
#include "ruby-duckdb.h"
|
|
2
|
+
|
|
3
|
+
VALUE cDuckDBBindInfo;
|
|
4
|
+
|
|
5
|
+
static void deallocate(void *ctx);
|
|
6
|
+
static VALUE allocate(VALUE klass);
|
|
7
|
+
static size_t memsize(const void *p);
|
|
8
|
+
static VALUE convert_duckdb_value_to_ruby(duckdb_value param_value);
|
|
9
|
+
static VALUE rbduckdb_bind_info_parameter_count(VALUE self);
|
|
10
|
+
static VALUE rbduckdb_bind_info_get_parameter(VALUE self, VALUE index);
|
|
11
|
+
static VALUE rbduckdb_bind_info_get_named_parameter(VALUE self, VALUE name);
|
|
12
|
+
static VALUE rbduckdb_bind_info__add_result_column(VALUE self, VALUE column_name, VALUE logical_type);
|
|
13
|
+
static VALUE rbduckdb_bind_info_set_cardinality(VALUE self, VALUE cardinality, VALUE is_exact);
|
|
14
|
+
static VALUE rbduckdb_bind_info_set_error(VALUE self, VALUE error);
|
|
15
|
+
|
|
16
|
+
static const rb_data_type_t bind_info_data_type = {
|
|
17
|
+
"DuckDB/BindInfo",
|
|
18
|
+
{NULL, deallocate, memsize,},
|
|
19
|
+
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
static void deallocate(void *ctx) {
|
|
23
|
+
rubyDuckDBBindInfo *p = (rubyDuckDBBindInfo *)ctx;
|
|
24
|
+
xfree(p);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
static VALUE allocate(VALUE klass) {
|
|
28
|
+
rubyDuckDBBindInfo *ctx = xcalloc((size_t)1, sizeof(rubyDuckDBBindInfo));
|
|
29
|
+
return TypedData_Wrap_Struct(klass, &bind_info_data_type, ctx);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
static size_t memsize(const void *p) {
|
|
33
|
+
return sizeof(rubyDuckDBBindInfo);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
rubyDuckDBBindInfo *get_struct_bind_info(VALUE obj) {
|
|
37
|
+
rubyDuckDBBindInfo *ctx;
|
|
38
|
+
TypedData_Get_Struct(obj, rubyDuckDBBindInfo, &bind_info_data_type, ctx);
|
|
39
|
+
return ctx;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/*
|
|
43
|
+
* Converts a duckdb_value to a Ruby VALUE.
|
|
44
|
+
* Handles basic types: BIGINT, INTEGER, VARCHAR, DOUBLE, BOOLEAN.
|
|
45
|
+
* Returns Qnil for unsupported types.
|
|
46
|
+
* Note: Caller must destroy duckdb_value and duckdb_logical_type.
|
|
47
|
+
*/
|
|
48
|
+
static VALUE convert_duckdb_value_to_ruby(duckdb_value param_value) {
|
|
49
|
+
duckdb_logical_type logical_type;
|
|
50
|
+
duckdb_type type_id;
|
|
51
|
+
VALUE result;
|
|
52
|
+
|
|
53
|
+
logical_type = duckdb_get_value_type(param_value);
|
|
54
|
+
type_id = duckdb_get_type_id(logical_type);
|
|
55
|
+
|
|
56
|
+
switch (type_id) {
|
|
57
|
+
case DUCKDB_TYPE_BIGINT:
|
|
58
|
+
result = LL2NUM(duckdb_get_int64(param_value));
|
|
59
|
+
break;
|
|
60
|
+
case DUCKDB_TYPE_INTEGER:
|
|
61
|
+
result = INT2NUM(duckdb_get_int32(param_value));
|
|
62
|
+
break;
|
|
63
|
+
case DUCKDB_TYPE_VARCHAR: {
|
|
64
|
+
char *str = duckdb_get_varchar(param_value);
|
|
65
|
+
result = rb_str_new_cstr(str);
|
|
66
|
+
duckdb_free(str);
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
case DUCKDB_TYPE_DOUBLE:
|
|
70
|
+
result = DBL2NUM(duckdb_get_double(param_value));
|
|
71
|
+
break;
|
|
72
|
+
case DUCKDB_TYPE_BOOLEAN:
|
|
73
|
+
result = duckdb_get_bool(param_value) ? Qtrue : Qfalse;
|
|
74
|
+
break;
|
|
75
|
+
default:
|
|
76
|
+
// For unsupported types, return nil
|
|
77
|
+
result = Qnil;
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
duckdb_destroy_logical_type(&logical_type);
|
|
82
|
+
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/*
|
|
87
|
+
* call-seq:
|
|
88
|
+
* bind_info.parameter_count -> Integer
|
|
89
|
+
*
|
|
90
|
+
* Returns the number of parameters passed to the table function.
|
|
91
|
+
*
|
|
92
|
+
* bind_info.parameter_count # => 2
|
|
93
|
+
*/
|
|
94
|
+
static VALUE rbduckdb_bind_info_parameter_count(VALUE self) {
|
|
95
|
+
rubyDuckDBBindInfo *ctx;
|
|
96
|
+
idx_t count;
|
|
97
|
+
|
|
98
|
+
TypedData_Get_Struct(self, rubyDuckDBBindInfo, &bind_info_data_type, ctx);
|
|
99
|
+
|
|
100
|
+
count = duckdb_bind_get_parameter_count(ctx->bind_info);
|
|
101
|
+
|
|
102
|
+
return ULL2NUM(count);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/*
|
|
106
|
+
* call-seq:
|
|
107
|
+
* bind_info.get_parameter(index) -> value
|
|
108
|
+
*
|
|
109
|
+
* Gets the parameter value at the given index.
|
|
110
|
+
*
|
|
111
|
+
* param = bind_info.get_parameter(0)
|
|
112
|
+
*/
|
|
113
|
+
static VALUE rbduckdb_bind_info_get_parameter(VALUE self, VALUE index) {
|
|
114
|
+
rubyDuckDBBindInfo *ctx;
|
|
115
|
+
idx_t idx;
|
|
116
|
+
duckdb_value param_value;
|
|
117
|
+
VALUE result;
|
|
118
|
+
|
|
119
|
+
TypedData_Get_Struct(self, rubyDuckDBBindInfo, &bind_info_data_type, ctx);
|
|
120
|
+
|
|
121
|
+
idx = NUM2ULL(index);
|
|
122
|
+
param_value = duckdb_bind_get_parameter(ctx->bind_info, idx);
|
|
123
|
+
|
|
124
|
+
result = convert_duckdb_value_to_ruby(param_value);
|
|
125
|
+
|
|
126
|
+
duckdb_destroy_value(¶m_value);
|
|
127
|
+
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/*
|
|
132
|
+
* call-seq:
|
|
133
|
+
* bind_info.get_named_parameter(name) -> value or nil
|
|
134
|
+
*
|
|
135
|
+
* Gets the named parameter value, or nil if not provided.
|
|
136
|
+
*
|
|
137
|
+
* param = bind_info.get_named_parameter('limit')
|
|
138
|
+
*/
|
|
139
|
+
static VALUE rbduckdb_bind_info_get_named_parameter(VALUE self, VALUE name) {
|
|
140
|
+
rubyDuckDBBindInfo *ctx;
|
|
141
|
+
const char *param_name;
|
|
142
|
+
duckdb_value param_value;
|
|
143
|
+
VALUE result;
|
|
144
|
+
|
|
145
|
+
TypedData_Get_Struct(self, rubyDuckDBBindInfo, &bind_info_data_type, ctx);
|
|
146
|
+
|
|
147
|
+
param_name = StringValueCStr(name);
|
|
148
|
+
param_value = duckdb_bind_get_named_parameter(ctx->bind_info, param_name);
|
|
149
|
+
|
|
150
|
+
// If parameter not found, return nil
|
|
151
|
+
if (!param_value) {
|
|
152
|
+
return Qnil;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
result = convert_duckdb_value_to_ruby(param_value);
|
|
156
|
+
|
|
157
|
+
duckdb_destroy_value(¶m_value);
|
|
158
|
+
|
|
159
|
+
return result;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/*
|
|
163
|
+
* call-seq:
|
|
164
|
+
* bind_info.add_result_column(name, logical_type) -> self
|
|
165
|
+
*
|
|
166
|
+
* Adds a column to the output schema.
|
|
167
|
+
*
|
|
168
|
+
* bind_info.add_result_column('id', DuckDB::LogicalType::BIGINT)
|
|
169
|
+
* bind_info.add_result_column('name', DuckDB::LogicalType::VARCHAR)
|
|
170
|
+
*/
|
|
171
|
+
static VALUE rbduckdb_bind_info__add_result_column(VALUE self, VALUE column_name, VALUE logical_type) {
|
|
172
|
+
rubyDuckDBBindInfo *ctx;
|
|
173
|
+
rubyDuckDBLogicalType *ctx_logical_type;
|
|
174
|
+
const char *col_name;
|
|
175
|
+
|
|
176
|
+
TypedData_Get_Struct(self, rubyDuckDBBindInfo, &bind_info_data_type, ctx);
|
|
177
|
+
ctx_logical_type = get_struct_logical_type(logical_type);
|
|
178
|
+
|
|
179
|
+
col_name = StringValueCStr(column_name);
|
|
180
|
+
duckdb_bind_add_result_column(ctx->bind_info, col_name, ctx_logical_type->logical_type);
|
|
181
|
+
|
|
182
|
+
return self;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/*
|
|
186
|
+
* call-seq:
|
|
187
|
+
* bind_info.set_cardinality(cardinality, is_exact) -> self
|
|
188
|
+
*
|
|
189
|
+
* Sets the estimated number of rows this function will return.
|
|
190
|
+
*
|
|
191
|
+
* bind_info.set_cardinality(100, true) # Exactly 100 rows
|
|
192
|
+
* bind_info.set_cardinality(1000, false) # Approximately 1000 rows
|
|
193
|
+
*/
|
|
194
|
+
static VALUE rbduckdb_bind_info_set_cardinality(VALUE self, VALUE cardinality, VALUE is_exact) {
|
|
195
|
+
rubyDuckDBBindInfo *ctx;
|
|
196
|
+
idx_t card;
|
|
197
|
+
bool exact;
|
|
198
|
+
|
|
199
|
+
TypedData_Get_Struct(self, rubyDuckDBBindInfo, &bind_info_data_type, ctx);
|
|
200
|
+
|
|
201
|
+
card = NUM2ULL(cardinality);
|
|
202
|
+
exact = RTEST(is_exact);
|
|
203
|
+
|
|
204
|
+
duckdb_bind_set_cardinality(ctx->bind_info, card, exact);
|
|
205
|
+
|
|
206
|
+
return self;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/*
|
|
210
|
+
* call-seq:
|
|
211
|
+
* bind_info.set_error(error_message) -> self
|
|
212
|
+
*
|
|
213
|
+
* Reports an error during bind phase.
|
|
214
|
+
*
|
|
215
|
+
* bind_info.set_error('Invalid parameter value')
|
|
216
|
+
*/
|
|
217
|
+
static VALUE rbduckdb_bind_info_set_error(VALUE self, VALUE error) {
|
|
218
|
+
rubyDuckDBBindInfo *ctx;
|
|
219
|
+
const char *error_msg;
|
|
220
|
+
|
|
221
|
+
TypedData_Get_Struct(self, rubyDuckDBBindInfo, &bind_info_data_type, ctx);
|
|
222
|
+
|
|
223
|
+
error_msg = StringValueCStr(error);
|
|
224
|
+
duckdb_bind_set_error(ctx->bind_info, error_msg);
|
|
225
|
+
|
|
226
|
+
return self;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
void rbduckdb_init_duckdb_bind_info(void) {
|
|
230
|
+
#if 0
|
|
231
|
+
VALUE mDuckDB = rb_define_module("DuckDB");
|
|
232
|
+
#endif
|
|
233
|
+
cDuckDBBindInfo = rb_define_class_under(mDuckDB, "BindInfo", rb_cObject);
|
|
234
|
+
rb_define_alloc_func(cDuckDBBindInfo, allocate);
|
|
235
|
+
|
|
236
|
+
rb_define_method(cDuckDBBindInfo, "parameter_count", rbduckdb_bind_info_parameter_count, 0);
|
|
237
|
+
rb_define_method(cDuckDBBindInfo, "get_parameter", rbduckdb_bind_info_get_parameter, 1);
|
|
238
|
+
rb_define_method(cDuckDBBindInfo, "get_named_parameter", rbduckdb_bind_info_get_named_parameter, 1);
|
|
239
|
+
rb_define_method(cDuckDBBindInfo, "set_cardinality", rbduckdb_bind_info_set_cardinality, 2);
|
|
240
|
+
rb_define_method(cDuckDBBindInfo, "set_error", rbduckdb_bind_info_set_error, 1);
|
|
241
|
+
|
|
242
|
+
rb_define_private_method(cDuckDBBindInfo, "_add_result_column", rbduckdb_bind_info__add_result_column, 2);
|
|
243
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#ifndef RUBY_DUCKDB_BIND_INFO_H
|
|
2
|
+
#define RUBY_DUCKDB_BIND_INFO_H
|
|
3
|
+
|
|
4
|
+
struct _rubyDuckDBBindInfo {
|
|
5
|
+
duckdb_bind_info bind_info;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
typedef struct _rubyDuckDBBindInfo rubyDuckDBBindInfo;
|
|
9
|
+
|
|
10
|
+
rubyDuckDBBindInfo *get_struct_bind_info(VALUE obj);
|
|
11
|
+
void rbduckdb_init_duckdb_bind_info(void);
|
|
12
|
+
|
|
13
|
+
#endif
|
data/ext/duckdb/connection.c
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
VALUE cDuckDBConnection;
|
|
4
4
|
|
|
5
5
|
static void deallocate(void *ctx);
|
|
6
|
+
static void mark(void *ctx);
|
|
6
7
|
static VALUE allocate(VALUE klass);
|
|
7
8
|
static size_t memsize(const void *p);
|
|
8
9
|
static VALUE duckdb_connection_disconnect(VALUE self);
|
|
@@ -10,10 +11,12 @@ static VALUE duckdb_connection_interrupt(VALUE self);
|
|
|
10
11
|
static VALUE duckdb_connection_query_progress(VALUE self);
|
|
11
12
|
static VALUE duckdb_connection_connect(VALUE self, VALUE oDuckDBDatabase);
|
|
12
13
|
static VALUE duckdb_connection_query_sql(VALUE self, VALUE str);
|
|
14
|
+
static VALUE duckdb_connection_register_scalar_function(VALUE self, VALUE scalar_function);
|
|
15
|
+
static VALUE duckdb_connection_register_table_function(VALUE self, VALUE table_function);
|
|
13
16
|
|
|
14
17
|
static const rb_data_type_t connection_data_type = {
|
|
15
18
|
"DuckDB/Connection",
|
|
16
|
-
{
|
|
19
|
+
{mark, deallocate, memsize,},
|
|
17
20
|
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
|
18
21
|
};
|
|
19
22
|
|
|
@@ -24,9 +27,18 @@ static void deallocate(void *ctx) {
|
|
|
24
27
|
xfree(p);
|
|
25
28
|
}
|
|
26
29
|
|
|
30
|
+
static void mark(void *ctx) {
|
|
31
|
+
rubyDuckDBConnection *p = (rubyDuckDBConnection *)ctx;
|
|
32
|
+
rb_gc_mark(p->registered_functions);
|
|
33
|
+
}
|
|
34
|
+
|
|
27
35
|
static VALUE allocate(VALUE klass) {
|
|
28
36
|
rubyDuckDBConnection *ctx = xcalloc((size_t)1, sizeof(rubyDuckDBConnection));
|
|
29
|
-
|
|
37
|
+
VALUE obj = TypedData_Wrap_Struct(klass, &connection_data_type, ctx);
|
|
38
|
+
VALUE registered_functions = rb_ary_new();
|
|
39
|
+
ctx->registered_functions = registered_functions;
|
|
40
|
+
RB_GC_GUARD(registered_functions);
|
|
41
|
+
return obj;
|
|
30
42
|
}
|
|
31
43
|
|
|
32
44
|
static size_t memsize(const void *p) {
|
|
@@ -62,6 +74,9 @@ static VALUE duckdb_connection_disconnect(VALUE self) {
|
|
|
62
74
|
TypedData_Get_Struct(self, rubyDuckDBConnection, &connection_data_type, ctx);
|
|
63
75
|
duckdb_disconnect(&(ctx->con));
|
|
64
76
|
|
|
77
|
+
/* Clear registered functions to release memory */
|
|
78
|
+
rb_ary_clear(ctx->registered_functions);
|
|
79
|
+
|
|
65
80
|
return self;
|
|
66
81
|
}
|
|
67
82
|
|
|
@@ -152,6 +167,47 @@ static VALUE duckdb_connection_query_sql(VALUE self, VALUE str) {
|
|
|
152
167
|
return result;
|
|
153
168
|
}
|
|
154
169
|
|
|
170
|
+
/* :nodoc: */
|
|
171
|
+
static VALUE duckdb_connection_register_scalar_function(VALUE self, VALUE scalar_function) {
|
|
172
|
+
rubyDuckDBConnection *ctxcon;
|
|
173
|
+
rubyDuckDBScalarFunction *ctxsf;
|
|
174
|
+
duckdb_state state;
|
|
175
|
+
|
|
176
|
+
ctxcon = get_struct_connection(self);
|
|
177
|
+
ctxsf = get_struct_scalar_function(scalar_function);
|
|
178
|
+
|
|
179
|
+
state = duckdb_register_scalar_function(ctxcon->con, ctxsf->scalar_function);
|
|
180
|
+
|
|
181
|
+
if (state == DuckDBError) {
|
|
182
|
+
rb_raise(eDuckDBError, "Failed to register scalar function");
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/* Keep reference to prevent GC while connection is alive */
|
|
186
|
+
rb_ary_push(ctxcon->registered_functions, scalar_function);
|
|
187
|
+
|
|
188
|
+
return self;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
static VALUE duckdb_connection_register_table_function(VALUE self, VALUE table_function) {
|
|
192
|
+
rubyDuckDBConnection *ctxcon;
|
|
193
|
+
rubyDuckDBTableFunction *ctxtf;
|
|
194
|
+
duckdb_state state;
|
|
195
|
+
|
|
196
|
+
ctxcon = get_struct_connection(self);
|
|
197
|
+
ctxtf = get_struct_table_function(table_function);
|
|
198
|
+
|
|
199
|
+
state = duckdb_register_table_function(ctxcon->con, ctxtf->table_function);
|
|
200
|
+
|
|
201
|
+
if (state == DuckDBError) {
|
|
202
|
+
rb_raise(eDuckDBError, "Failed to register table function");
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/* Keep reference to prevent GC while connection is alive */
|
|
206
|
+
rb_ary_push(ctxcon->registered_functions, table_function);
|
|
207
|
+
|
|
208
|
+
return self;
|
|
209
|
+
}
|
|
210
|
+
|
|
155
211
|
void rbduckdb_init_duckdb_connection(void) {
|
|
156
212
|
#if 0
|
|
157
213
|
VALUE mDuckDB = rb_define_module("DuckDB");
|
|
@@ -162,6 +218,8 @@ void rbduckdb_init_duckdb_connection(void) {
|
|
|
162
218
|
rb_define_method(cDuckDBConnection, "disconnect", duckdb_connection_disconnect, 0);
|
|
163
219
|
rb_define_method(cDuckDBConnection, "interrupt", duckdb_connection_interrupt, 0);
|
|
164
220
|
rb_define_method(cDuckDBConnection, "query_progress", duckdb_connection_query_progress, 0);
|
|
221
|
+
rb_define_private_method(cDuckDBConnection, "_register_scalar_function", duckdb_connection_register_scalar_function, 1);
|
|
222
|
+
rb_define_private_method(cDuckDBConnection, "_register_table_function", duckdb_connection_register_table_function, 1);
|
|
165
223
|
rb_define_private_method(cDuckDBConnection, "_connect", duckdb_connection_connect, 1);
|
|
166
224
|
/* TODO: query_sql => _query_sql */
|
|
167
225
|
rb_define_private_method(cDuckDBConnection, "query_sql", duckdb_connection_query_sql, 1);
|
data/ext/duckdb/connection.h
CHANGED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
#include "ruby-duckdb.h"
|
|
2
|
+
|
|
3
|
+
VALUE cDuckDBDataChunk;
|
|
4
|
+
extern VALUE cDuckDBVector;
|
|
5
|
+
|
|
6
|
+
static void deallocate(void *ctx);
|
|
7
|
+
static VALUE allocate(VALUE klass);
|
|
8
|
+
static size_t memsize(const void *p);
|
|
9
|
+
static VALUE rbduckdb_data_chunk_column_count(VALUE self);
|
|
10
|
+
static VALUE rbduckdb_data_chunk_get_size(VALUE self);
|
|
11
|
+
static VALUE rbduckdb_data_chunk_set_size(VALUE self, VALUE size);
|
|
12
|
+
static VALUE rbduckdb_data_chunk_get_vector(VALUE self, VALUE col_idx);
|
|
13
|
+
|
|
14
|
+
static const rb_data_type_t data_chunk_data_type = {
|
|
15
|
+
"DuckDB/DataChunk",
|
|
16
|
+
{NULL, deallocate, memsize,},
|
|
17
|
+
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
static void deallocate(void *ctx) {
|
|
21
|
+
rubyDuckDBDataChunk *p = (rubyDuckDBDataChunk *)ctx;
|
|
22
|
+
xfree(p);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static VALUE allocate(VALUE klass) {
|
|
26
|
+
rubyDuckDBDataChunk *ctx = xcalloc((size_t)1, sizeof(rubyDuckDBDataChunk));
|
|
27
|
+
return TypedData_Wrap_Struct(klass, &data_chunk_data_type, ctx);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static size_t memsize(const void *p) {
|
|
31
|
+
return sizeof(rubyDuckDBDataChunk);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
rubyDuckDBDataChunk *get_struct_data_chunk(VALUE obj) {
|
|
35
|
+
rubyDuckDBDataChunk *ctx;
|
|
36
|
+
TypedData_Get_Struct(obj, rubyDuckDBDataChunk, &data_chunk_data_type, ctx);
|
|
37
|
+
return ctx;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/*
|
|
41
|
+
* call-seq:
|
|
42
|
+
* data_chunk.column_count -> Integer
|
|
43
|
+
*
|
|
44
|
+
* Returns the number of columns in the data chunk.
|
|
45
|
+
*
|
|
46
|
+
* data_chunk.column_count # => 2
|
|
47
|
+
*/
|
|
48
|
+
static VALUE rbduckdb_data_chunk_column_count(VALUE self) {
|
|
49
|
+
rubyDuckDBDataChunk *ctx;
|
|
50
|
+
idx_t count;
|
|
51
|
+
|
|
52
|
+
TypedData_Get_Struct(self, rubyDuckDBDataChunk, &data_chunk_data_type, ctx);
|
|
53
|
+
|
|
54
|
+
count = duckdb_data_chunk_get_column_count(ctx->data_chunk);
|
|
55
|
+
|
|
56
|
+
return ULL2NUM(count);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/*
|
|
60
|
+
* call-seq:
|
|
61
|
+
* data_chunk.size -> Integer
|
|
62
|
+
*
|
|
63
|
+
* Returns the current number of tuples in the data chunk.
|
|
64
|
+
*
|
|
65
|
+
* data_chunk.size # => 100
|
|
66
|
+
*/
|
|
67
|
+
static VALUE rbduckdb_data_chunk_get_size(VALUE self) {
|
|
68
|
+
rubyDuckDBDataChunk *ctx;
|
|
69
|
+
idx_t size;
|
|
70
|
+
|
|
71
|
+
TypedData_Get_Struct(self, rubyDuckDBDataChunk, &data_chunk_data_type, ctx);
|
|
72
|
+
|
|
73
|
+
size = duckdb_data_chunk_get_size(ctx->data_chunk);
|
|
74
|
+
|
|
75
|
+
return ULL2NUM(size);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/*
|
|
79
|
+
* call-seq:
|
|
80
|
+
* data_chunk.size = size -> size
|
|
81
|
+
*
|
|
82
|
+
* Sets the number of tuples in the data chunk.
|
|
83
|
+
*
|
|
84
|
+
* data_chunk.size = 50
|
|
85
|
+
*/
|
|
86
|
+
static VALUE rbduckdb_data_chunk_set_size(VALUE self, VALUE size) {
|
|
87
|
+
rubyDuckDBDataChunk *ctx;
|
|
88
|
+
idx_t sz;
|
|
89
|
+
|
|
90
|
+
TypedData_Get_Struct(self, rubyDuckDBDataChunk, &data_chunk_data_type, ctx);
|
|
91
|
+
|
|
92
|
+
sz = NUM2ULL(size);
|
|
93
|
+
duckdb_data_chunk_set_size(ctx->data_chunk, sz);
|
|
94
|
+
|
|
95
|
+
return size;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/*
|
|
99
|
+
* call-seq:
|
|
100
|
+
* data_chunk.get_vector(col_idx) -> DuckDB::Vector
|
|
101
|
+
*
|
|
102
|
+
* Gets the vector at the specified column index.
|
|
103
|
+
*
|
|
104
|
+
* vector = data_chunk.get_vector(0)
|
|
105
|
+
*/
|
|
106
|
+
static VALUE rbduckdb_data_chunk_get_vector(VALUE self, VALUE col_idx) {
|
|
107
|
+
rubyDuckDBDataChunk *ctx;
|
|
108
|
+
idx_t idx;
|
|
109
|
+
duckdb_vector vector;
|
|
110
|
+
VALUE vector_obj;
|
|
111
|
+
rubyDuckDBVector *vector_ctx;
|
|
112
|
+
|
|
113
|
+
TypedData_Get_Struct(self, rubyDuckDBDataChunk, &data_chunk_data_type, ctx);
|
|
114
|
+
|
|
115
|
+
idx = NUM2ULL(col_idx);
|
|
116
|
+
vector = duckdb_data_chunk_get_vector(ctx->data_chunk, idx);
|
|
117
|
+
|
|
118
|
+
// Create Vector wrapper
|
|
119
|
+
vector_obj = rb_class_new_instance(0, NULL, cDuckDBVector);
|
|
120
|
+
vector_ctx = get_struct_vector(vector_obj);
|
|
121
|
+
vector_ctx->vector = vector;
|
|
122
|
+
|
|
123
|
+
return vector_obj;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
void rbduckdb_init_duckdb_data_chunk(void) {
|
|
127
|
+
#if 0
|
|
128
|
+
VALUE mDuckDB = rb_define_module("DuckDB");
|
|
129
|
+
#endif
|
|
130
|
+
cDuckDBDataChunk = rb_define_class_under(mDuckDB, "DataChunk", rb_cObject);
|
|
131
|
+
rb_define_alloc_func(cDuckDBDataChunk, allocate);
|
|
132
|
+
|
|
133
|
+
rb_define_method(cDuckDBDataChunk, "column_count", rbduckdb_data_chunk_column_count, 0);
|
|
134
|
+
rb_define_method(cDuckDBDataChunk, "size", rbduckdb_data_chunk_get_size, 0);
|
|
135
|
+
rb_define_method(cDuckDBDataChunk, "size=", rbduckdb_data_chunk_set_size, 1);
|
|
136
|
+
rb_define_method(cDuckDBDataChunk, "get_vector", rbduckdb_data_chunk_get_vector, 1);
|
|
137
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#ifndef RUBY_DUCKDB_DATA_CHUNK_H
|
|
2
|
+
#define RUBY_DUCKDB_DATA_CHUNK_H
|
|
3
|
+
|
|
4
|
+
struct _rubyDuckDBDataChunk {
|
|
5
|
+
duckdb_data_chunk data_chunk;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
typedef struct _rubyDuckDBDataChunk rubyDuckDBDataChunk;
|
|
9
|
+
|
|
10
|
+
rubyDuckDBDataChunk *get_struct_data_chunk(VALUE obj);
|
|
11
|
+
void rbduckdb_init_duckdb_data_chunk(void);
|
|
12
|
+
|
|
13
|
+
#endif
|
data/ext/duckdb/duckdb.c
CHANGED
|
@@ -42,4 +42,11 @@ Init_duckdb_native(void) {
|
|
|
42
42
|
rbduckdb_init_duckdb_instance_cache();
|
|
43
43
|
rbduckdb_init_duckdb_value_impl();
|
|
44
44
|
rbduckdb_init_duckdb_scalar_function();
|
|
45
|
+
rbduckdb_init_duckdb_bind_info();
|
|
46
|
+
rbduckdb_init_duckdb_init_info();
|
|
47
|
+
rbduckdb_init_duckdb_function_info();
|
|
48
|
+
rbduckdb_init_duckdb_vector();
|
|
49
|
+
rbduckdb_init_duckdb_data_chunk();
|
|
50
|
+
rbduckdb_init_memory_helper();
|
|
51
|
+
rbduckdb_init_duckdb_table_function();
|
|
45
52
|
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#include "ruby-duckdb.h"
|
|
2
|
+
|
|
3
|
+
VALUE cDuckDBFunctionInfo;
|
|
4
|
+
|
|
5
|
+
static void deallocate(void *ctx);
|
|
6
|
+
static VALUE allocate(VALUE klass);
|
|
7
|
+
static size_t memsize(const void *p);
|
|
8
|
+
static VALUE rbduckdb_function_info_set_error(VALUE self, VALUE error);
|
|
9
|
+
|
|
10
|
+
static const rb_data_type_t function_info_data_type = {
|
|
11
|
+
"DuckDB/FunctionInfo",
|
|
12
|
+
{NULL, deallocate, memsize,},
|
|
13
|
+
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
static void deallocate(void *ctx) {
|
|
17
|
+
rubyDuckDBFunctionInfo *p = (rubyDuckDBFunctionInfo *)ctx;
|
|
18
|
+
xfree(p);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static VALUE allocate(VALUE klass) {
|
|
22
|
+
rubyDuckDBFunctionInfo *ctx = xcalloc((size_t)1, sizeof(rubyDuckDBFunctionInfo));
|
|
23
|
+
return TypedData_Wrap_Struct(klass, &function_info_data_type, ctx);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
static size_t memsize(const void *p) {
|
|
27
|
+
return sizeof(rubyDuckDBFunctionInfo);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
rubyDuckDBFunctionInfo *get_struct_function_info(VALUE obj) {
|
|
31
|
+
rubyDuckDBFunctionInfo *ctx;
|
|
32
|
+
TypedData_Get_Struct(obj, rubyDuckDBFunctionInfo, &function_info_data_type, ctx);
|
|
33
|
+
return ctx;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/*
|
|
37
|
+
* call-seq:
|
|
38
|
+
* function_info.set_error(error_message) -> self
|
|
39
|
+
*
|
|
40
|
+
* Sets an error message for the function execution.
|
|
41
|
+
* This will cause the query to fail with the specified error.
|
|
42
|
+
*
|
|
43
|
+
* function_info.set_error('Invalid parameter value')
|
|
44
|
+
*/
|
|
45
|
+
static VALUE rbduckdb_function_info_set_error(VALUE self, VALUE error) {
|
|
46
|
+
rubyDuckDBFunctionInfo *ctx;
|
|
47
|
+
const char *error_msg;
|
|
48
|
+
|
|
49
|
+
TypedData_Get_Struct(self, rubyDuckDBFunctionInfo, &function_info_data_type, ctx);
|
|
50
|
+
|
|
51
|
+
error_msg = StringValueCStr(error);
|
|
52
|
+
duckdb_function_set_error(ctx->info, error_msg);
|
|
53
|
+
|
|
54
|
+
return self;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
void rbduckdb_init_duckdb_function_info(void) {
|
|
58
|
+
#if 0
|
|
59
|
+
VALUE mDuckDB = rb_define_module("DuckDB");
|
|
60
|
+
#endif
|
|
61
|
+
cDuckDBFunctionInfo = rb_define_class_under(mDuckDB, "FunctionInfo", rb_cObject);
|
|
62
|
+
rb_define_alloc_func(cDuckDBFunctionInfo, allocate);
|
|
63
|
+
|
|
64
|
+
rb_define_method(cDuckDBFunctionInfo, "set_error", rbduckdb_function_info_set_error, 1);
|
|
65
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#ifndef RUBY_DUCKDB_FUNCTION_INFO_H
|
|
2
|
+
#define RUBY_DUCKDB_FUNCTION_INFO_H
|
|
3
|
+
|
|
4
|
+
struct _rubyDuckDBFunctionInfo {
|
|
5
|
+
duckdb_function_info info;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
typedef struct _rubyDuckDBFunctionInfo rubyDuckDBFunctionInfo;
|
|
9
|
+
|
|
10
|
+
rubyDuckDBFunctionInfo *get_struct_function_info(VALUE obj);
|
|
11
|
+
void rbduckdb_init_duckdb_function_info(void);
|
|
12
|
+
|
|
13
|
+
#endif
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#include "ruby-duckdb.h"
|
|
2
|
+
|
|
3
|
+
VALUE cDuckDBInitInfo;
|
|
4
|
+
|
|
5
|
+
static void deallocate(void *ctx);
|
|
6
|
+
static VALUE allocate(VALUE klass);
|
|
7
|
+
static size_t memsize(const void *p);
|
|
8
|
+
static VALUE rbduckdb_init_info_set_error(VALUE self, VALUE error);
|
|
9
|
+
|
|
10
|
+
static const rb_data_type_t init_info_data_type = {
|
|
11
|
+
"DuckDB/InitInfo",
|
|
12
|
+
{NULL, deallocate, memsize,},
|
|
13
|
+
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
static void deallocate(void *ctx) {
|
|
17
|
+
rubyDuckDBInitInfo *p = (rubyDuckDBInitInfo *)ctx;
|
|
18
|
+
xfree(p);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static VALUE allocate(VALUE klass) {
|
|
22
|
+
rubyDuckDBInitInfo *ctx = xcalloc((size_t)1, sizeof(rubyDuckDBInitInfo));
|
|
23
|
+
return TypedData_Wrap_Struct(klass, &init_info_data_type, ctx);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
static size_t memsize(const void *p) {
|
|
27
|
+
return sizeof(rubyDuckDBInitInfo);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
rubyDuckDBInitInfo *get_struct_init_info(VALUE obj) {
|
|
31
|
+
rubyDuckDBInitInfo *ctx;
|
|
32
|
+
TypedData_Get_Struct(obj, rubyDuckDBInitInfo, &init_info_data_type, ctx);
|
|
33
|
+
return ctx;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/*
|
|
37
|
+
* call-seq:
|
|
38
|
+
* init_info.set_error(error_message) -> self
|
|
39
|
+
*
|
|
40
|
+
* Sets an error message for the init phase.
|
|
41
|
+
* This will cause the query to fail with the specified error.
|
|
42
|
+
*
|
|
43
|
+
* init_info.set_error('Invalid initialization')
|
|
44
|
+
*/
|
|
45
|
+
static VALUE rbduckdb_init_info_set_error(VALUE self, VALUE error) {
|
|
46
|
+
rubyDuckDBInitInfo *ctx;
|
|
47
|
+
const char *error_msg;
|
|
48
|
+
|
|
49
|
+
TypedData_Get_Struct(self, rubyDuckDBInitInfo, &init_info_data_type, ctx);
|
|
50
|
+
|
|
51
|
+
error_msg = StringValueCStr(error);
|
|
52
|
+
duckdb_init_set_error(ctx->info, error_msg);
|
|
53
|
+
|
|
54
|
+
return self;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
void rbduckdb_init_duckdb_init_info(void) {
|
|
58
|
+
#if 0
|
|
59
|
+
VALUE mDuckDB = rb_define_module("DuckDB");
|
|
60
|
+
#endif
|
|
61
|
+
cDuckDBInitInfo = rb_define_class_under(mDuckDB, "InitInfo", rb_cObject);
|
|
62
|
+
rb_define_alloc_func(cDuckDBInitInfo, allocate);
|
|
63
|
+
|
|
64
|
+
rb_define_method(cDuckDBInitInfo, "set_error", rbduckdb_init_info_set_error, 1);
|
|
65
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#ifndef RUBY_DUCKDB_INIT_INFO_H
|
|
2
|
+
#define RUBY_DUCKDB_INIT_INFO_H
|
|
3
|
+
|
|
4
|
+
struct _rubyDuckDBInitInfo {
|
|
5
|
+
duckdb_init_info info;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
typedef struct _rubyDuckDBInitInfo rubyDuckDBInitInfo;
|
|
9
|
+
|
|
10
|
+
rubyDuckDBInitInfo *get_struct_init_info(VALUE obj);
|
|
11
|
+
void rbduckdb_init_duckdb_init_info(void);
|
|
12
|
+
|
|
13
|
+
#endif
|