duckdb 1.5.2.0 → 1.5.2.1
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 +9 -0
- data/duckdb.gemspec +37 -0
- data/ext/duckdb/aggregate_function.c +61 -100
- data/ext/duckdb/aggregate_function.h +2 -2
- data/ext/duckdb/appender.c +76 -35
- data/ext/duckdb/appender.h +1 -1
- data/ext/duckdb/client_context.c +5 -5
- data/ext/duckdb/client_context.h +2 -2
- data/ext/duckdb/column.c +13 -13
- data/ext/duckdb/column.h +1 -1
- data/ext/duckdb/connection.c +40 -41
- data/ext/duckdb/connection.h +2 -2
- data/ext/duckdb/converter.h +1 -7
- data/ext/duckdb/conveter.c +6 -6
- data/ext/duckdb/data_chunk.c +22 -22
- data/ext/duckdb/data_chunk.h +2 -2
- data/ext/duckdb/database.c +10 -10
- data/ext/duckdb/database.h +1 -1
- data/ext/duckdb/duckdb.c +17 -17
- data/ext/duckdb/expression.c +8 -8
- data/ext/duckdb/expression.h +1 -1
- data/ext/duckdb/extconf.rb +4 -3
- data/ext/duckdb/extracted_statements.c +15 -15
- data/ext/duckdb/extracted_statements.h +1 -1
- data/ext/duckdb/instance_cache.c +10 -10
- data/ext/duckdb/instance_cache.h +1 -1
- data/ext/duckdb/logical_type.c +94 -133
- data/ext/duckdb/logical_type.h +2 -2
- data/ext/duckdb/memory_helper.c +28 -28
- data/ext/duckdb/pending_result.c +27 -27
- data/ext/duckdb/pending_result.h +2 -2
- data/ext/duckdb/prepared_statement.c +103 -103
- data/ext/duckdb/prepared_statement.h +2 -2
- data/ext/duckdb/result.c +33 -33
- data/ext/duckdb/result.h +2 -3
- data/ext/duckdb/ruby-duckdb.h +4 -0
- data/ext/duckdb/scalar_function.c +3 -3
- data/ext/duckdb/table_description.c +1 -1
- data/ext/duckdb/table_function.c +3 -3
- data/ext/duckdb/table_function_bind_info.c +1 -1
- data/ext/duckdb/value.c +62 -50
- data/ext/duckdb/value.h +2 -2
- data/ext/duckdb/vector.c +20 -20
- data/ext/duckdb/vector.h +2 -2
- data/lib/duckdb/aggregate_function.rb +202 -3
- data/lib/duckdb/appender.rb +74 -0
- data/lib/duckdb/connection.rb +1 -16
- data/lib/duckdb/converter.rb +5 -0
- data/lib/duckdb/logical_type.rb +1 -3
- data/lib/duckdb/prepared_statement.rb +1 -1
- data/lib/duckdb/table_function.rb +0 -1
- data/lib/duckdb/value.rb +19 -0
- data/lib/duckdb/version.rb +1 -1
- metadata +2 -2
- data/lib/duckdb/duckdb_native.so +0 -0
data/ext/duckdb/ruby-duckdb.h
CHANGED
|
@@ -139,7 +139,7 @@ static VALUE rbduckdb_scalar_function__set_return_type(VALUE self, VALUE logical
|
|
|
139
139
|
rubyDuckDBLogicalType *lt;
|
|
140
140
|
|
|
141
141
|
TypedData_Get_Struct(self, rubyDuckDBScalarFunction, &scalar_function_data_type, p);
|
|
142
|
-
lt =
|
|
142
|
+
lt = rbduckdb_get_struct_logical_type(logical_type);
|
|
143
143
|
|
|
144
144
|
duckdb_scalar_function_set_return_type(p->scalar_function, lt->logical_type);
|
|
145
145
|
|
|
@@ -151,7 +151,7 @@ static VALUE rbduckdb_scalar_function__set_varargs(VALUE self, VALUE logical_typ
|
|
|
151
151
|
rubyDuckDBLogicalType *lt;
|
|
152
152
|
|
|
153
153
|
TypedData_Get_Struct(self, rubyDuckDBScalarFunction, &scalar_function_data_type, p);
|
|
154
|
-
lt =
|
|
154
|
+
lt = rbduckdb_get_struct_logical_type(logical_type);
|
|
155
155
|
|
|
156
156
|
duckdb_scalar_function_set_varargs(p->scalar_function, lt->logical_type);
|
|
157
157
|
|
|
@@ -172,7 +172,7 @@ static VALUE rbduckdb_scalar_function_add_parameter(VALUE self, VALUE logical_ty
|
|
|
172
172
|
rubyDuckDBLogicalType *lt;
|
|
173
173
|
|
|
174
174
|
TypedData_Get_Struct(self, rubyDuckDBScalarFunction, &scalar_function_data_type, p);
|
|
175
|
-
lt =
|
|
175
|
+
lt = rbduckdb_get_struct_logical_type(logical_type);
|
|
176
176
|
|
|
177
177
|
duckdb_scalar_function_add_parameter(p->scalar_function, lt->logical_type);
|
|
178
178
|
|
|
@@ -70,7 +70,7 @@ static VALUE duckdb_table_description__initialize(VALUE self, VALUE con, VALUE c
|
|
|
70
70
|
if (!NIL_P(table)) {
|
|
71
71
|
ptable = StringValuePtr(table);
|
|
72
72
|
}
|
|
73
|
-
ctxcon =
|
|
73
|
+
ctxcon = rbduckdb_get_struct_connection(con);
|
|
74
74
|
ctx = get_struct_table_description(self);
|
|
75
75
|
|
|
76
76
|
if (ctx->table_description) {
|
data/ext/duckdb/table_function.c
CHANGED
|
@@ -148,7 +148,7 @@ static VALUE rbduckdb_table_function_add_parameter(VALUE self, VALUE logical_typ
|
|
|
148
148
|
rb_raise(eDuckDBError, "Table function is destroyed");
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
ctx_logical_type =
|
|
151
|
+
ctx_logical_type = rbduckdb_get_struct_logical_type(logical_type);
|
|
152
152
|
duckdb_table_function_add_parameter(ctx->table_function, ctx_logical_type->logical_type);
|
|
153
153
|
|
|
154
154
|
return self;
|
|
@@ -174,7 +174,7 @@ static VALUE rbduckdb_table_function_add_named_parameter(VALUE self, VALUE name,
|
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
param_name = StringValueCStr(name);
|
|
177
|
-
ctx_logical_type =
|
|
177
|
+
ctx_logical_type = rbduckdb_get_struct_logical_type(logical_type);
|
|
178
178
|
duckdb_table_function_add_named_parameter(ctx->table_function, param_name, ctx_logical_type->logical_type);
|
|
179
179
|
|
|
180
180
|
return self;
|
|
@@ -388,7 +388,7 @@ static void execute_execute_callback_protected(void *user_data) {
|
|
|
388
388
|
func_info_ctx->info = darg->info;
|
|
389
389
|
|
|
390
390
|
data_chunk_obj = rb_class_new_instance(0, NULL, cDuckDBDataChunk);
|
|
391
|
-
data_chunk_ctx =
|
|
391
|
+
data_chunk_ctx = rbduckdb_get_struct_data_chunk(data_chunk_obj);
|
|
392
392
|
data_chunk_ctx->data_chunk = darg->output;
|
|
393
393
|
|
|
394
394
|
VALUE call_args[3] = { darg->ctx->execute_proc, func_info_obj, data_chunk_obj };
|
|
@@ -135,7 +135,7 @@ static VALUE rbduckdb_bind_info__add_result_column(VALUE self, VALUE column_name
|
|
|
135
135
|
const char *col_name;
|
|
136
136
|
|
|
137
137
|
TypedData_Get_Struct(self, rubyDuckDBBindInfo, &bind_info_data_type, ctx);
|
|
138
|
-
ctx_logical_type =
|
|
138
|
+
ctx_logical_type = rbduckdb_get_struct_logical_type(logical_type);
|
|
139
139
|
|
|
140
140
|
col_name = StringValueCStr(column_name);
|
|
141
141
|
duckdb_bind_add_result_column(ctx->bind_info, col_name, ctx_logical_type->logical_type);
|
data/ext/duckdb/value.c
CHANGED
|
@@ -5,22 +5,23 @@ VALUE cDuckDBValue;
|
|
|
5
5
|
static void deallocate(void *);
|
|
6
6
|
static VALUE allocate(VALUE klass);
|
|
7
7
|
static size_t memsize(const void *p);
|
|
8
|
-
static VALUE
|
|
9
|
-
static VALUE
|
|
10
|
-
static VALUE
|
|
11
|
-
static VALUE
|
|
12
|
-
static VALUE
|
|
13
|
-
static VALUE
|
|
14
|
-
static VALUE
|
|
15
|
-
static VALUE
|
|
16
|
-
static VALUE
|
|
17
|
-
static VALUE
|
|
18
|
-
static VALUE
|
|
19
|
-
static VALUE
|
|
20
|
-
static VALUE
|
|
21
|
-
static VALUE
|
|
22
|
-
static VALUE
|
|
23
|
-
static VALUE
|
|
8
|
+
static VALUE value_s__create_bool(VALUE klass, VALUE flag);
|
|
9
|
+
static VALUE value_s__create_int8(VALUE klass, VALUE val);
|
|
10
|
+
static VALUE value_s__create_int16(VALUE klass, VALUE val);
|
|
11
|
+
static VALUE value_s__create_int32(VALUE klass, VALUE val);
|
|
12
|
+
static VALUE value_s__create_int64(VALUE klass, VALUE val);
|
|
13
|
+
static VALUE value_s__create_uint8(VALUE klass, VALUE val);
|
|
14
|
+
static VALUE value_s__create_uint16(VALUE klass, VALUE val);
|
|
15
|
+
static VALUE value_s__create_uint32(VALUE klass, VALUE val);
|
|
16
|
+
static VALUE value_s__create_uint64(VALUE klass, VALUE val);
|
|
17
|
+
static VALUE value_s__create_float(VALUE klass, VALUE val);
|
|
18
|
+
static VALUE value_s__create_double(VALUE klass, VALUE val);
|
|
19
|
+
static VALUE value_s__create_varchar(VALUE klass, VALUE str);
|
|
20
|
+
static VALUE value_s__create_blob(VALUE klass, VALUE str);
|
|
21
|
+
static VALUE value_s__create_hugeint(VALUE klass, VALUE lower, VALUE upper);
|
|
22
|
+
static VALUE value_s__create_uhugeint(VALUE klass, VALUE lower, VALUE upper);
|
|
23
|
+
static VALUE value_s__create_decimal(VALUE klass, VALUE lower, VALUE upper, VALUE width, VALUE scale);
|
|
24
|
+
static VALUE value_s_create_null(VALUE klass);
|
|
24
25
|
|
|
25
26
|
static const rb_data_type_t value_data_type = {
|
|
26
27
|
"DuckDB/Value",
|
|
@@ -44,76 +45,76 @@ static size_t memsize(const void *p) {
|
|
|
44
45
|
return sizeof(rubyDuckDBValue);
|
|
45
46
|
}
|
|
46
47
|
|
|
47
|
-
static VALUE
|
|
48
|
+
static VALUE value_s__create_bool(VALUE klass, VALUE flag) {
|
|
48
49
|
duckdb_value value = duckdb_create_bool(RTEST(flag) ? true : false);
|
|
49
50
|
return rbduckdb_value_new(value);
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
static VALUE
|
|
53
|
+
static VALUE value_s__create_int8(VALUE klass, VALUE val) {
|
|
53
54
|
duckdb_value value = duckdb_create_int8((int8_t)NUM2INT(val));
|
|
54
55
|
return rbduckdb_value_new(value);
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
static VALUE
|
|
58
|
+
static VALUE value_s__create_int16(VALUE klass, VALUE val) {
|
|
58
59
|
duckdb_value value = duckdb_create_int16((int16_t)NUM2INT(val));
|
|
59
60
|
return rbduckdb_value_new(value);
|
|
60
61
|
}
|
|
61
62
|
|
|
62
|
-
static VALUE
|
|
63
|
+
static VALUE value_s__create_int32(VALUE klass, VALUE val) {
|
|
63
64
|
duckdb_value value = duckdb_create_int32(NUM2INT(val));
|
|
64
65
|
return rbduckdb_value_new(value);
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
static VALUE
|
|
68
|
+
static VALUE value_s__create_int64(VALUE klass, VALUE val) {
|
|
68
69
|
duckdb_value value = duckdb_create_int64((int64_t)NUM2LL(val));
|
|
69
70
|
return rbduckdb_value_new(value);
|
|
70
71
|
}
|
|
71
72
|
|
|
72
|
-
static VALUE
|
|
73
|
+
static VALUE value_s__create_uint8(VALUE klass, VALUE val) {
|
|
73
74
|
duckdb_value value = duckdb_create_uint8((uint8_t)NUM2UINT(val));
|
|
74
75
|
return rbduckdb_value_new(value);
|
|
75
76
|
}
|
|
76
77
|
|
|
77
|
-
static VALUE
|
|
78
|
+
static VALUE value_s__create_uint16(VALUE klass, VALUE val) {
|
|
78
79
|
duckdb_value value = duckdb_create_uint16((uint16_t)NUM2UINT(val));
|
|
79
80
|
return rbduckdb_value_new(value);
|
|
80
81
|
}
|
|
81
82
|
|
|
82
|
-
static VALUE
|
|
83
|
+
static VALUE value_s__create_uint32(VALUE klass, VALUE val) {
|
|
83
84
|
duckdb_value value = duckdb_create_uint32((uint32_t)NUM2UINT(val));
|
|
84
85
|
return rbduckdb_value_new(value);
|
|
85
86
|
}
|
|
86
87
|
|
|
87
|
-
static VALUE
|
|
88
|
+
static VALUE value_s__create_uint64(VALUE klass, VALUE val) {
|
|
88
89
|
duckdb_value value = duckdb_create_uint64((uint64_t)RB_NUM2ULL(val));
|
|
89
90
|
return rbduckdb_value_new(value);
|
|
90
91
|
}
|
|
91
92
|
|
|
92
|
-
static VALUE
|
|
93
|
+
static VALUE value_s__create_float(VALUE klass, VALUE val) {
|
|
93
94
|
duckdb_value value = duckdb_create_float((float)NUM2DBL(val));
|
|
94
95
|
return rbduckdb_value_new(value);
|
|
95
96
|
}
|
|
96
97
|
|
|
97
|
-
static VALUE
|
|
98
|
+
static VALUE value_s__create_double(VALUE klass, VALUE val) {
|
|
98
99
|
duckdb_value value = duckdb_create_double(NUM2DBL(val));
|
|
99
100
|
return rbduckdb_value_new(value);
|
|
100
101
|
}
|
|
101
102
|
|
|
102
|
-
static VALUE
|
|
103
|
+
static VALUE value_s__create_varchar(VALUE klass, VALUE str) {
|
|
103
104
|
const char *str_ptr = StringValuePtr(str);
|
|
104
105
|
idx_t str_len = RSTRING_LEN(str);
|
|
105
106
|
duckdb_value value = duckdb_create_varchar_length(str_ptr, str_len);
|
|
106
107
|
return rbduckdb_value_new(value);
|
|
107
108
|
}
|
|
108
109
|
|
|
109
|
-
static VALUE
|
|
110
|
+
static VALUE value_s__create_blob(VALUE klass, VALUE str) {
|
|
110
111
|
const uint8_t *data_ptr = (const uint8_t *)StringValuePtr(str);
|
|
111
112
|
idx_t data_len = RSTRING_LEN(str);
|
|
112
113
|
duckdb_value value = duckdb_create_blob(data_ptr, data_len);
|
|
113
114
|
return rbduckdb_value_new(value);
|
|
114
115
|
}
|
|
115
116
|
|
|
116
|
-
static VALUE
|
|
117
|
+
static VALUE value_s__create_hugeint(VALUE klass, VALUE lower, VALUE upper) {
|
|
117
118
|
duckdb_hugeint hugeint;
|
|
118
119
|
hugeint.lower = NUM2ULL(lower);
|
|
119
120
|
hugeint.upper = NUM2LL(upper);
|
|
@@ -121,7 +122,7 @@ static VALUE duckdb_value_s__create_hugeint(VALUE klass, VALUE lower, VALUE uppe
|
|
|
121
122
|
return rbduckdb_value_new(value);
|
|
122
123
|
}
|
|
123
124
|
|
|
124
|
-
static VALUE
|
|
125
|
+
static VALUE value_s__create_uhugeint(VALUE klass, VALUE lower, VALUE upper) {
|
|
125
126
|
duckdb_uhugeint uhugeint;
|
|
126
127
|
uhugeint.lower = NUM2ULL(lower);
|
|
127
128
|
uhugeint.upper = NUM2ULL(upper);
|
|
@@ -129,6 +130,16 @@ static VALUE duckdb_value_s__create_uhugeint(VALUE klass, VALUE lower, VALUE upp
|
|
|
129
130
|
return rbduckdb_value_new(value);
|
|
130
131
|
}
|
|
131
132
|
|
|
133
|
+
static VALUE value_s__create_decimal(VALUE klass, VALUE lower, VALUE upper, VALUE width, VALUE scale) {
|
|
134
|
+
duckdb_decimal decimal;
|
|
135
|
+
decimal.value.lower = NUM2ULL(lower);
|
|
136
|
+
decimal.value.upper = NUM2LL(upper);
|
|
137
|
+
decimal.width = (uint8_t)NUM2UINT(width);
|
|
138
|
+
decimal.scale = (uint8_t)NUM2UINT(scale);
|
|
139
|
+
duckdb_value value = duckdb_create_decimal(decimal);
|
|
140
|
+
return rbduckdb_value_new(value);
|
|
141
|
+
}
|
|
142
|
+
|
|
132
143
|
/*
|
|
133
144
|
* call-seq:
|
|
134
145
|
* DuckDB::Value.create_null -> DuckDB::Value
|
|
@@ -138,7 +149,7 @@ static VALUE duckdb_value_s__create_uhugeint(VALUE klass, VALUE lower, VALUE upp
|
|
|
138
149
|
* require 'duckdb'
|
|
139
150
|
* value = DuckDB::Value.create_null
|
|
140
151
|
*/
|
|
141
|
-
static VALUE
|
|
152
|
+
static VALUE value_s_create_null(VALUE klass) {
|
|
142
153
|
duckdb_value value = duckdb_create_null_value();
|
|
143
154
|
return rbduckdb_value_new(value);
|
|
144
155
|
}
|
|
@@ -151,7 +162,7 @@ VALUE rbduckdb_value_new(duckdb_value value) {
|
|
|
151
162
|
return obj;
|
|
152
163
|
}
|
|
153
164
|
|
|
154
|
-
rubyDuckDBValue *
|
|
165
|
+
rubyDuckDBValue *rbduckdb_get_struct_value(VALUE obj) {
|
|
155
166
|
rubyDuckDBValue *ctx;
|
|
156
167
|
TypedData_Get_Struct(obj, rubyDuckDBValue, &value_data_type, ctx);
|
|
157
168
|
return ctx;
|
|
@@ -252,28 +263,29 @@ VALUE rbduckdb_duckdb_value_to_ruby(duckdb_value val) {
|
|
|
252
263
|
return result;
|
|
253
264
|
}
|
|
254
265
|
|
|
255
|
-
void
|
|
266
|
+
void rbduckdb_init_value(void) {
|
|
256
267
|
#if 0
|
|
257
268
|
VALUE mDuckDB = rb_define_module("DuckDB");
|
|
258
269
|
#endif
|
|
259
270
|
cDuckDBValue = rb_define_class_under(mDuckDB, "Value", rb_cObject);
|
|
260
271
|
rb_define_alloc_func(cDuckDBValue, allocate);
|
|
261
272
|
|
|
262
|
-
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_bool",
|
|
263
|
-
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_int8",
|
|
264
|
-
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_int16",
|
|
265
|
-
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_int32",
|
|
266
|
-
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_int64",
|
|
267
|
-
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_uint8",
|
|
268
|
-
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_uint16",
|
|
269
|
-
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_uint32",
|
|
270
|
-
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_uint64",
|
|
271
|
-
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_float",
|
|
272
|
-
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_double",
|
|
273
|
-
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_varchar",
|
|
274
|
-
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_blob",
|
|
275
|
-
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_hugeint",
|
|
276
|
-
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_uhugeint",
|
|
277
|
-
|
|
273
|
+
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_bool", value_s__create_bool, 1);
|
|
274
|
+
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_int8", value_s__create_int8, 1);
|
|
275
|
+
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_int16", value_s__create_int16, 1);
|
|
276
|
+
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_int32", value_s__create_int32, 1);
|
|
277
|
+
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_int64", value_s__create_int64, 1);
|
|
278
|
+
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_uint8", value_s__create_uint8, 1);
|
|
279
|
+
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_uint16", value_s__create_uint16, 1);
|
|
280
|
+
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_uint32", value_s__create_uint32, 1);
|
|
281
|
+
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_uint64", value_s__create_uint64, 1);
|
|
282
|
+
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_float", value_s__create_float, 1);
|
|
283
|
+
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_double", value_s__create_double, 1);
|
|
284
|
+
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_varchar", value_s__create_varchar, 1);
|
|
285
|
+
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_blob", value_s__create_blob, 1);
|
|
286
|
+
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_hugeint", value_s__create_hugeint, 2);
|
|
287
|
+
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_uhugeint", value_s__create_uhugeint, 2);
|
|
288
|
+
rb_define_private_method(rb_singleton_class(cDuckDBValue), "_create_decimal", value_s__create_decimal, 4);
|
|
289
|
+
rb_define_singleton_method(cDuckDBValue, "create_null", value_s_create_null, 0);
|
|
278
290
|
}
|
|
279
291
|
|
data/ext/duckdb/value.h
CHANGED
|
@@ -7,9 +7,9 @@ struct _rubyDuckDBValue {
|
|
|
7
7
|
|
|
8
8
|
typedef struct _rubyDuckDBValue rubyDuckDBValue;
|
|
9
9
|
|
|
10
|
-
void
|
|
10
|
+
void rbduckdb_init_value(void);
|
|
11
11
|
VALUE rbduckdb_value_new(duckdb_value value);
|
|
12
12
|
VALUE rbduckdb_duckdb_value_to_ruby(duckdb_value val);
|
|
13
|
-
rubyDuckDBValue *
|
|
13
|
+
rubyDuckDBValue *rbduckdb_get_struct_value(VALUE obj);
|
|
14
14
|
|
|
15
15
|
#endif
|
data/ext/duckdb/vector.c
CHANGED
|
@@ -5,12 +5,12 @@ VALUE cDuckDBVector;
|
|
|
5
5
|
static void deallocate(void *ctx);
|
|
6
6
|
static VALUE allocate(VALUE klass);
|
|
7
7
|
static size_t memsize(const void *p);
|
|
8
|
-
static VALUE
|
|
9
|
-
static VALUE
|
|
10
|
-
static VALUE
|
|
11
|
-
static VALUE
|
|
12
|
-
static VALUE
|
|
13
|
-
static VALUE
|
|
8
|
+
static VALUE vector_get_data(VALUE self);
|
|
9
|
+
static VALUE vector_get_validity(VALUE self);
|
|
10
|
+
static VALUE vector_assign_string_element(VALUE self, VALUE index, VALUE str);
|
|
11
|
+
static VALUE vector_assign_string_element_len(VALUE self, VALUE index, VALUE str);
|
|
12
|
+
static VALUE vector_logical_type(VALUE self);
|
|
13
|
+
static VALUE vector_set_validity(VALUE self, VALUE index, VALUE valid);
|
|
14
14
|
|
|
15
15
|
static const rb_data_type_t vector_data_type = {
|
|
16
16
|
"DuckDB/Vector",
|
|
@@ -32,7 +32,7 @@ static size_t memsize(const void *p) {
|
|
|
32
32
|
return sizeof(rubyDuckDBVector);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
rubyDuckDBVector *
|
|
35
|
+
rubyDuckDBVector *rbduckdb_get_struct_vector(VALUE obj) {
|
|
36
36
|
rubyDuckDBVector *ctx;
|
|
37
37
|
TypedData_Get_Struct(obj, rubyDuckDBVector, &vector_data_type, ctx);
|
|
38
38
|
return ctx;
|
|
@@ -47,7 +47,7 @@ rubyDuckDBVector *get_struct_vector(VALUE obj) {
|
|
|
47
47
|
*
|
|
48
48
|
* ptr = vector.get_data
|
|
49
49
|
*/
|
|
50
|
-
static VALUE
|
|
50
|
+
static VALUE vector_get_data(VALUE self) {
|
|
51
51
|
rubyDuckDBVector *ctx;
|
|
52
52
|
void *data;
|
|
53
53
|
|
|
@@ -67,7 +67,7 @@ static VALUE rbduckdb_vector_get_data(VALUE self) {
|
|
|
67
67
|
*
|
|
68
68
|
* validity = vector.get_validity
|
|
69
69
|
*/
|
|
70
|
-
static VALUE
|
|
70
|
+
static VALUE vector_get_validity(VALUE self) {
|
|
71
71
|
rubyDuckDBVector *ctx;
|
|
72
72
|
uint64_t *validity;
|
|
73
73
|
|
|
@@ -90,7 +90,7 @@ static VALUE rbduckdb_vector_get_validity(VALUE self) {
|
|
|
90
90
|
*
|
|
91
91
|
* vector.assign_string_element(0, 'hello')
|
|
92
92
|
*/
|
|
93
|
-
static VALUE
|
|
93
|
+
static VALUE vector_assign_string_element(VALUE self, VALUE index, VALUE str) {
|
|
94
94
|
rubyDuckDBVector *ctx;
|
|
95
95
|
idx_t idx;
|
|
96
96
|
const char *string_val;
|
|
@@ -114,7 +114,7 @@ static VALUE rbduckdb_vector_assign_string_element(VALUE self, VALUE index, VALU
|
|
|
114
114
|
*
|
|
115
115
|
* vector.assign_string_element_len(0, "\x00\x01\x02\x03")
|
|
116
116
|
*/
|
|
117
|
-
static VALUE
|
|
117
|
+
static VALUE vector_assign_string_element_len(VALUE self, VALUE index, VALUE str) {
|
|
118
118
|
rubyDuckDBVector *ctx;
|
|
119
119
|
idx_t idx;
|
|
120
120
|
const char *string_val;
|
|
@@ -141,7 +141,7 @@ static VALUE rbduckdb_vector_assign_string_element_len(VALUE self, VALUE index,
|
|
|
141
141
|
* type = vector.logical_type
|
|
142
142
|
* type.id #=> DuckDB::Type::BIGINT
|
|
143
143
|
*/
|
|
144
|
-
static VALUE
|
|
144
|
+
static VALUE vector_logical_type(VALUE self) {
|
|
145
145
|
rubyDuckDBVector *ctx;
|
|
146
146
|
duckdb_logical_type logical_type;
|
|
147
147
|
|
|
@@ -161,7 +161,7 @@ static VALUE rbduckdb_vector_logical_type(VALUE self) {
|
|
|
161
161
|
* vector.set_validity(0, false) # Mark row 0 as NULL
|
|
162
162
|
* vector.set_validity(1, true) # Mark row 1 as valid
|
|
163
163
|
*/
|
|
164
|
-
static VALUE
|
|
164
|
+
static VALUE vector_set_validity(VALUE self, VALUE index, VALUE valid) {
|
|
165
165
|
rubyDuckDBVector *ctx;
|
|
166
166
|
idx_t idx;
|
|
167
167
|
uint64_t *validity;
|
|
@@ -185,17 +185,17 @@ static VALUE rbduckdb_vector_set_validity(VALUE self, VALUE index, VALUE valid)
|
|
|
185
185
|
return self;
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
void
|
|
188
|
+
void rbduckdb_init_vector(void) {
|
|
189
189
|
#if 0
|
|
190
190
|
VALUE mDuckDB = rb_define_module("DuckDB");
|
|
191
191
|
#endif
|
|
192
192
|
cDuckDBVector = rb_define_class_under(mDuckDB, "Vector", rb_cObject);
|
|
193
193
|
rb_define_alloc_func(cDuckDBVector, allocate);
|
|
194
194
|
|
|
195
|
-
rb_define_method(cDuckDBVector, "get_data",
|
|
196
|
-
rb_define_method(cDuckDBVector, "get_validity",
|
|
197
|
-
rb_define_method(cDuckDBVector, "assign_string_element",
|
|
198
|
-
rb_define_method(cDuckDBVector, "assign_string_element_len",
|
|
199
|
-
rb_define_method(cDuckDBVector, "logical_type",
|
|
200
|
-
rb_define_method(cDuckDBVector, "set_validity",
|
|
195
|
+
rb_define_method(cDuckDBVector, "get_data", vector_get_data, 0);
|
|
196
|
+
rb_define_method(cDuckDBVector, "get_validity", vector_get_validity, 0);
|
|
197
|
+
rb_define_method(cDuckDBVector, "assign_string_element", vector_assign_string_element, 2);
|
|
198
|
+
rb_define_method(cDuckDBVector, "assign_string_element_len", vector_assign_string_element_len, 2);
|
|
199
|
+
rb_define_method(cDuckDBVector, "logical_type", vector_logical_type, 0);
|
|
200
|
+
rb_define_method(cDuckDBVector, "set_validity", vector_set_validity, 2);
|
|
201
201
|
}
|
data/ext/duckdb/vector.h
CHANGED
|
@@ -7,7 +7,7 @@ struct _rubyDuckDBVector {
|
|
|
7
7
|
|
|
8
8
|
typedef struct _rubyDuckDBVector rubyDuckDBVector;
|
|
9
9
|
|
|
10
|
-
rubyDuckDBVector *
|
|
11
|
-
void
|
|
10
|
+
rubyDuckDBVector *rbduckdb_get_struct_vector(VALUE obj);
|
|
11
|
+
void rbduckdb_init_vector(void);
|
|
12
12
|
|
|
13
13
|
#endif
|
|
@@ -1,13 +1,153 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module DuckDB
|
|
4
|
-
# DuckDB::AggregateFunction
|
|
4
|
+
# DuckDB::AggregateFunction lets you register a custom aggregate function
|
|
5
|
+
# written in Ruby and call it from SQL.
|
|
5
6
|
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
7
|
+
# An aggregate function folds many rows into a single value. You define its
|
|
8
|
+
# behaviour with four callbacks:
|
|
9
|
+
#
|
|
10
|
+
# * +set_init+ — called once per group; returns the initial state.
|
|
11
|
+
# * +set_update+ — called once per row; receives the current state and the
|
|
12
|
+
# input value(s), returns the new state.
|
|
13
|
+
# * +set_combine+ — merges two partial states (required for parallel
|
|
14
|
+
# execution); receives source and target states, returns the
|
|
15
|
+
# merged state.
|
|
16
|
+
# * +set_finalize+ — converts the final state into the SQL result value.
|
|
17
|
+
#
|
|
18
|
+
# Only +set_init+ is required. The other three have sensible defaults:
|
|
19
|
+
# * +set_update+ defaults to +{ |state, *| state }+ (ignore inputs)
|
|
20
|
+
# * +set_combine+ defaults to +{ |s1, _s2| s1 }+ (keep source state)
|
|
21
|
+
# * +set_finalize+ defaults to +{ |x| x }+ (return state as-is)
|
|
22
|
+
#
|
|
23
|
+
# @note The default +set_combine+ keeps the source state and discards the
|
|
24
|
+
# target, which is only correct for single-threaded (single-partition)
|
|
25
|
+
# execution. If DuckDB runs the aggregate in parallel it will produce
|
|
26
|
+
# wrong results. Always supply an explicit +set_combine+ when the
|
|
27
|
+
# aggregate must be parallel-safe.
|
|
28
|
+
#
|
|
29
|
+
# == Basic example: custom SUM
|
|
30
|
+
#
|
|
31
|
+
# af = DuckDB::AggregateFunction.new
|
|
32
|
+
# af.name = 'my_sum'
|
|
33
|
+
# af.return_type = DuckDB::LogicalType::BIGINT
|
|
34
|
+
# af.add_parameter(DuckDB::LogicalType::BIGINT)
|
|
35
|
+
#
|
|
36
|
+
# af.set_init { 0 }
|
|
37
|
+
# af.set_update { |state, value| state + value }
|
|
38
|
+
# af.set_combine { |s1, s2| s1 + s2 }
|
|
39
|
+
#
|
|
40
|
+
# con.register_aggregate_function(af)
|
|
41
|
+
# con.query('SELECT my_sum(i) FROM range(100) t(i)').first.first # => 4950
|
|
42
|
+
#
|
|
43
|
+
# == Example: weighted average with Hash state
|
|
44
|
+
#
|
|
45
|
+
# af = DuckDB::AggregateFunction.new
|
|
46
|
+
# af.name = 'weighted_avg'
|
|
47
|
+
# af.return_type = DuckDB::LogicalType::DOUBLE
|
|
48
|
+
# af.add_parameter(DuckDB::LogicalType::DOUBLE) # value
|
|
49
|
+
# af.add_parameter(DuckDB::LogicalType::DOUBLE) # weight
|
|
50
|
+
#
|
|
51
|
+
# af.set_init { { sum: 0.0, weight: 0.0 } }
|
|
52
|
+
# af.set_update { |state, value, weight| { sum: state[:sum] + value * weight, weight: state[:weight] + weight } }
|
|
53
|
+
# af.set_combine { |s1, s2| { sum: s1[:sum] + s2[:sum], weight: s1[:weight] + s2[:weight] } }
|
|
54
|
+
# af.set_finalize { |state| state[:weight].zero? ? nil : state[:sum] / state[:weight] }
|
|
55
|
+
#
|
|
56
|
+
# con.register_aggregate_function(af)
|
|
8
57
|
class AggregateFunction
|
|
9
58
|
include FunctionTypeValidation
|
|
10
59
|
|
|
60
|
+
class << self
|
|
61
|
+
# Creates a new AggregateFunction in a single call.
|
|
62
|
+
#
|
|
63
|
+
# This is a convenience factory that builds and configures an
|
|
64
|
+
# AggregateFunction without requiring you to set each attribute
|
|
65
|
+
# separately.
|
|
66
|
+
#
|
|
67
|
+
# @param name [String] the SQL function name
|
|
68
|
+
# @param return_type [DuckDB::LogicalType | Symbol] the SQL return type
|
|
69
|
+
# @param params [Array<DuckDB::LogicalType | Symbol>] input parameter types
|
|
70
|
+
# (empty array for a zero-argument aggregate)
|
|
71
|
+
# @param init [#call] callable that returns the initial per-group state
|
|
72
|
+
# @param update [#call] callable that folds one row into the state;
|
|
73
|
+
# receives +state, *inputs+ and must return the updated state.
|
|
74
|
+
# Default: +->( state, *) { state }+ (ignore inputs)
|
|
75
|
+
# @param combine [#call] callable that merges two partial states;
|
|
76
|
+
# receives +source_state, target_state+ and must return the merged
|
|
77
|
+
# state. Default: +->(state, _other) { state }+ (keep source only —
|
|
78
|
+
# only correct for single-threaded execution)
|
|
79
|
+
# @param finalize [#call] callable that converts the final state into the
|
|
80
|
+
# SQL result value; receives +state+ and must return a value compatible
|
|
81
|
+
# with +return_type+.
|
|
82
|
+
# Default: +->(state) { state }+ (return state as-is)
|
|
83
|
+
# @param null_handling [Boolean] when +true+, enables special NULL
|
|
84
|
+
# handling so that rows with NULL inputs are passed to +update+ as
|
|
85
|
+
# +nil+ instead of being skipped (default: +false+)
|
|
86
|
+
# @return [DuckDB::AggregateFunction] the configured aggregate function,
|
|
87
|
+
# ready to be passed to +Connection#register_aggregate_function+
|
|
88
|
+
# @raise [ArgumentError] if any of +init+, +update+, +combine+, or
|
|
89
|
+
# +finalize+ does not respond to +call+
|
|
90
|
+
#
|
|
91
|
+
# == Example: custom SUM
|
|
92
|
+
#
|
|
93
|
+
# af = DuckDB::AggregateFunction.create(
|
|
94
|
+
# name: 'my_sum',
|
|
95
|
+
# return_type: :bigint,
|
|
96
|
+
# params: [:bigint],
|
|
97
|
+
# init: -> { 0 },
|
|
98
|
+
# update: ->(state, value) { state + value },
|
|
99
|
+
# combine: ->(state, other) { state + other }
|
|
100
|
+
# )
|
|
101
|
+
# con.register_aggregate_function(af)
|
|
102
|
+
# con.query('SELECT my_sum(i) FROM range(100) t(i)').first.first # => 4950
|
|
103
|
+
#
|
|
104
|
+
# == Example: count including NULL values
|
|
105
|
+
#
|
|
106
|
+
# af = DuckDB::AggregateFunction.create(
|
|
107
|
+
# name: 'count_with_nulls',
|
|
108
|
+
# return_type: :bigint,
|
|
109
|
+
# params: [:bigint],
|
|
110
|
+
# init: -> { 0 },
|
|
111
|
+
# update: ->(state, _value) { state + 1 },
|
|
112
|
+
# combine: ->(state, other) { state + other },
|
|
113
|
+
# null_handling: true
|
|
114
|
+
# )
|
|
115
|
+
def create( # rubocop:disable Metrics/MethodLength, Metrics/ParameterLists, Metrics/AbcSize
|
|
116
|
+
name:,
|
|
117
|
+
return_type:,
|
|
118
|
+
params: [], # rubocop:disable Style/KeywordParametersOrder
|
|
119
|
+
init:,
|
|
120
|
+
update: ->(state, *_inputs) { state },
|
|
121
|
+
combine: ->(state, _other_state) { state },
|
|
122
|
+
finalize: ->(state) { state },
|
|
123
|
+
null_handling: false
|
|
124
|
+
)
|
|
125
|
+
callable!(:init, init)
|
|
126
|
+
callable!(:update, update)
|
|
127
|
+
callable!(:combine, combine)
|
|
128
|
+
callable!(:finalize, finalize)
|
|
129
|
+
|
|
130
|
+
af = AggregateFunction.new
|
|
131
|
+
af.name = name
|
|
132
|
+
af.return_type = return_type
|
|
133
|
+
params.each do |param|
|
|
134
|
+
af.add_parameter(param)
|
|
135
|
+
end
|
|
136
|
+
af.set_init { init.call }
|
|
137
|
+
af.set_update { |state, *inputs| update.call(state, *inputs) }
|
|
138
|
+
af.set_combine { |state, other_state| combine.call(state, other_state) }
|
|
139
|
+
af.set_finalize { |state| finalize.call(state) }
|
|
140
|
+
af.set_special_handling if null_handling
|
|
141
|
+
af
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
private
|
|
145
|
+
|
|
146
|
+
def callable!(name, arg)
|
|
147
|
+
raise ArgumentError, "#{name} must respond to `call`" unless arg.respond_to?(:call)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
11
151
|
# Sets the return type for the aggregate function.
|
|
12
152
|
#
|
|
13
153
|
# @param logical_type [DuckDB::LogicalType | :logical_type_symbol] the return type
|
|
@@ -30,6 +170,65 @@ module DuckDB
|
|
|
30
170
|
_add_parameter(logical_type)
|
|
31
171
|
end
|
|
32
172
|
|
|
173
|
+
# Sets the block that initialises the per-group state.
|
|
174
|
+
# The block takes no arguments and returns the initial state value.
|
|
175
|
+
# This is the only required callback; defaults for +set_update+,
|
|
176
|
+
# +set_combine+, and +set_finalize+ are injected automatically on the
|
|
177
|
+
# first call if those methods have not been called explicitly.
|
|
178
|
+
#
|
|
179
|
+
# @note The injected default for +set_combine+ is +{ |s1, _s2| s1 }+, which
|
|
180
|
+
# is only correct for single-threaded execution. Always call +set_combine+
|
|
181
|
+
# explicitly when the aggregate must be parallel-safe.
|
|
182
|
+
#
|
|
183
|
+
# @return [DuckDB::AggregateFunction] self
|
|
184
|
+
def set_init(&)
|
|
185
|
+
unless @init_set
|
|
186
|
+
_set_update { |state, *| state } unless @update_set
|
|
187
|
+
_set_combine { |s1, _s2| s1 } unless @combine_set
|
|
188
|
+
_set_finalize { |x| x } unless @finalize_set
|
|
189
|
+
end
|
|
190
|
+
_set_init(&)
|
|
191
|
+
@init_set = true
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# Sets the block that accumulates one row into the state.
|
|
195
|
+
# The block receives the current state followed by the input column
|
|
196
|
+
# value(s) for that row, and must return the updated state.
|
|
197
|
+
# Default: +{ |state, *| state }+ (ignore inputs, keep state unchanged).
|
|
198
|
+
# May be called after +set_init+ to override the injected default.
|
|
199
|
+
#
|
|
200
|
+
# @return [DuckDB::AggregateFunction] self
|
|
201
|
+
def set_update(&)
|
|
202
|
+
@update_set = true
|
|
203
|
+
_set_update(&)
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# Sets the block that merges two partial states during parallel execution.
|
|
207
|
+
# The block receives the source and target states and must return the
|
|
208
|
+
# merged state.
|
|
209
|
+
# May be called after +set_init+ to override the injected default.
|
|
210
|
+
#
|
|
211
|
+
# @note The default +{ |s1, _s2| s1 }+ is only correct for single-threaded
|
|
212
|
+
# execution. Supply an explicit combine block for parallel-safe aggregates.
|
|
213
|
+
#
|
|
214
|
+
# @return [DuckDB::AggregateFunction] self
|
|
215
|
+
def set_combine(&)
|
|
216
|
+
@combine_set = true
|
|
217
|
+
_set_combine(&)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# Sets the block that converts the final state into the SQL result value.
|
|
221
|
+
# The block receives the accumulated state and must return a value
|
|
222
|
+
# compatible with the declared +return_type+.
|
|
223
|
+
# Default: +{ |x| x }+ (return the state as-is).
|
|
224
|
+
# May be called after +set_init+ to override the injected default.
|
|
225
|
+
#
|
|
226
|
+
# @return [DuckDB::AggregateFunction] self
|
|
227
|
+
def set_finalize(&)
|
|
228
|
+
@finalize_set = true
|
|
229
|
+
_set_finalize(&)
|
|
230
|
+
end
|
|
231
|
+
|
|
33
232
|
# Sets special NULL handling for the aggregate function.
|
|
34
233
|
# By default DuckDB skips rows with NULL input values. Calling this
|
|
35
234
|
# method disables that behaviour so the update callback is invoked even
|