duckdb 1.2.1.0 → 1.2.2.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/workflows/test_on_macos.yml +2 -2
- data/.github/workflows/test_on_ubuntu.yml +2 -2
- data/.github/workflows/test_on_windows.yml +3 -2
- data/CHANGELOG.md +12 -0
- data/Dockerfile +1 -1
- data/Gemfile.lock +8 -8
- data/ext/duckdb/database.c +8 -0
- data/ext/duckdb/database.h +1 -0
- data/ext/duckdb/duckdb.c +3 -0
- data/ext/duckdb/instance_cache.c +108 -0
- data/ext/duckdb/instance_cache.h +17 -0
- data/ext/duckdb/logical_type.c +119 -0
- data/ext/duckdb/prepared_statement.c +65 -0
- data/ext/duckdb/ruby-duckdb.h +8 -0
- data/lib/duckdb/instance_cache.rb +26 -0
- data/lib/duckdb/logical_type.rb +43 -0
- data/lib/duckdb/prepared_statement.rb +40 -0
- data/lib/duckdb/version.rb +1 -1
- data/lib/duckdb.rb +1 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9dc90028f52da778feed9afafb7e1bddfa8128120dea8c798fec4c21317cc8e1
|
4
|
+
data.tar.gz: 5cb1ae0ae04c712c0edcd5dc61ac7a05c12e6ee59c7c72a113f8ea3a8012aa2e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3dce5d6c09d593ae95e59aed616ce83d1849136bcbfe7b1f668e8e515a1c8941cf18bd62593bfaec7a4f587731e2cad841d03d0d743da49c3c18ae7f346e3528
|
7
|
+
data.tar.gz: 5852c870293bd442e2afcf8c624fe21c1695803f4102a065b142d6c64b8639dc793af30852717742571d6d49d89d4753b4df805173a36f895fbc6bbaaa446c8b
|
@@ -15,8 +15,8 @@ jobs:
|
|
15
15
|
runs-on: macos-latest
|
16
16
|
strategy:
|
17
17
|
matrix:
|
18
|
-
ruby: ['3.
|
19
|
-
duckdb: ['1.2.
|
18
|
+
ruby: ['3.2.7', '3.3.8', '3.4.2', 'head']
|
19
|
+
duckdb: ['1.2.2', '1.1.3', '1.1.1']
|
20
20
|
|
21
21
|
steps:
|
22
22
|
- uses: actions/checkout@v4
|
@@ -15,8 +15,8 @@ jobs:
|
|
15
15
|
runs-on: ubuntu-latest
|
16
16
|
strategy:
|
17
17
|
matrix:
|
18
|
-
ruby: ['3.
|
19
|
-
duckdb: ['1.2.
|
18
|
+
ruby: ['3.2.7', '3.3.8', '3.4.2', 'head']
|
19
|
+
duckdb: ['1.2.2', '1.1.3', '1.1.1']
|
20
20
|
|
21
21
|
steps:
|
22
22
|
- uses: actions/checkout@v4
|
@@ -15,8 +15,9 @@ jobs:
|
|
15
15
|
runs-on: windows-latest
|
16
16
|
strategy:
|
17
17
|
matrix:
|
18
|
-
ruby: ['3.
|
19
|
-
|
18
|
+
# ruby: ['3.2.6', '3.3.6', '3.4.1', 'ucrt', 'mingw', 'mswin', 'head']
|
19
|
+
ruby: ['3.2.6', '3.3.6', '3.4.1', 'ucrt', 'mingw', 'mswin']
|
20
|
+
duckdb: ['1.2.2', '1.1.3', '1.1.1']
|
20
21
|
|
21
22
|
steps:
|
22
23
|
- uses: actions/checkout@v4
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,18 @@
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
# Unreleased
|
5
5
|
|
6
|
+
# 1.2.2.0 - 2025-05-11
|
7
|
+
- drop Ruby 3.1.
|
8
|
+
- implement `DuckDB::InstanceCache` class.
|
9
|
+
- bump duckdb to 1.2.2 on CI.
|
10
|
+
- add `DuckDB::PreparedStatement#bind_uint8`, `DuckDB::PreparedStatement#bind_uint16`,
|
11
|
+
`DuckDB::PreparedStatement#bind_uint32`, `DuckDB::PreparedStatement#bind_uint64`.
|
12
|
+
- add `DuckDB::LogicalType` class.
|
13
|
+
- `DuckDB::LogicalType` class is under construction. `DuckDB::LogicalType#internal_type`,
|
14
|
+
`DuckDB::LogicalType#dictionary_size`, `DuckDB::LogicalType#dictionary_value_at`,
|
15
|
+
`DuckDB::LogicalType#each_dictionary_value`, `DuckDB::LogicalType#alias`, and
|
16
|
+
`DuckDB::LogicalType#alias=`are available.
|
17
|
+
|
6
18
|
# 1.2.1.0 - 2025-03-30
|
7
19
|
- bump duckdb v1.2.1 on CI.
|
8
20
|
- drop duckdb v1.0.0.
|
data/Dockerfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
duckdb (1.2.
|
4
|
+
duckdb (1.2.2.0)
|
5
5
|
bigdecimal (>= 3.1.4)
|
6
6
|
|
7
7
|
GEM
|
@@ -11,22 +11,22 @@ GEM
|
|
11
11
|
bigdecimal (3.1.9)
|
12
12
|
mini_portile2 (2.8.8)
|
13
13
|
minitest (5.25.5)
|
14
|
-
nokogiri (1.18.
|
14
|
+
nokogiri (1.18.8)
|
15
15
|
mini_portile2 (~> 2.8.2)
|
16
16
|
racc (~> 1.4)
|
17
|
-
nokogiri (1.18.
|
17
|
+
nokogiri (1.18.8-aarch64-linux-gnu)
|
18
18
|
racc (~> 1.4)
|
19
|
-
nokogiri (1.18.
|
19
|
+
nokogiri (1.18.8-arm-linux-gnu)
|
20
20
|
racc (~> 1.4)
|
21
|
-
nokogiri (1.18.
|
21
|
+
nokogiri (1.18.8-arm64-darwin)
|
22
22
|
racc (~> 1.4)
|
23
|
-
nokogiri (1.18.
|
23
|
+
nokogiri (1.18.8-x86_64-darwin)
|
24
24
|
racc (~> 1.4)
|
25
|
-
nokogiri (1.18.
|
25
|
+
nokogiri (1.18.8-x86_64-linux-gnu)
|
26
26
|
racc (~> 1.4)
|
27
27
|
racc (1.8.1)
|
28
28
|
rake (13.2.1)
|
29
|
-
rake-compiler (1.
|
29
|
+
rake-compiler (1.3.0)
|
30
30
|
rake
|
31
31
|
ruby_memcheck (3.0.1)
|
32
32
|
nokogiri
|
data/ext/duckdb/database.c
CHANGED
@@ -118,6 +118,14 @@ static VALUE duckdb_database_close(VALUE self) {
|
|
118
118
|
return self;
|
119
119
|
}
|
120
120
|
|
121
|
+
VALUE rbduckdb_create_database_obj(duckdb_database db) {
|
122
|
+
VALUE obj = allocate(cDuckDBDatabase);
|
123
|
+
rubyDuckDB *ctx;
|
124
|
+
TypedData_Get_Struct(obj, rubyDuckDB, &database_data_type, ctx);
|
125
|
+
ctx->db = db;
|
126
|
+
return obj;
|
127
|
+
}
|
128
|
+
|
121
129
|
void rbduckdb_init_duckdb_database(void) {
|
122
130
|
#if 0
|
123
131
|
VALUE mDuckDB = rb_define_module("DuckDB");
|
data/ext/duckdb/database.h
CHANGED
data/ext/duckdb/duckdb.c
CHANGED
@@ -0,0 +1,108 @@
|
|
1
|
+
#include "ruby-duckdb.h"
|
2
|
+
|
3
|
+
#ifdef HAVE_DUCKDB_H_GE_V1_2_0
|
4
|
+
VALUE cDuckDBInstanceCache;
|
5
|
+
|
6
|
+
static void deallocate(void * ctx);
|
7
|
+
static VALUE allocate(VALUE klass);
|
8
|
+
static size_t memsize(const void *p);
|
9
|
+
static VALUE duckdb_instance_cache_initialize(VALUE self);
|
10
|
+
static VALUE duckdb_instance_cache_get_or_create(int argc, VALUE *argv, VALUE self);
|
11
|
+
static VALUE duckdb_instance_cache_destroy(VALUE self);
|
12
|
+
|
13
|
+
static const rb_data_type_t instance_cache_data_type = {
|
14
|
+
"DuckDB/InstanceCache",
|
15
|
+
{NULL, deallocate, memsize,},
|
16
|
+
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
17
|
+
};
|
18
|
+
|
19
|
+
static void deallocate(void * ctx) {
|
20
|
+
rubyDuckDBInstanceCache *p = (rubyDuckDBInstanceCache *)ctx;
|
21
|
+
|
22
|
+
if (p->instance_cache) {
|
23
|
+
duckdb_destroy_instance_cache(&(p->instance_cache));
|
24
|
+
}
|
25
|
+
xfree(p);
|
26
|
+
}
|
27
|
+
|
28
|
+
static size_t memsize(const void *p) {
|
29
|
+
return sizeof(rubyDuckDBInstanceCache);
|
30
|
+
}
|
31
|
+
|
32
|
+
static VALUE allocate(VALUE klass) {
|
33
|
+
rubyDuckDBInstanceCache *ctx = xcalloc((size_t)1, sizeof(rubyDuckDBInstanceCache));
|
34
|
+
return TypedData_Wrap_Struct(klass, &instance_cache_data_type, ctx);
|
35
|
+
}
|
36
|
+
|
37
|
+
static VALUE duckdb_instance_cache_initialize(VALUE self) {
|
38
|
+
rubyDuckDBInstanceCache *ctx;
|
39
|
+
|
40
|
+
TypedData_Get_Struct(self, rubyDuckDBInstanceCache, &instance_cache_data_type, ctx);
|
41
|
+
|
42
|
+
ctx->instance_cache = duckdb_create_instance_cache();
|
43
|
+
if (ctx->instance_cache == NULL) {
|
44
|
+
rb_raise(eDuckDBError, "Failed to create instance cache");
|
45
|
+
}
|
46
|
+
|
47
|
+
return self;
|
48
|
+
}
|
49
|
+
|
50
|
+
/* :nodoc: */
|
51
|
+
static VALUE duckdb_instance_cache_get_or_create(int argc, VALUE *argv, VALUE self) {
|
52
|
+
VALUE vpath = Qnil;
|
53
|
+
VALUE vconfig = Qnil;
|
54
|
+
const char *path = NULL;
|
55
|
+
char *error = NULL;
|
56
|
+
duckdb_config config = NULL;
|
57
|
+
duckdb_database db;
|
58
|
+
rubyDuckDBInstanceCache *ctx;
|
59
|
+
|
60
|
+
rb_scan_args(argc, argv, "02", &vpath, &vconfig);
|
61
|
+
if (!NIL_P(vpath)) {
|
62
|
+
path = StringValuePtr(vpath);
|
63
|
+
}
|
64
|
+
if (!NIL_P(vconfig)) {
|
65
|
+
if (!rb_obj_is_kind_of(vconfig, cDuckDBConfig)) {
|
66
|
+
rb_raise(rb_eTypeError, "The second argument must be DuckDB::Config object.");
|
67
|
+
}
|
68
|
+
rubyDuckDBConfig *ctx_config = get_struct_config(vconfig);
|
69
|
+
config = ctx_config->config;
|
70
|
+
}
|
71
|
+
|
72
|
+
TypedData_Get_Struct(self, rubyDuckDBInstanceCache, &instance_cache_data_type, ctx);
|
73
|
+
|
74
|
+
if (duckdb_get_or_create_from_cache(ctx->instance_cache, path, &db, config, &error) == DuckDBError) {
|
75
|
+
if (error) {
|
76
|
+
VALUE message = rb_str_new_cstr(error);
|
77
|
+
duckdb_free(error);
|
78
|
+
rb_raise(eDuckDBError, "%s", StringValuePtr(message));
|
79
|
+
} else {
|
80
|
+
rb_raise(eDuckDBError, "Failed to get or create database from instance cache");
|
81
|
+
}
|
82
|
+
}
|
83
|
+
return rbduckdb_create_database_obj(db);
|
84
|
+
}
|
85
|
+
|
86
|
+
static VALUE duckdb_instance_cache_destroy(VALUE self) {
|
87
|
+
rubyDuckDBInstanceCache *ctx;
|
88
|
+
TypedData_Get_Struct(self, rubyDuckDBInstanceCache, &instance_cache_data_type, ctx);
|
89
|
+
|
90
|
+
if (ctx->instance_cache) {
|
91
|
+
duckdb_destroy_instance_cache(&(ctx->instance_cache));
|
92
|
+
ctx->instance_cache = NULL;
|
93
|
+
}
|
94
|
+
|
95
|
+
return Qnil;
|
96
|
+
}
|
97
|
+
|
98
|
+
void rbduckdb_init_duckdb_instance_cache(void) {
|
99
|
+
#if 0
|
100
|
+
VALUE mDuckDB = rb_define_module("DuckDB");
|
101
|
+
#endif
|
102
|
+
cDuckDBInstanceCache = rb_define_class_under(mDuckDB, "InstanceCache", rb_cObject);
|
103
|
+
rb_define_method(cDuckDBInstanceCache, "initialize", duckdb_instance_cache_initialize, 0);
|
104
|
+
rb_define_method(cDuckDBInstanceCache, "get_or_create", duckdb_instance_cache_get_or_create, -1);
|
105
|
+
rb_define_method(cDuckDBInstanceCache, "destroy", duckdb_instance_cache_destroy, 0);
|
106
|
+
rb_define_alloc_func(cDuckDBInstanceCache, allocate);
|
107
|
+
}
|
108
|
+
#endif
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#ifndef RUBY_DUCKDB_INSTANCE_CACHE_H
|
2
|
+
#define RUBY_DUCKDB_INSTANCE_CACHE_H
|
3
|
+
|
4
|
+
#ifdef HAVE_DUCKDB_H_GE_V1_2_0
|
5
|
+
|
6
|
+
struct _rubyDuckDBInstanceCache {
|
7
|
+
duckdb_instance_cache instance_cache;
|
8
|
+
};
|
9
|
+
|
10
|
+
typedef struct _rubyDuckDBInstanceCache rubyDuckDBInstanceCache;
|
11
|
+
|
12
|
+
void rbduckdb_init_duckdb_instance_cache(void);
|
13
|
+
|
14
|
+
#endif
|
15
|
+
|
16
|
+
#endif
|
17
|
+
|
data/ext/duckdb/logical_type.c
CHANGED
@@ -18,6 +18,11 @@ static VALUE duckdb_logical_type_value_type(VALUE self);
|
|
18
18
|
static VALUE duckdb_logical_type_member_count(VALUE self);
|
19
19
|
static VALUE duckdb_logical_type_member_name_at(VALUE self, VALUE midx);
|
20
20
|
static VALUE duckdb_logical_type_member_type_at(VALUE self, VALUE midx);
|
21
|
+
static VALUE duckdb_logical_type__internal_type(VALUE self);
|
22
|
+
static VALUE duckdb_logical_type_dictionary_size(VALUE self);
|
23
|
+
static VALUE duckdb_logical_type_dictionary_value_at(VALUE self, VALUE didx);
|
24
|
+
static VALUE duckdb_logical_type__get_alias(VALUE self);
|
25
|
+
static VALUE duckdb_logical_type__set_alias(VALUE self, VALUE aname);
|
21
26
|
|
22
27
|
static const rb_data_type_t logical_type_data_type = {
|
23
28
|
"DuckDB/LogicalType",
|
@@ -288,6 +293,115 @@ static VALUE duckdb_logical_type_member_type_at(VALUE self, VALUE midx) {
|
|
288
293
|
return rbduckdb_create_logical_type(union_member_type);
|
289
294
|
}
|
290
295
|
|
296
|
+
/*
|
297
|
+
* call-seq:
|
298
|
+
* enum_col.logical_type.internal_type -> Symbol
|
299
|
+
*
|
300
|
+
* Returns the logical type's internal type.
|
301
|
+
*
|
302
|
+
*/
|
303
|
+
static VALUE duckdb_logical_type__internal_type(VALUE self) {
|
304
|
+
rubyDuckDBLogicalType *ctx;
|
305
|
+
duckdb_type type_id;
|
306
|
+
duckdb_type internal_type_id;
|
307
|
+
|
308
|
+
TypedData_Get_Struct(self, rubyDuckDBLogicalType, &logical_type_data_type, ctx);
|
309
|
+
|
310
|
+
type_id = duckdb_get_type_id(ctx->logical_type);
|
311
|
+
switch (type_id) {
|
312
|
+
case DUCKDB_TYPE_DECIMAL:
|
313
|
+
internal_type_id = duckdb_decimal_internal_type(ctx->logical_type);
|
314
|
+
break;
|
315
|
+
case DUCKDB_TYPE_ENUM:
|
316
|
+
internal_type_id = duckdb_enum_internal_type(ctx->logical_type);
|
317
|
+
break;
|
318
|
+
default:
|
319
|
+
internal_type_id = DUCKDB_TYPE_INVALID;
|
320
|
+
}
|
321
|
+
|
322
|
+
return INT2FIX(internal_type_id);
|
323
|
+
}
|
324
|
+
|
325
|
+
/*
|
326
|
+
* call-seq:
|
327
|
+
* enum_col.logical_type.dictionary_size -> Integer
|
328
|
+
*
|
329
|
+
* Returns the dictionary size of the enum type.
|
330
|
+
*
|
331
|
+
*/
|
332
|
+
static VALUE duckdb_logical_type_dictionary_size(VALUE self) {
|
333
|
+
rubyDuckDBLogicalType *ctx;
|
334
|
+
TypedData_Get_Struct(self, rubyDuckDBLogicalType, &logical_type_data_type, ctx);
|
335
|
+
return INT2FIX(duckdb_enum_dictionary_size(ctx->logical_type));
|
336
|
+
}
|
337
|
+
|
338
|
+
/*
|
339
|
+
* call-seq:
|
340
|
+
* enum_col.logical_type.dictionary_value_at(index) -> String
|
341
|
+
*
|
342
|
+
* Returns the dictionary value at the specified index.
|
343
|
+
*
|
344
|
+
*/
|
345
|
+
static VALUE duckdb_logical_type_dictionary_value_at(VALUE self, VALUE didx) {
|
346
|
+
rubyDuckDBLogicalType *ctx;
|
347
|
+
VALUE dvalue;
|
348
|
+
const char *dict_value;
|
349
|
+
idx_t idx = NUM2ULL(didx);
|
350
|
+
|
351
|
+
TypedData_Get_Struct(self, rubyDuckDBLogicalType, &logical_type_data_type, ctx);
|
352
|
+
|
353
|
+
dict_value = duckdb_enum_dictionary_value(ctx->logical_type, idx);
|
354
|
+
if (dict_value == NULL) {
|
355
|
+
rb_raise(eDuckDBError, "fail to get dictionary value of %llu", (unsigned long long)idx);
|
356
|
+
}
|
357
|
+
dvalue = rb_utf8_str_new_cstr(dict_value);
|
358
|
+
duckdb_free((void *)dict_value);
|
359
|
+
return dvalue;
|
360
|
+
}
|
361
|
+
|
362
|
+
/*
|
363
|
+
* call-seq:
|
364
|
+
* col.logical_type.alias -> String
|
365
|
+
*
|
366
|
+
* Returns the alias of the logical type.
|
367
|
+
*
|
368
|
+
*/
|
369
|
+
static VALUE duckdb_logical_type__get_alias(VALUE self) {
|
370
|
+
rubyDuckDBLogicalType *ctx;
|
371
|
+
VALUE alias = Qnil;
|
372
|
+
const char *_alias;
|
373
|
+
|
374
|
+
TypedData_Get_Struct(self, rubyDuckDBLogicalType, &logical_type_data_type, ctx);
|
375
|
+
|
376
|
+
_alias = duckdb_logical_type_get_alias(ctx->logical_type);
|
377
|
+
if (_alias != NULL) {
|
378
|
+
alias = rb_utf8_str_new_cstr(_alias);
|
379
|
+
}
|
380
|
+
duckdb_free((void *)_alias);
|
381
|
+
return alias;
|
382
|
+
}
|
383
|
+
|
384
|
+
/*
|
385
|
+
* call-seq:
|
386
|
+
* col.logical_type.alias(alias) -> String
|
387
|
+
*
|
388
|
+
* Return the set alias of the logical type.
|
389
|
+
*
|
390
|
+
*/
|
391
|
+
static VALUE duckdb_logical_type__set_alias(VALUE self, VALUE aname) {
|
392
|
+
rubyDuckDBLogicalType *ctx;
|
393
|
+
VALUE alias = Qnil;
|
394
|
+
const char *_alias = StringValuePtr(aname);
|
395
|
+
|
396
|
+
TypedData_Get_Struct(self, rubyDuckDBLogicalType, &logical_type_data_type, ctx);
|
397
|
+
duckdb_logical_type_set_alias(ctx->logical_type, _alias);
|
398
|
+
if (_alias != NULL) {
|
399
|
+
alias = rb_utf8_str_new_cstr(_alias);
|
400
|
+
}
|
401
|
+
|
402
|
+
return alias;
|
403
|
+
}
|
404
|
+
|
291
405
|
VALUE rbduckdb_create_logical_type(duckdb_logical_type logical_type) {
|
292
406
|
VALUE obj;
|
293
407
|
rubyDuckDBLogicalType *ctx;
|
@@ -320,4 +434,9 @@ void rbduckdb_init_duckdb_logical_type(void) {
|
|
320
434
|
rb_define_method(cDuckDBLogicalType, "member_count", duckdb_logical_type_member_count, 0);
|
321
435
|
rb_define_method(cDuckDBLogicalType, "member_name_at", duckdb_logical_type_member_name_at, 1);
|
322
436
|
rb_define_method(cDuckDBLogicalType, "member_type_at", duckdb_logical_type_member_type_at, 1);
|
437
|
+
rb_define_method(cDuckDBLogicalType, "_internal_type", duckdb_logical_type__internal_type, 0);
|
438
|
+
rb_define_method(cDuckDBLogicalType, "dictionary_size", duckdb_logical_type_dictionary_size, 0);
|
439
|
+
rb_define_method(cDuckDBLogicalType, "dictionary_value_at", duckdb_logical_type_dictionary_value_at, 1);
|
440
|
+
rb_define_method(cDuckDBLogicalType, "get_alias", duckdb_logical_type__get_alias, 0);
|
441
|
+
rb_define_method(cDuckDBLogicalType, "set_alias", duckdb_logical_type__set_alias, 1);
|
323
442
|
}
|
@@ -27,6 +27,10 @@ static VALUE duckdb_prepared_statement_bind_blob(VALUE self, VALUE vidx, VALUE b
|
|
27
27
|
static VALUE duckdb_prepared_statement_bind_null(VALUE self, VALUE vidx);
|
28
28
|
static VALUE duckdb_prepared_statement__statement_type(VALUE self);
|
29
29
|
static VALUE duckdb_prepared_statement__param_type(VALUE self, VALUE vidx);
|
30
|
+
static VALUE duckdb_prepared_statement__bind_uint8(VALUE self, VALUE vidx, VALUE val);
|
31
|
+
static VALUE duckdb_prepared_statement__bind_uint16(VALUE self, VALUE vidx, VALUE val);
|
32
|
+
static VALUE duckdb_prepared_statement__bind_uint32(VALUE self, VALUE vidx, VALUE val);
|
33
|
+
static VALUE duckdb_prepared_statement__bind_uint64(VALUE self, VALUE vidx, VALUE val);
|
30
34
|
static VALUE duckdb_prepared_statement__bind_date(VALUE self, VALUE vidx, VALUE year, VALUE month, VALUE day);
|
31
35
|
static VALUE duckdb_prepared_statement__bind_time(VALUE self, VALUE vidx, VALUE hour, VALUE min, VALUE sec, VALUE micros);
|
32
36
|
static VALUE duckdb_prepared_statement__bind_timestamp(VALUE self, VALUE vidx, VALUE year, VALUE month, VALUE day, VALUE hour, VALUE min, VALUE sec, VALUE micros);
|
@@ -244,6 +248,7 @@ static VALUE duckdb_prepared_statement_bind_int8(VALUE self, VALUE vidx, VALUE v
|
|
244
248
|
return self;
|
245
249
|
}
|
246
250
|
|
251
|
+
|
247
252
|
static VALUE duckdb_prepared_statement_bind_int16(VALUE self, VALUE vidx, VALUE val) {
|
248
253
|
rubyDuckDBPreparedStatement *ctx;
|
249
254
|
idx_t idx = check_index(vidx);
|
@@ -359,6 +364,62 @@ static VALUE duckdb_prepared_statement__param_type(VALUE self, VALUE vidx) {
|
|
359
364
|
return INT2FIX(duckdb_param_type(ctx->prepared_statement, NUM2ULL(vidx)));
|
360
365
|
}
|
361
366
|
|
367
|
+
/* :nodoc: */
|
368
|
+
static VALUE duckdb_prepared_statement__bind_uint8(VALUE self, VALUE vidx, VALUE val) {
|
369
|
+
rubyDuckDBPreparedStatement *ctx;
|
370
|
+
idx_t idx = check_index(vidx);
|
371
|
+
uint8_t ui8val = (uint8_t)NUM2UINT(val);
|
372
|
+
|
373
|
+
TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
|
374
|
+
|
375
|
+
if (duckdb_bind_uint8(ctx->prepared_statement, idx, ui8val) == DuckDBError) {
|
376
|
+
rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
|
377
|
+
}
|
378
|
+
return self;
|
379
|
+
}
|
380
|
+
|
381
|
+
/* :nodoc: */
|
382
|
+
static VALUE duckdb_prepared_statement__bind_uint16(VALUE self, VALUE vidx, VALUE val) {
|
383
|
+
rubyDuckDBPreparedStatement *ctx;
|
384
|
+
idx_t idx = check_index(vidx);
|
385
|
+
uint16_t ui16val = (uint16_t)NUM2UINT(val);
|
386
|
+
|
387
|
+
TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
|
388
|
+
|
389
|
+
if (duckdb_bind_uint16(ctx->prepared_statement, idx, ui16val) == DuckDBError) {
|
390
|
+
rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
|
391
|
+
}
|
392
|
+
return self;
|
393
|
+
}
|
394
|
+
|
395
|
+
/* :nodoc: */
|
396
|
+
static VALUE duckdb_prepared_statement__bind_uint32(VALUE self, VALUE vidx, VALUE val) {
|
397
|
+
rubyDuckDBPreparedStatement *ctx;
|
398
|
+
idx_t idx = check_index(vidx);
|
399
|
+
uint32_t ui32val = (uint32_t)NUM2UINT(val);
|
400
|
+
|
401
|
+
TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
|
402
|
+
|
403
|
+
if (duckdb_bind_uint32(ctx->prepared_statement, idx, ui32val) == DuckDBError) {
|
404
|
+
rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
|
405
|
+
}
|
406
|
+
return self;
|
407
|
+
}
|
408
|
+
|
409
|
+
/* :nodoc: */
|
410
|
+
static VALUE duckdb_prepared_statement__bind_uint64(VALUE self, VALUE vidx, VALUE val) {
|
411
|
+
rubyDuckDBPreparedStatement *ctx;
|
412
|
+
idx_t idx = check_index(vidx);
|
413
|
+
uint64_t ui64val = (uint64_t)NUM2ULL(val);
|
414
|
+
|
415
|
+
TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
|
416
|
+
|
417
|
+
if (duckdb_bind_uint64(ctx->prepared_statement, idx, ui64val) == DuckDBError) {
|
418
|
+
rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
|
419
|
+
}
|
420
|
+
return self;
|
421
|
+
}
|
422
|
+
|
362
423
|
/* :nodoc: */
|
363
424
|
static VALUE duckdb_prepared_statement__bind_date(VALUE self, VALUE vidx, VALUE year, VALUE month, VALUE day) {
|
364
425
|
rubyDuckDBPreparedStatement *ctx;
|
@@ -511,6 +572,10 @@ void rbduckdb_init_duckdb_prepared_statement(void) {
|
|
511
572
|
rb_define_method(cDuckDBPreparedStatement, "bind_varchar", duckdb_prepared_statement_bind_varchar, 2);
|
512
573
|
rb_define_method(cDuckDBPreparedStatement, "bind_blob", duckdb_prepared_statement_bind_blob, 2);
|
513
574
|
rb_define_method(cDuckDBPreparedStatement, "bind_null", duckdb_prepared_statement_bind_null, 1);
|
575
|
+
rb_define_private_method(cDuckDBPreparedStatement, "_bind_uint8", duckdb_prepared_statement__bind_uint8, 2);
|
576
|
+
rb_define_private_method(cDuckDBPreparedStatement, "_bind_uint16", duckdb_prepared_statement__bind_uint16, 2);
|
577
|
+
rb_define_private_method(cDuckDBPreparedStatement, "_bind_uint32", duckdb_prepared_statement__bind_uint32, 2);
|
578
|
+
rb_define_private_method(cDuckDBPreparedStatement, "_bind_uint64", duckdb_prepared_statement__bind_uint64, 2);
|
514
579
|
rb_define_private_method(cDuckDBPreparedStatement, "_statement_type", duckdb_prepared_statement__statement_type, 0);
|
515
580
|
rb_define_private_method(cDuckDBPreparedStatement, "_param_type", duckdb_prepared_statement__param_type, 1);
|
516
581
|
rb_define_private_method(cDuckDBPreparedStatement, "_bind_date", duckdb_prepared_statement__bind_date, 4);
|
data/ext/duckdb/ruby-duckdb.h
CHANGED
@@ -32,6 +32,10 @@
|
|
32
32
|
#include "./appender.h"
|
33
33
|
#include "./config.h"
|
34
34
|
|
35
|
+
#ifdef HAVE_DUCKDB_H_GE_V1_2_0
|
36
|
+
#include "./instance_cache.h"
|
37
|
+
#endif
|
38
|
+
|
35
39
|
extern VALUE mDuckDB;
|
36
40
|
extern VALUE cDuckDBDatabase;
|
37
41
|
extern VALUE cDuckDBConnection;
|
@@ -43,4 +47,8 @@ extern VALUE cDuckDBPreparedStatement;
|
|
43
47
|
extern VALUE PositiveInfinity;
|
44
48
|
extern VALUE NegativeInfinity;
|
45
49
|
|
50
|
+
#ifdef HAVE_DUCKDB_H_GE_V1_2_0
|
51
|
+
extern VALUE cDuckDBInstanceCache;
|
52
|
+
#endif
|
53
|
+
|
46
54
|
#endif
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
if defined?(DuckDB::InstanceCache)
|
4
|
+
|
5
|
+
module DuckDB
|
6
|
+
# The DuckDB::InstanceCache is necessary if a client/program (re)opens
|
7
|
+
# multiple databases to the same file within the same statement.
|
8
|
+
#
|
9
|
+
# require 'duckdb'
|
10
|
+
# cache = DuckDB::InstanceCache.new
|
11
|
+
# db1 = cache.get(path: 'db.duckdb')
|
12
|
+
# db2 = cache.get(path: 'db.duckdb')
|
13
|
+
class InstanceCache
|
14
|
+
# :call-seq:
|
15
|
+
# instance_cache.get(path:, config:) -> self
|
16
|
+
#
|
17
|
+
# Returns a DuckDB::Database object for the given path and config.
|
18
|
+
# db1 = cache.get(path: 'db.duckdb')
|
19
|
+
# db2 = cache.get(path: 'db.duckdb')
|
20
|
+
def get(path: nil, config: nil)
|
21
|
+
get_or_create(path, config)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
data/lib/duckdb/logical_type.rb
CHANGED
@@ -2,6 +2,9 @@
|
|
2
2
|
|
3
3
|
module DuckDB
|
4
4
|
class LogicalType
|
5
|
+
alias :alias get_alias
|
6
|
+
alias :alias= set_alias
|
7
|
+
|
5
8
|
# returns logical type's type symbol
|
6
9
|
# `:unknown` means that the logical type's type is unknown/unsupported by ruby-duckdb.
|
7
10
|
# `:invalid` means that the logical type's type is invalid in duckdb.
|
@@ -19,6 +22,24 @@ module DuckDB
|
|
19
22
|
DuckDB::Converter::IntToSym.type_to_sym(type_id)
|
20
23
|
end
|
21
24
|
|
25
|
+
# returns logical type's internal type symbol for Decimal or Enum types
|
26
|
+
# `:unknown` means that the logical type's type is unknown/unsupported by ruby-duckdb.
|
27
|
+
# `:invalid` means that the logical type's type is invalid in duckdb.
|
28
|
+
#
|
29
|
+
# require 'duckdb'
|
30
|
+
# db = DuckDB::Database.open
|
31
|
+
# con = db.connect
|
32
|
+
# con.query("CREATE TYPE mood AS ENUM ('happy', 'sad')")
|
33
|
+
# con.query("CREATE TABLE emotions (id INTEGER, enum_col mood)")
|
34
|
+
#
|
35
|
+
# users = con.query('SELECT * FROM emotions')
|
36
|
+
# ernum_col = users.columns.find { |col| col.name == 'enum_col' }
|
37
|
+
# enum_col.logical_type.internal_type #=> :utinyint
|
38
|
+
def internal_type
|
39
|
+
type_id = _internal_type
|
40
|
+
DuckDB::Converter::IntToSym.type_to_sym(type_id)
|
41
|
+
end
|
42
|
+
|
22
43
|
# Iterates over each union member name.
|
23
44
|
#
|
24
45
|
# When a block is provided, this method yields each union member name in
|
@@ -106,5 +127,27 @@ module DuckDB
|
|
106
127
|
yield child_type_at(i)
|
107
128
|
end
|
108
129
|
end
|
130
|
+
|
131
|
+
# Iterates over each enum dictionary value.
|
132
|
+
#
|
133
|
+
# When a block is provided, this method yields each enum dictionary value
|
134
|
+
# in order. It also returns the total number of dictionary values yielded.
|
135
|
+
#
|
136
|
+
# enum_logical_type.each_value do |value|
|
137
|
+
# puts "Enum value: #{value}"
|
138
|
+
# end
|
139
|
+
#
|
140
|
+
# If no block is given, an Enumerator is returned, which can be used to
|
141
|
+
# retrieve all enum dictionary values.
|
142
|
+
#
|
143
|
+
# values = enum_logical_type.each_value.to_a
|
144
|
+
# # => ["happy", "sad"]
|
145
|
+
def each_dictionary_value
|
146
|
+
return to_enum(__method__) {dictionary_size} unless block_given?
|
147
|
+
|
148
|
+
dictionary_size.times do |i|
|
149
|
+
yield dictionary_value_at(i)
|
150
|
+
end
|
151
|
+
end
|
109
152
|
end
|
110
153
|
end
|
@@ -105,6 +105,46 @@ module DuckDB
|
|
105
105
|
end
|
106
106
|
end
|
107
107
|
|
108
|
+
# binds i-th parameter with SQL prepared statement.
|
109
|
+
# The first argument is index of parameter.
|
110
|
+
# The index of first parameter is 1 not 0.
|
111
|
+
# The second argument value is to expected Integer value between 0 to 255.
|
112
|
+
def bind_uint8(index, val)
|
113
|
+
return _bind_uint8(index, val) if val.between?(0, 255)
|
114
|
+
|
115
|
+
raise DuckDB::Error, "can't bind uint8(bind_uint8) to `#{val}`. The `#{val}` is out of range 0..255."
|
116
|
+
end
|
117
|
+
|
118
|
+
# binds i-th parameter with SQL prepared statement.
|
119
|
+
# The first argument is index of parameter.
|
120
|
+
# The index of first parameter is 1 not 0.
|
121
|
+
# The second argument value is to expected Integer value between 0 to 65535.
|
122
|
+
def bind_uint16(index, val)
|
123
|
+
return _bind_uint16(index, val) if val.between?(0, 65_535)
|
124
|
+
|
125
|
+
raise DuckDB::Error, "can't bind uint16(bind_uint16) to `#{val}`. The `#{val}` is out of range 0..65535."
|
126
|
+
end
|
127
|
+
|
128
|
+
# binds i-th parameter with SQL prepared statement.
|
129
|
+
# The first argument is index of parameter.
|
130
|
+
# The index of first parameter is 1 not 0.
|
131
|
+
# The second argument value is to expected Integer value between 0 to 4294967295.
|
132
|
+
def bind_uint32(index, val)
|
133
|
+
return _bind_uint32(index, val) if val.between?(0, 4_294_967_295)
|
134
|
+
|
135
|
+
raise DuckDB::Error, "can't bind uint32(bind_uint32) to `#{val}`. The `#{val}` is out of range 0..4294967295."
|
136
|
+
end
|
137
|
+
|
138
|
+
# binds i-th parameter with SQL prepared statement.
|
139
|
+
# The first argument is index of parameter.
|
140
|
+
# The index of first parameter is 1 not 0.
|
141
|
+
# The second argument value is to expected Integer value between 0 to 18446744073709551615.
|
142
|
+
def bind_uint64(index, val)
|
143
|
+
return _bind_uint64(index, val) if val.between?(0, 18_446_744_073_709_551_615)
|
144
|
+
|
145
|
+
raise DuckDB::Error, "can't bind uint64(bind_uint64) to `#{val}`. The `#{val}` is out of range 0..18446744073709551615."
|
146
|
+
end
|
147
|
+
|
108
148
|
# binds i-th parameter with SQL prepared statement.
|
109
149
|
# The first argument is index of parameter.
|
110
150
|
# The index of first parameter is 1 not 0.
|
data/lib/duckdb/version.rb
CHANGED
data/lib/duckdb.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: duckdb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Masaki Suketa
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: bigdecimal
|
@@ -132,6 +132,8 @@ files:
|
|
132
132
|
- ext/duckdb/extconf.rb
|
133
133
|
- ext/duckdb/extracted_statements.c
|
134
134
|
- ext/duckdb/extracted_statements.h
|
135
|
+
- ext/duckdb/instance_cache.c
|
136
|
+
- ext/duckdb/instance_cache.h
|
135
137
|
- ext/duckdb/logical_type.c
|
136
138
|
- ext/duckdb/logical_type.h
|
137
139
|
- ext/duckdb/pending_result.c
|
@@ -154,6 +156,7 @@ files:
|
|
154
156
|
- lib/duckdb/database.rb
|
155
157
|
- lib/duckdb/extracted_statements.rb
|
156
158
|
- lib/duckdb/infinity.rb
|
159
|
+
- lib/duckdb/instance_cache.rb
|
157
160
|
- lib/duckdb/interval.rb
|
158
161
|
- lib/duckdb/library_version.rb
|
159
162
|
- lib/duckdb/logical_type.rb
|
@@ -185,7 +188,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
185
188
|
- !ruby/object:Gem::Version
|
186
189
|
version: '0'
|
187
190
|
requirements: []
|
188
|
-
rubygems_version: 3.6.
|
191
|
+
rubygems_version: 3.6.7
|
189
192
|
specification_version: 4
|
190
193
|
summary: This module is Ruby binding for DuckDB database engine.
|
191
194
|
test_files: []
|