duckdb 1.3.0.0 → 1.4.1.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 +2 -3
- data/CHANGELOG.md +33 -0
- data/Dockerfile +1 -1
- data/Gemfile.lock +10 -10
- data/duckdb.gemspec +1 -1
- data/ext/duckdb/appender.c +88 -4
- data/ext/duckdb/database.c +55 -7
- data/ext/duckdb/duckdb.c +2 -2
- data/ext/duckdb/extconf.rb +4 -8
- data/ext/duckdb/instance_cache.c +0 -2
- data/ext/duckdb/instance_cache.h +0 -5
- data/ext/duckdb/logical_type.c +34 -0
- data/ext/duckdb/logical_type.h +1 -1
- data/ext/duckdb/result.c +50 -14
- data/ext/duckdb/ruby-duckdb.h +8 -14
- data/ext/duckdb/scalar_function.c +57 -0
- data/ext/duckdb/scalar_function.h +14 -0
- data/ext/duckdb/value_impl.c +38 -0
- data/ext/duckdb/value_impl.h +13 -0
- data/getduckdb.sh +11 -3
- data/lib/duckdb/appender.rb +4 -0
- data/lib/duckdb/connection.rb +22 -0
- data/lib/duckdb/converter/int_to_sym.rb +5 -1
- data/lib/duckdb/logical_type.rb +49 -0
- data/lib/duckdb/version.rb +1 -1
- metadata +7 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 172cad0f5262bd839bcae9bd60455db2ae92c3d2777856a807448749b4982d63
|
|
4
|
+
data.tar.gz: 7af629371eb57967458add2ad62d88bf22f4c01eb3fc8e07ec67456c9d0edcb0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 92aa3a8b950008ff7327a27f98a76ba8e519d5f7ea1e3120b4d5310dd27bc15a7b330b5893d2a766da3533acf95a1e3b65614e28e9564a22286d8b493988fa9f
|
|
7
|
+
data.tar.gz: 53660ec068a0a15f6065d67c15323612d13b5e91fc578a81554a8e8728c92888096cf817d2649fc15d4af6bb1045ed9f4bdf2232cb67fd8701a4578c37c34e0a
|
|
@@ -15,8 +15,8 @@ jobs:
|
|
|
15
15
|
runs-on: macos-latest
|
|
16
16
|
strategy:
|
|
17
17
|
matrix:
|
|
18
|
-
ruby: ['3.2.
|
|
19
|
-
duckdb: ['1.
|
|
18
|
+
ruby: ['3.2.9', '3.3.10', '3.4.7', 'head', '3.5.0-preview1']
|
|
19
|
+
duckdb: ['1.4.1', '1.3.2']
|
|
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.2.
|
|
19
|
-
duckdb: ['1.
|
|
18
|
+
ruby: ['3.2.9', '3.3.10', '3.4.7', 'head', '3.5.0-preview1']
|
|
19
|
+
duckdb: ['1.4.1', '1.3.2']
|
|
20
20
|
|
|
21
21
|
steps:
|
|
22
22
|
- uses: actions/checkout@v4
|
|
@@ -15,9 +15,8 @@ jobs:
|
|
|
15
15
|
runs-on: windows-latest
|
|
16
16
|
strategy:
|
|
17
17
|
matrix:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
duckdb: ['1.2.2', '1.1.3', '1.1.1', '1.3.0']
|
|
18
|
+
ruby: ['3.2.9', '3.3.10', '3.4.7', 'ucrt', 'mingw', 'mswin', 'head']
|
|
19
|
+
duckdb: ['1.4.1', '1.3.2']
|
|
21
20
|
|
|
22
21
|
steps:
|
|
23
22
|
- uses: actions/checkout@v4
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,39 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
# Unreleased
|
|
6
6
|
|
|
7
|
+
# 1.4.1.0 - 2025-11-01
|
|
8
|
+
- add DuckDB::Connection#appender_from_query.
|
|
9
|
+
- add DuckDB::Appender.create_query.
|
|
10
|
+
- add `DuckDB::LogicalType.boolean`, `DuckDB::LogicalType.tinyint`, `DuckDB::LogicalType.smallint`,
|
|
11
|
+
`DuckDB::LogicalType.integer`, `DuckDB::LogicalType.bigint`, `DuckDB::LogicalType.utinyint`,
|
|
12
|
+
`DuckDB::LogicalType.usmallint`, `DuckDB::LogicalType.uinteger`, `DuckDB::LogicalType.ubigint`,
|
|
13
|
+
`DuckDB::LogicalType.float`, `DuckDB::LogicalType.double`, `DuckDB::LogicalType.timestamp`,
|
|
14
|
+
`DuckDB::LogicalType.date`, `DuckDB::LogicalType.time`, `DuckDB::LogicalType.interval`,
|
|
15
|
+
`DuckDB::LogicalType.hugeint`, `DuckDB::LogicalType.uhugeint`, `DuckDB::LogicalType.varchar`,
|
|
16
|
+
`DuckDB::LogicalType.blob`, `DuckDB::LogicalType.timestamp_s`,
|
|
17
|
+
`DuckDB::LogicalType.timestamp_ms`, `DuckDB::LogicalType.timestamp_ns`,
|
|
18
|
+
`DuckDB::LogicalType.bit`, `DuckDB::LogicalType.time_tz`, `DuckDB::LogicalType.timestamp_tz`.
|
|
19
|
+
- add `DuckDB::LogicalType::BOOLEAN`, `DuckDB::LogicalType::TINYINT`, `DuckDB::LogicalType::SMALLINT`,
|
|
20
|
+
`DuckDB::LogicalType::INTEGER`, `DuckDB::LogicalType::BIGINT`, `DuckDB::LogicalType::UTINYINT`,
|
|
21
|
+
`DuckDB::LogicalType::USMALLINT`, `DuckDB::LogicalType::UINTEGER`, `DuckDB::LogicalType::UBIGINT`,
|
|
22
|
+
`DuckDB::LogicalType::FLOAT`, `DuckDB::LogicalType::DOUBLE`, `DuckDB::LogicalType::TIMESTAMP`,
|
|
23
|
+
`DuckDB::LogicalType::DATE`, `DuckDB::LogicalType::TIME`, `DuckDB::LogicalType::INTERVAL`,
|
|
24
|
+
`DuckDB::LogicalType::HUGEINT`, `DuckDB::LogicalType::UHUGEINT`, `DuckDB::LogicalType::VARCHAR`,
|
|
25
|
+
`DuckDB::LogicalType::BLOB`, `DuckDB::LogicalType::TIMESTAMP_S`,
|
|
26
|
+
`DuckDB::LogicalType::TIMESTAMP_MS`, `DuckDB::LogicalType::TIMESTAMP_NS`,
|
|
27
|
+
`DuckDB::LogicalType::BIT`, `DuckDB::LogicalType::TIME_TZ`, `DuckDB::LogicalType::TIMESTAMP_TZ`.
|
|
28
|
+
- Support TIMESTAMP_NS infinity, -infinity value.
|
|
29
|
+
- bump duckdb to 1.3.2, 1.4.1 on CI.
|
|
30
|
+
- add `DuckDB::ValueImpl` class. This class is under construction. You must not use this class directly.
|
|
31
|
+
- add `DuckDB::ScalarFunction` class. This class is under construction.
|
|
32
|
+
- add `DuckDB::ScalarFunction#set_name`.
|
|
33
|
+
- add `DuckDB::LogicalType.new(type_id)` to create a logical type from a type ID.
|
|
34
|
+
|
|
35
|
+
# 1.3.1.0 - 2025-06-28
|
|
36
|
+
- Support TIMESTAMP_S, TIMESTAMP_MS infinity, -infinity value.
|
|
37
|
+
- bump duckdb to 1.3.1 on CI.
|
|
38
|
+
- drop dcukdb v1.1.x.
|
|
39
|
+
|
|
7
40
|
# 1.3.0.0 - 2025-05-31
|
|
8
41
|
- bump duckdb to 1.3.0 on CI.
|
|
9
42
|
|
data/Dockerfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
duckdb (1.
|
|
4
|
+
duckdb (1.4.1.0)
|
|
5
5
|
bigdecimal (>= 3.1.4)
|
|
6
6
|
|
|
7
7
|
GEM
|
|
8
8
|
remote: https://rubygems.org/
|
|
9
9
|
specs:
|
|
10
10
|
benchmark-ips (2.14.0)
|
|
11
|
-
bigdecimal (3.
|
|
11
|
+
bigdecimal (3.3.1)
|
|
12
12
|
mini_portile2 (2.8.9)
|
|
13
|
-
minitest (5.
|
|
14
|
-
nokogiri (1.18.
|
|
13
|
+
minitest (5.26.0)
|
|
14
|
+
nokogiri (1.18.10)
|
|
15
15
|
mini_portile2 (~> 2.8.2)
|
|
16
16
|
racc (~> 1.4)
|
|
17
|
-
nokogiri (1.18.
|
|
17
|
+
nokogiri (1.18.10-aarch64-linux-gnu)
|
|
18
18
|
racc (~> 1.4)
|
|
19
|
-
nokogiri (1.18.
|
|
19
|
+
nokogiri (1.18.10-arm-linux-gnu)
|
|
20
20
|
racc (~> 1.4)
|
|
21
|
-
nokogiri (1.18.
|
|
21
|
+
nokogiri (1.18.10-arm64-darwin)
|
|
22
22
|
racc (~> 1.4)
|
|
23
|
-
nokogiri (1.18.
|
|
23
|
+
nokogiri (1.18.10-x86_64-darwin)
|
|
24
24
|
racc (~> 1.4)
|
|
25
|
-
nokogiri (1.18.
|
|
25
|
+
nokogiri (1.18.10-x86_64-linux-gnu)
|
|
26
26
|
racc (~> 1.4)
|
|
27
27
|
racc (1.8.1)
|
|
28
|
-
rake (13.3.
|
|
28
|
+
rake (13.3.1)
|
|
29
29
|
rake-compiler (1.3.0)
|
|
30
30
|
rake
|
|
31
31
|
ruby_memcheck (3.0.1)
|
data/duckdb.gemspec
CHANGED
|
@@ -27,7 +27,7 @@ Gem::Specification.new do |spec|
|
|
|
27
27
|
end
|
|
28
28
|
spec.require_paths = ['lib']
|
|
29
29
|
spec.extensions = ['ext/duckdb/extconf.rb']
|
|
30
|
-
spec.required_ruby_version = '>= 3.
|
|
30
|
+
spec.required_ruby_version = '>= 3.2.0'
|
|
31
31
|
spec.add_dependency 'bigdecimal', '>= 3.1.4'
|
|
32
32
|
|
|
33
33
|
spec.add_development_dependency 'bundler', '~> 2.3'
|
data/ext/duckdb/appender.c
CHANGED
|
@@ -5,6 +5,11 @@ static VALUE cDuckDBAppender;
|
|
|
5
5
|
static void deallocate(void *);
|
|
6
6
|
static VALUE allocate(VALUE klass);
|
|
7
7
|
static size_t memsize(const void *p);
|
|
8
|
+
|
|
9
|
+
#ifdef HAVE_DUCKDB_H_GE_V1_4_0
|
|
10
|
+
static VALUE appender_s_create_query(VALUE klass, VALUE con, VALUE query, VALUE types, VALUE table, VALUE columns);
|
|
11
|
+
#endif
|
|
12
|
+
|
|
8
13
|
static VALUE appender_initialize(VALUE klass, VALUE con, VALUE schema, VALUE table);
|
|
9
14
|
static VALUE appender_error_message(VALUE self);
|
|
10
15
|
static VALUE appender__append_bool(VALUE self, VALUE val);
|
|
@@ -56,6 +61,69 @@ static size_t memsize(const void *p) {
|
|
|
56
61
|
return sizeof(rubyDuckDBAppender);
|
|
57
62
|
}
|
|
58
63
|
|
|
64
|
+
#ifdef HAVE_DUCKDB_H_GE_V1_4_0
|
|
65
|
+
/* call-seq:
|
|
66
|
+
* DuckDB::Appender.create_query -> DuckDB::Appender
|
|
67
|
+
*
|
|
68
|
+
* Returns a new Appender instance created from a query.
|
|
69
|
+
*
|
|
70
|
+
* require 'duckdb'
|
|
71
|
+
* db = DuckDB::Database.open
|
|
72
|
+
* con = db.connect
|
|
73
|
+
* con.query('CREATE TABLE users (id INTEGER, name VARCHAR)')
|
|
74
|
+
* query = 'INSERT OR REPLACE INTO users SELECT i, val FROM my_appended_data'
|
|
75
|
+
* types = [DuckDB::LogicalType::INTEGER, DuckDB::LogicalType::VARCHAR]
|
|
76
|
+
* appender = DuckDB::Appender.create_query(con, query, types, 'my_appended_data', %w[i val])
|
|
77
|
+
*/
|
|
78
|
+
static VALUE appender_s_create_query(VALUE klass, VALUE con, VALUE query, VALUE types, VALUE table, VALUE columns) {
|
|
79
|
+
rubyDuckDBConnection *ctxcon;
|
|
80
|
+
rubyDuckDBAppender *ctx;
|
|
81
|
+
char *query_str = StringValuePtr(query);
|
|
82
|
+
char *table_name = NULL;
|
|
83
|
+
const char **column_names = NULL;
|
|
84
|
+
idx_t column_count = 0;
|
|
85
|
+
duckdb_logical_type *type_array = NULL;
|
|
86
|
+
VALUE appender = Qnil;
|
|
87
|
+
|
|
88
|
+
if (!rb_obj_is_kind_of(con, cDuckDBConnection)) {
|
|
89
|
+
rb_raise(rb_eTypeError, "1st argument should be instance of DackDB::Connection");
|
|
90
|
+
}
|
|
91
|
+
if (rb_obj_is_kind_of(types, rb_cArray) == Qfalse) {
|
|
92
|
+
rb_raise(rb_eTypeError, "2nd argument should be an Array");
|
|
93
|
+
}
|
|
94
|
+
column_count = RARRAY_LEN(types);
|
|
95
|
+
type_array = ALLOCA_N(duckdb_logical_type, (size_t)column_count);
|
|
96
|
+
for (idx_t i = 0; i < column_count; i++) {
|
|
97
|
+
VALUE type_val = rb_ary_entry(types, i);
|
|
98
|
+
rubyDuckDBLogicalType *type_ctx = get_struct_logical_type(type_val);
|
|
99
|
+
type_array[i] = type_ctx->logical_type;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (table != Qnil) {
|
|
103
|
+
table_name = StringValuePtr(table);
|
|
104
|
+
}
|
|
105
|
+
if (columns != Qnil) {
|
|
106
|
+
if (rb_obj_is_kind_of(columns, rb_cArray) == Qfalse) {
|
|
107
|
+
rb_raise(rb_eTypeError, "4th argument should be an Array or nil");
|
|
108
|
+
}
|
|
109
|
+
idx_t col_count = RARRAY_LEN(columns);
|
|
110
|
+
column_names = ALLOCA_N(const char *, (size_t)col_count);
|
|
111
|
+
for (idx_t i = 0; i < col_count; i++) {
|
|
112
|
+
VALUE col_name_val = rb_ary_entry(columns, i);
|
|
113
|
+
column_names[i] = StringValuePtr(col_name_val);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
ctxcon = get_struct_connection(con);
|
|
117
|
+
appender = allocate(klass);
|
|
118
|
+
TypedData_Get_Struct(appender, rubyDuckDBAppender, &appender_data_type, ctx);
|
|
119
|
+
if (duckdb_appender_create_query(ctxcon->con, query_str, column_count, type_array, table_name, column_names, &ctx->appender) == DuckDBError) {
|
|
120
|
+
rb_raise(eDuckDBError, "failed to create appender from query");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return appender;
|
|
124
|
+
}
|
|
125
|
+
#endif
|
|
126
|
+
|
|
59
127
|
static VALUE appender_initialize(VALUE self, VALUE con, VALUE schema, VALUE table) {
|
|
60
128
|
|
|
61
129
|
rubyDuckDBConnection *ctxcon;
|
|
@@ -93,14 +161,27 @@ static VALUE appender_initialize(VALUE self, VALUE con, VALUE schema, VALUE tabl
|
|
|
93
161
|
*/
|
|
94
162
|
static VALUE appender_error_message(VALUE self) {
|
|
95
163
|
rubyDuckDBAppender *ctx;
|
|
96
|
-
|
|
164
|
+
#ifdef HAVE_DUCKDB_H_GE_V1_4_0
|
|
165
|
+
duckdb_error_data error_data;
|
|
166
|
+
#endif
|
|
167
|
+
const char *msg = NULL;
|
|
168
|
+
VALUE rb_msg = Qnil;
|
|
97
169
|
TypedData_Get_Struct(self, rubyDuckDBAppender, &appender_data_type, ctx);
|
|
98
170
|
|
|
171
|
+
#ifdef HAVE_DUCKDB_H_GE_V1_4_0
|
|
172
|
+
error_data = duckdb_appender_error_data(ctx->appender);
|
|
173
|
+
if (duckdb_error_data_has_error(error_data)) {
|
|
174
|
+
msg = duckdb_error_data_message(error_data);
|
|
175
|
+
rb_msg = rb_str_new2(msg);
|
|
176
|
+
}
|
|
177
|
+
duckdb_destroy_error_data(&error_data);
|
|
178
|
+
#else
|
|
99
179
|
msg = duckdb_appender_error(ctx->appender);
|
|
100
|
-
if (msg
|
|
101
|
-
|
|
180
|
+
if (msg != NULL) {
|
|
181
|
+
rb_msg = rb_str_new2(msg);
|
|
102
182
|
}
|
|
103
|
-
|
|
183
|
+
#endif
|
|
184
|
+
return rb_msg;
|
|
104
185
|
}
|
|
105
186
|
|
|
106
187
|
/* :nodoc: */
|
|
@@ -376,6 +457,9 @@ void rbduckdb_init_duckdb_appender(void) {
|
|
|
376
457
|
#endif
|
|
377
458
|
cDuckDBAppender = rb_define_class_under(mDuckDB, "Appender", rb_cObject);
|
|
378
459
|
rb_define_alloc_func(cDuckDBAppender, allocate);
|
|
460
|
+
#ifdef HAVE_DUCKDB_H_GE_V1_4_0
|
|
461
|
+
rb_define_singleton_method(cDuckDBAppender, "create_query", appender_s_create_query, 5);
|
|
462
|
+
#endif
|
|
379
463
|
rb_define_method(cDuckDBAppender, "initialize", appender_initialize, 3);
|
|
380
464
|
rb_define_method(cDuckDBAppender, "error_message", appender_error_message, 0);
|
|
381
465
|
rb_define_private_method(cDuckDBAppender, "_end_row", appender__end_row, 0);
|
data/ext/duckdb/database.c
CHANGED
|
@@ -6,6 +6,7 @@ static void close_database(rubyDuckDB *p);
|
|
|
6
6
|
static void deallocate(void * ctx);
|
|
7
7
|
static VALUE allocate(VALUE klass);
|
|
8
8
|
static size_t memsize(const void *p);
|
|
9
|
+
static duckdb_config create_config_with_ruby_api(void);
|
|
9
10
|
static VALUE duckdb_database_s_open(int argc, VALUE *argv, VALUE cDuckDBDatabase);
|
|
10
11
|
static VALUE duckdb_database_s_open_ext(int argc, VALUE *argv, VALUE cDuckDBDatabase);
|
|
11
12
|
static VALUE duckdb_database_connect(VALUE self);
|
|
@@ -43,10 +44,27 @@ rubyDuckDB *rbduckdb_get_struct_database(VALUE obj) {
|
|
|
43
44
|
return ctx;
|
|
44
45
|
}
|
|
45
46
|
|
|
47
|
+
static duckdb_config create_config_with_ruby_api(void) {
|
|
48
|
+
duckdb_config config;
|
|
49
|
+
|
|
50
|
+
if (duckdb_create_config(&config) == DuckDBError) {
|
|
51
|
+
rb_raise(eDuckDBError, "failed to create config");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (duckdb_set_config(config, "duckdb_api", "ruby") == DuckDBError) {
|
|
55
|
+
duckdb_destroy_config(&config);
|
|
56
|
+
rb_raise(eDuckDBError, "failed to set duckdb_api config");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return config;
|
|
60
|
+
}
|
|
61
|
+
|
|
46
62
|
/* :nodoc: */
|
|
47
63
|
static VALUE duckdb_database_s_open(int argc, VALUE *argv, VALUE cDuckDBDatabase) {
|
|
48
64
|
rubyDuckDB *ctx;
|
|
49
65
|
VALUE obj;
|
|
66
|
+
duckdb_config config;
|
|
67
|
+
char *perror = NULL;
|
|
50
68
|
|
|
51
69
|
char *pfile = NULL;
|
|
52
70
|
VALUE file = Qnil;
|
|
@@ -59,9 +77,19 @@ static VALUE duckdb_database_s_open(int argc, VALUE *argv, VALUE cDuckDBDatabase
|
|
|
59
77
|
|
|
60
78
|
obj = allocate(cDuckDBDatabase);
|
|
61
79
|
TypedData_Get_Struct(obj, rubyDuckDB, &database_data_type, ctx);
|
|
62
|
-
|
|
63
|
-
|
|
80
|
+
|
|
81
|
+
config = create_config_with_ruby_api();
|
|
82
|
+
|
|
83
|
+
if (duckdb_open_ext(pfile, &(ctx->db), config, &perror) == DuckDBError) {
|
|
84
|
+
VALUE error_msg = rb_str_new_cstr(perror ? perror : "Unknown error");
|
|
85
|
+
if (perror) {
|
|
86
|
+
duckdb_free(perror);
|
|
87
|
+
}
|
|
88
|
+
duckdb_destroy_config(&config);
|
|
89
|
+
rb_raise(eDuckDBError, "failed to open database: %s", StringValueCStr(error_msg));
|
|
64
90
|
}
|
|
91
|
+
|
|
92
|
+
duckdb_destroy_config(&config);
|
|
65
93
|
return obj;
|
|
66
94
|
}
|
|
67
95
|
|
|
@@ -70,7 +98,9 @@ static VALUE duckdb_database_s_open_ext(int argc, VALUE *argv, VALUE cDuckDBData
|
|
|
70
98
|
rubyDuckDB *ctx;
|
|
71
99
|
VALUE obj;
|
|
72
100
|
rubyDuckDBConfig *ctx_config;
|
|
73
|
-
|
|
101
|
+
duckdb_config config_to_use;
|
|
102
|
+
char *perror = NULL;
|
|
103
|
+
int need_destroy_config = 0;
|
|
74
104
|
|
|
75
105
|
char *pfile = NULL;
|
|
76
106
|
VALUE file = Qnil;
|
|
@@ -84,19 +114,37 @@ static VALUE duckdb_database_s_open_ext(int argc, VALUE *argv, VALUE cDuckDBData
|
|
|
84
114
|
|
|
85
115
|
obj = allocate(cDuckDBDatabase);
|
|
86
116
|
TypedData_Get_Struct(obj, rubyDuckDB, &database_data_type, ctx);
|
|
117
|
+
|
|
87
118
|
if (!NIL_P(config)) {
|
|
88
119
|
if (!rb_obj_is_kind_of(config, cDuckDBConfig)) {
|
|
89
120
|
rb_raise(rb_eTypeError, "The second argument must be DuckDB::Config object.");
|
|
90
121
|
}
|
|
91
122
|
ctx_config = get_struct_config(config);
|
|
92
|
-
|
|
93
|
-
|
|
123
|
+
/* Set duckdb_api to "ruby" for the provided config */
|
|
124
|
+
if (duckdb_set_config(ctx_config->config, "duckdb_api", "ruby") == DuckDBError) {
|
|
125
|
+
rb_raise(eDuckDBError, "failed to set duckdb_api config");
|
|
94
126
|
}
|
|
127
|
+
config_to_use = ctx_config->config;
|
|
95
128
|
} else {
|
|
96
|
-
|
|
97
|
-
|
|
129
|
+
config_to_use = create_config_with_ruby_api();
|
|
130
|
+
need_destroy_config = 1;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (duckdb_open_ext(pfile, &(ctx->db), config_to_use, &perror) == DuckDBError) {
|
|
134
|
+
VALUE error_msg = rb_str_new_cstr(perror ? perror : "Unknown error");
|
|
135
|
+
if (perror) {
|
|
136
|
+
duckdb_free(perror);
|
|
98
137
|
}
|
|
138
|
+
if (need_destroy_config) {
|
|
139
|
+
duckdb_destroy_config(&config_to_use);
|
|
140
|
+
}
|
|
141
|
+
rb_raise(eDuckDBError, "failed to open database: %s", StringValueCStr(error_msg));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (need_destroy_config) {
|
|
145
|
+
duckdb_destroy_config(&config_to_use);
|
|
99
146
|
}
|
|
147
|
+
|
|
100
148
|
return obj;
|
|
101
149
|
}
|
|
102
150
|
|
data/ext/duckdb/duckdb.c
CHANGED
|
@@ -39,7 +39,7 @@ Init_duckdb_native(void) {
|
|
|
39
39
|
rbduckdb_init_duckdb_config();
|
|
40
40
|
rbduckdb_init_duckdb_converter();
|
|
41
41
|
rbduckdb_init_duckdb_extracted_statements();
|
|
42
|
-
#ifdef HAVE_DUCKDB_H_GE_V1_2_0
|
|
43
42
|
rbduckdb_init_duckdb_instance_cache();
|
|
44
|
-
|
|
43
|
+
rbduckdb_init_duckdb_value_impl();
|
|
44
|
+
rbduckdb_init_duckdb_scalar_function();
|
|
45
45
|
}
|
data/ext/duckdb/extconf.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'mkmf'
|
|
4
4
|
|
|
5
|
-
DUCKDB_REQUIRED_VERSION = '1.
|
|
5
|
+
DUCKDB_REQUIRED_VERSION = '1.2.0'
|
|
6
6
|
|
|
7
7
|
def check_duckdb_header(header, version)
|
|
8
8
|
found = find_header(
|
|
@@ -56,10 +56,7 @@ end
|
|
|
56
56
|
dir_config('duckdb')
|
|
57
57
|
|
|
58
58
|
check_duckdb_header('duckdb.h', DUCKDB_REQUIRED_VERSION)
|
|
59
|
-
check_duckdb_library('duckdb', '
|
|
60
|
-
|
|
61
|
-
# check duckdb >= 1.1.0
|
|
62
|
-
have_func('duckdb_result_error_type', 'duckdb.h')
|
|
59
|
+
check_duckdb_library('duckdb', 'duckdb_create_instance_cache', DUCKDB_REQUIRED_VERSION)
|
|
63
60
|
|
|
64
61
|
# check duckdb >= 1.2.0
|
|
65
62
|
have_func('duckdb_create_instance_cache', 'duckdb.h')
|
|
@@ -67,9 +64,8 @@ have_func('duckdb_create_instance_cache', 'duckdb.h')
|
|
|
67
64
|
# check duckdb >= 1.3.0
|
|
68
65
|
have_func('duckdb_get_table_names', 'duckdb.h')
|
|
69
66
|
|
|
70
|
-
#
|
|
71
|
-
|
|
72
|
-
have_const('DUCKDB_TYPE_SQLNULL', 'duckdb.h')
|
|
67
|
+
# check duckdb >= 1.4.0
|
|
68
|
+
have_func('duckdb_appender_create_query', 'duckdb.h')
|
|
73
69
|
|
|
74
70
|
$CFLAGS << ' -DDUCKDB_API_NO_DEPRECATED' if ENV['DUCKDB_API_NO_DEPRECATED']
|
|
75
71
|
|
data/ext/duckdb/instance_cache.c
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
#include "ruby-duckdb.h"
|
|
2
2
|
|
|
3
|
-
#ifdef HAVE_DUCKDB_H_GE_V1_2_0
|
|
4
3
|
VALUE cDuckDBInstanceCache;
|
|
5
4
|
|
|
6
5
|
static void deallocate(void * ctx);
|
|
@@ -105,4 +104,3 @@ void rbduckdb_init_duckdb_instance_cache(void) {
|
|
|
105
104
|
rb_define_method(cDuckDBInstanceCache, "destroy", duckdb_instance_cache_destroy, 0);
|
|
106
105
|
rb_define_alloc_func(cDuckDBInstanceCache, allocate);
|
|
107
106
|
}
|
|
108
|
-
#endif
|
data/ext/duckdb/instance_cache.h
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
#ifndef RUBY_DUCKDB_INSTANCE_CACHE_H
|
|
2
2
|
#define RUBY_DUCKDB_INSTANCE_CACHE_H
|
|
3
3
|
|
|
4
|
-
#ifdef HAVE_DUCKDB_H_GE_V1_2_0
|
|
5
|
-
|
|
6
4
|
struct _rubyDuckDBInstanceCache {
|
|
7
5
|
duckdb_instance_cache instance_cache;
|
|
8
6
|
};
|
|
@@ -12,6 +10,3 @@ typedef struct _rubyDuckDBInstanceCache rubyDuckDBInstanceCache;
|
|
|
12
10
|
void rbduckdb_init_duckdb_instance_cache(void);
|
|
13
11
|
|
|
14
12
|
#endif
|
|
15
|
-
|
|
16
|
-
#endif
|
|
17
|
-
|
data/ext/duckdb/logical_type.c
CHANGED
|
@@ -23,6 +23,7 @@ static VALUE duckdb_logical_type_dictionary_size(VALUE self);
|
|
|
23
23
|
static VALUE duckdb_logical_type_dictionary_value_at(VALUE self, VALUE didx);
|
|
24
24
|
static VALUE duckdb_logical_type__get_alias(VALUE self);
|
|
25
25
|
static VALUE duckdb_logical_type__set_alias(VALUE self, VALUE aname);
|
|
26
|
+
static VALUE initialize(VALUE self, VALUE type_id_arg);
|
|
26
27
|
|
|
27
28
|
static const rb_data_type_t logical_type_data_type = {
|
|
28
29
|
"DuckDB/LogicalType",
|
|
@@ -40,6 +41,12 @@ static void deallocate(void *ctx) {
|
|
|
40
41
|
xfree(p);
|
|
41
42
|
}
|
|
42
43
|
|
|
44
|
+
rubyDuckDBLogicalType *get_struct_logical_type(VALUE obj) {
|
|
45
|
+
rubyDuckDBLogicalType *ctx;
|
|
46
|
+
TypedData_Get_Struct(obj, rubyDuckDBLogicalType, &logical_type_data_type, ctx);
|
|
47
|
+
return ctx;
|
|
48
|
+
}
|
|
49
|
+
|
|
43
50
|
static VALUE allocate(VALUE klass) {
|
|
44
51
|
rubyDuckDBLogicalType *ctx = xcalloc((size_t)1, sizeof(rubyDuckDBLogicalType));
|
|
45
52
|
return TypedData_Wrap_Struct(klass, &logical_type_data_type, ctx);
|
|
@@ -49,6 +56,31 @@ static size_t memsize(const void *p) {
|
|
|
49
56
|
return sizeof(rubyDuckDBLogicalType);
|
|
50
57
|
}
|
|
51
58
|
|
|
59
|
+
static VALUE initialize(VALUE self, VALUE type_id_arg) {
|
|
60
|
+
rubyDuckDBLogicalType *ctx;
|
|
61
|
+
duckdb_type type = (duckdb_type)NUM2INT(type_id_arg);
|
|
62
|
+
duckdb_logical_type new_logical_type;
|
|
63
|
+
|
|
64
|
+
TypedData_Get_Struct(self, rubyDuckDBLogicalType, &logical_type_data_type, ctx);
|
|
65
|
+
|
|
66
|
+
if (ctx->logical_type) {
|
|
67
|
+
duckdb_destroy_logical_type(&(ctx->logical_type));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
new_logical_type = duckdb_create_logical_type(type);
|
|
71
|
+
|
|
72
|
+
if (!new_logical_type || duckdb_get_type_id(new_logical_type) == DUCKDB_TYPE_INVALID) {
|
|
73
|
+
if (new_logical_type) {
|
|
74
|
+
duckdb_destroy_logical_type(&new_logical_type);
|
|
75
|
+
}
|
|
76
|
+
rb_raise(rb_eArgError, "Invalid or unsupported logical type ID: %d", type);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
ctx->logical_type = new_logical_type;
|
|
80
|
+
|
|
81
|
+
return self;
|
|
82
|
+
}
|
|
83
|
+
|
|
52
84
|
/*
|
|
53
85
|
* call-seq:
|
|
54
86
|
* decimal_col.logical_type.type -> Symbol
|
|
@@ -439,4 +471,6 @@ void rbduckdb_init_duckdb_logical_type(void) {
|
|
|
439
471
|
rb_define_method(cDuckDBLogicalType, "dictionary_value_at", duckdb_logical_type_dictionary_value_at, 1);
|
|
440
472
|
rb_define_method(cDuckDBLogicalType, "get_alias", duckdb_logical_type__get_alias, 0);
|
|
441
473
|
rb_define_method(cDuckDBLogicalType, "set_alias", duckdb_logical_type__set_alias, 1);
|
|
474
|
+
|
|
475
|
+
rb_define_method(cDuckDBLogicalType, "initialize", initialize, 1);
|
|
442
476
|
}
|
data/ext/duckdb/logical_type.h
CHANGED
data/ext/duckdb/result.c
CHANGED
|
@@ -48,6 +48,10 @@ static VALUE vector_hugeint(void* vector_data, idx_t row_idx);
|
|
|
48
48
|
static VALUE vector_uhugeint(void* vector_data, idx_t row_idx);
|
|
49
49
|
static VALUE vector_decimal(duckdb_logical_type ty, void* vector_data, idx_t row_idx);
|
|
50
50
|
static VALUE infinite_timestamp_value(duckdb_timestamp timestamp);
|
|
51
|
+
static VALUE infinite_timestamp_s_value(duckdb_timestamp_s timestamp_s);
|
|
52
|
+
static VALUE infinite_timestamp_ms_value(duckdb_timestamp_ms timestamp_ms);
|
|
53
|
+
static VALUE infinite_timestamp_ns_value(duckdb_timestamp_ns timestamp_ns);
|
|
54
|
+
|
|
51
55
|
static VALUE vector_timestamp_s(void* vector_data, idx_t row_idx);
|
|
52
56
|
static VALUE vector_timestamp_ms(void* vector_data, idx_t row_idx);
|
|
53
57
|
static VALUE vector_timestamp_ns(void* vector_data, idx_t row_idx);
|
|
@@ -223,14 +227,7 @@ static VALUE duckdb_result__column_type(VALUE oDuckDBResult, VALUE col_idx) {
|
|
|
223
227
|
static VALUE duckdb_result__return_type(VALUE oDuckDBResult) {
|
|
224
228
|
rubyDuckDBResult *ctx;
|
|
225
229
|
TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx);
|
|
226
|
-
/*
|
|
227
|
-
* remove this #if ... #else statement when dropping duckdb 1.1.0.
|
|
228
|
-
*/
|
|
229
|
-
#if !defined(HAVE_DUCKDB_H_GE_V1_1_1) && defined(DUCKDB_API_NO_DEPRECATED)
|
|
230
|
-
rb_raise(eDuckDBError, "duckdb_result_return_type C-API is not available with duckdb v1.1.0 with enabled DUCKDB_API_NO_DEPRECATED.");
|
|
231
|
-
#else
|
|
232
230
|
return INT2FIX(duckdb_result_return_type(ctx->result));
|
|
233
|
-
#endif
|
|
234
231
|
}
|
|
235
232
|
|
|
236
233
|
/* :nodoc: */
|
|
@@ -438,24 +435,63 @@ static VALUE infinite_timestamp_value(duckdb_timestamp timestamp) {
|
|
|
438
435
|
return Qnil;
|
|
439
436
|
}
|
|
440
437
|
|
|
438
|
+
static VALUE infinite_timestamp_s_value(duckdb_timestamp_s timestamp_s) {
|
|
439
|
+
if (duckdb_is_finite_timestamp_s(timestamp_s) == false) {
|
|
440
|
+
return rb_funcall(mDuckDBConverter, id__to_infinity, 1,
|
|
441
|
+
LL2NUM(timestamp_s.seconds)
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
return Qnil;
|
|
445
|
+
}
|
|
446
|
+
|
|
441
447
|
static VALUE vector_timestamp_s(void* vector_data, idx_t row_idx) {
|
|
442
|
-
|
|
448
|
+
duckdb_timestamp_s data = ((duckdb_timestamp_s *)vector_data)[row_idx];
|
|
449
|
+
VALUE obj = infinite_timestamp_s_value(data);
|
|
450
|
+
if (obj != Qnil) {
|
|
451
|
+
return obj;
|
|
452
|
+
}
|
|
443
453
|
return rb_funcall(mDuckDBConverter, id__to_time_from_duckdb_timestamp_s, 1,
|
|
444
|
-
LL2NUM(data.
|
|
445
|
-
|
|
454
|
+
LL2NUM(data.seconds)
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
static VALUE infinite_timestamp_ms_value(duckdb_timestamp_ms timestamp_ms) {
|
|
459
|
+
if (duckdb_is_finite_timestamp_ms(timestamp_ms) == false) {
|
|
460
|
+
return rb_funcall(mDuckDBConverter, id__to_infinity, 1,
|
|
461
|
+
LL2NUM(timestamp_ms.millis)
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
return Qnil;
|
|
446
465
|
}
|
|
447
466
|
|
|
448
467
|
static VALUE vector_timestamp_ms(void* vector_data, idx_t row_idx) {
|
|
449
|
-
|
|
468
|
+
duckdb_timestamp_ms data = ((duckdb_timestamp_ms *)vector_data)[row_idx];
|
|
469
|
+
VALUE obj = infinite_timestamp_ms_value(data);
|
|
470
|
+
if (obj != Qnil) {
|
|
471
|
+
return obj;
|
|
472
|
+
}
|
|
450
473
|
return rb_funcall(mDuckDBConverter, id__to_time_from_duckdb_timestamp_ms, 1,
|
|
451
|
-
LL2NUM(data.
|
|
474
|
+
LL2NUM(data.millis)
|
|
452
475
|
);
|
|
453
476
|
}
|
|
454
477
|
|
|
478
|
+
static VALUE infinite_timestamp_ns_value(duckdb_timestamp_ns timestamp_ns) {
|
|
479
|
+
if (duckdb_is_finite_timestamp_ns(timestamp_ns) == false) {
|
|
480
|
+
return rb_funcall(mDuckDBConverter, id__to_infinity, 1,
|
|
481
|
+
LL2NUM(timestamp_ns.nanos)
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
return Qnil;
|
|
485
|
+
}
|
|
486
|
+
|
|
455
487
|
static VALUE vector_timestamp_ns(void* vector_data, idx_t row_idx) {
|
|
456
|
-
|
|
488
|
+
duckdb_timestamp_ns data = ((duckdb_timestamp_ns *)vector_data)[row_idx];
|
|
489
|
+
VALUE obj = infinite_timestamp_ns_value(data);
|
|
490
|
+
if (obj != Qnil) {
|
|
491
|
+
return obj;
|
|
492
|
+
}
|
|
457
493
|
return rb_funcall(mDuckDBConverter, id__to_time_from_duckdb_timestamp_ns, 1,
|
|
458
|
-
LL2NUM(data.
|
|
494
|
+
LL2NUM(data.nanos)
|
|
459
495
|
);
|
|
460
496
|
}
|
|
461
497
|
|
data/ext/duckdb/ruby-duckdb.h
CHANGED
|
@@ -8,18 +8,14 @@
|
|
|
8
8
|
#include "ruby/thread.h"
|
|
9
9
|
#include <duckdb.h>
|
|
10
10
|
|
|
11
|
-
#ifdef HAVE_CONST_DUCKDB_TYPE_SQLNULL
|
|
12
|
-
#define HAVE_DUCKDB_H_GE_V1_1_1 1
|
|
13
|
-
#endif
|
|
14
|
-
|
|
15
|
-
#ifdef HAVE_DUCKDB_CREATE_INSTANCE_CACHE
|
|
16
|
-
#define HAVE_DUCKDB_H_GE_V1_2_0 1
|
|
17
|
-
#endif
|
|
18
|
-
|
|
19
11
|
#ifdef HAVE_DUCKDB_GET_TABLE_NAMES
|
|
20
12
|
#define HAVE_DUCKDB_H_GE_V1_3_0 1
|
|
21
13
|
#endif
|
|
22
14
|
|
|
15
|
+
#ifdef HAVE_DUCKDB_APPENDER_CREATE_QUERY
|
|
16
|
+
#define HAVE_DUCKDB_H_GE_V1_4_0 1
|
|
17
|
+
#endif
|
|
18
|
+
|
|
23
19
|
#include "./error.h"
|
|
24
20
|
#include "./database.h"
|
|
25
21
|
#include "./connection.h"
|
|
@@ -35,10 +31,9 @@
|
|
|
35
31
|
#include "./blob.h"
|
|
36
32
|
#include "./appender.h"
|
|
37
33
|
#include "./config.h"
|
|
38
|
-
|
|
39
|
-
#ifdef HAVE_DUCKDB_H_GE_V1_2_0
|
|
40
34
|
#include "./instance_cache.h"
|
|
41
|
-
#
|
|
35
|
+
#include "./value_impl.h"
|
|
36
|
+
#include "./scalar_function.h"
|
|
42
37
|
|
|
43
38
|
extern VALUE mDuckDB;
|
|
44
39
|
extern VALUE cDuckDBDatabase;
|
|
@@ -50,9 +45,8 @@ extern VALUE mDuckDBConverter;
|
|
|
50
45
|
extern VALUE cDuckDBPreparedStatement;
|
|
51
46
|
extern VALUE PositiveInfinity;
|
|
52
47
|
extern VALUE NegativeInfinity;
|
|
53
|
-
|
|
54
|
-
#ifdef HAVE_DUCKDB_H_GE_V1_2_0
|
|
55
48
|
extern VALUE cDuckDBInstanceCache;
|
|
56
|
-
|
|
49
|
+
extern VALUE cDuckDBValueImpl;
|
|
50
|
+
extern VALUE cDuckDBScalarFunction;
|
|
57
51
|
|
|
58
52
|
#endif
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#include "ruby-duckdb.h"
|
|
2
|
+
|
|
3
|
+
VALUE cDuckDBScalarFunction;
|
|
4
|
+
|
|
5
|
+
static void deallocate(void *);
|
|
6
|
+
static VALUE allocate(VALUE klass);
|
|
7
|
+
static size_t memsize(const void *p);
|
|
8
|
+
static VALUE duckdb_scalar_function_initialize(VALUE self);
|
|
9
|
+
static VALUE rbduckdb_scalar_function_set_name(VALUE self, VALUE name);
|
|
10
|
+
|
|
11
|
+
static const rb_data_type_t scalar_function_data_type = {
|
|
12
|
+
"DuckDB/ScalarFunction",
|
|
13
|
+
{NULL, deallocate, memsize,},
|
|
14
|
+
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
static void deallocate(void * ctx) {
|
|
18
|
+
rubyDuckDBScalarFunction *p = (rubyDuckDBScalarFunction *)ctx;
|
|
19
|
+
duckdb_destroy_scalar_function(&(p->scalar_function));
|
|
20
|
+
xfree(p);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static VALUE allocate(VALUE klass) {
|
|
24
|
+
rubyDuckDBScalarFunction *ctx = xcalloc((size_t)1, sizeof(rubyDuckDBScalarFunction));
|
|
25
|
+
return TypedData_Wrap_Struct(klass, &scalar_function_data_type, ctx);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
static size_t memsize(const void *p) {
|
|
29
|
+
return sizeof(rubyDuckDBScalarFunction);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
static VALUE duckdb_scalar_function_initialize(VALUE self) {
|
|
33
|
+
rubyDuckDBScalarFunction *p;
|
|
34
|
+
TypedData_Get_Struct(self, rubyDuckDBScalarFunction, &scalar_function_data_type, p);
|
|
35
|
+
p->scalar_function = duckdb_create_scalar_function();
|
|
36
|
+
return self;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static VALUE rbduckdb_scalar_function_set_name(VALUE self, VALUE name) {
|
|
40
|
+
rubyDuckDBScalarFunction *p;
|
|
41
|
+
TypedData_Get_Struct(self, rubyDuckDBScalarFunction, &scalar_function_data_type, p);
|
|
42
|
+
|
|
43
|
+
const char *str = StringValuePtr(name);
|
|
44
|
+
duckdb_scalar_function_set_name(p->scalar_function, str);
|
|
45
|
+
|
|
46
|
+
return self;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
void rbduckdb_init_duckdb_scalar_function(void) {
|
|
50
|
+
#if 0
|
|
51
|
+
VALUE mDuckDB = rb_define_module("DuckDB");
|
|
52
|
+
#endif
|
|
53
|
+
cDuckDBScalarFunction = rb_define_class_under(mDuckDB, "ScalarFunction", rb_cObject);
|
|
54
|
+
rb_define_alloc_func(cDuckDBScalarFunction, allocate);
|
|
55
|
+
rb_define_method(cDuckDBScalarFunction, "initialize", duckdb_scalar_function_initialize, 0);
|
|
56
|
+
rb_define_method(cDuckDBScalarFunction, "set_name", rbduckdb_scalar_function_set_name, 1);
|
|
57
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#ifndef RUBY_DUCKDB_SCALAR_FUNCTION_H
|
|
2
|
+
#define RUBY_DUCKDB_SCALAR_FUNCTION_H
|
|
3
|
+
|
|
4
|
+
struct _rubyDuckDBScalarFunction {
|
|
5
|
+
duckdb_scalar_function scalar_function;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
typedef struct _rubyDuckDBScalarFunction rubyDuckDBScalarFunction;
|
|
9
|
+
|
|
10
|
+
void rbduckdb_init_duckdb_scalar_function(void);
|
|
11
|
+
|
|
12
|
+
#endif
|
|
13
|
+
|
|
14
|
+
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#include "ruby-duckdb.h"
|
|
2
|
+
|
|
3
|
+
VALUE cDuckDBValueImpl;
|
|
4
|
+
|
|
5
|
+
static void deallocate(void *);
|
|
6
|
+
static VALUE allocate(VALUE klass);
|
|
7
|
+
static size_t memsize(const void *p);
|
|
8
|
+
|
|
9
|
+
static const rb_data_type_t value_impl_data_type = {
|
|
10
|
+
"DuckDB/ValueImpl",
|
|
11
|
+
{NULL, deallocate, memsize,},
|
|
12
|
+
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
static void deallocate(void * ctx) {
|
|
16
|
+
rubyDuckDBValueImpl *p = (rubyDuckDBValueImpl *)ctx;
|
|
17
|
+
|
|
18
|
+
duckdb_destroy_value(&(p->value));
|
|
19
|
+
xfree(p);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static VALUE allocate(VALUE klass) {
|
|
23
|
+
rubyDuckDBValueImpl *ctx = xcalloc((size_t)1, sizeof(rubyDuckDBValueImpl));
|
|
24
|
+
return TypedData_Wrap_Struct(klass, &value_impl_data_type, ctx);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
static size_t memsize(const void *p) {
|
|
28
|
+
return sizeof(rubyDuckDBValueImpl);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
void rbduckdb_init_duckdb_value_impl(void) {
|
|
32
|
+
#if 0
|
|
33
|
+
VALUE mDuckDB = rb_define_module("DuckDB");
|
|
34
|
+
#endif
|
|
35
|
+
cDuckDBValueImpl = rb_define_class_under(mDuckDB, "ValueImpl", rb_cObject);
|
|
36
|
+
rb_define_alloc_func(cDuckDBValueImpl, allocate);
|
|
37
|
+
}
|
|
38
|
+
|
data/getduckdb.sh
CHANGED
|
@@ -3,8 +3,16 @@
|
|
|
3
3
|
MACHINE=`uname -m`
|
|
4
4
|
|
|
5
5
|
case "$MACHINE" in
|
|
6
|
-
"x86_64"
|
|
7
|
-
|
|
6
|
+
"x86_64")
|
|
7
|
+
ARCH=amd64
|
|
8
|
+
;;
|
|
9
|
+
"aarch64")
|
|
10
|
+
if printf '%s\n' '1.3.0' "$DUCKDB_VERSION" | sort -C -V; then
|
|
11
|
+
ARCH=arm64
|
|
12
|
+
else
|
|
13
|
+
ARCH=aarch64
|
|
14
|
+
fi
|
|
15
|
+
;;
|
|
8
16
|
esac
|
|
9
17
|
|
|
10
|
-
wget -O duckdb.zip "https://github.com/duckdb/duckdb/releases/download/v$DUCKDB_VERSION/libduckdb-linux-$
|
|
18
|
+
wget -O duckdb.zip "https://github.com/duckdb/duckdb/releases/download/v$DUCKDB_VERSION/libduckdb-linux-$ARCH.zip"
|
data/lib/duckdb/appender.rb
CHANGED
|
@@ -23,6 +23,10 @@ module DuckDB
|
|
|
23
23
|
private_constant :RANGE_INT16, :RANGE_INT32, :RANGE_INT64
|
|
24
24
|
# :startdoc:
|
|
25
25
|
|
|
26
|
+
class << self
|
|
27
|
+
alias from_query create_query if DuckDB::Appender.respond_to?(:create_query)
|
|
28
|
+
end
|
|
29
|
+
|
|
26
30
|
# :call-seq:
|
|
27
31
|
# appender.begin_row -> self
|
|
28
32
|
# A nop method, provided for backwards compatibility reasons.
|
data/lib/duckdb/connection.rb
CHANGED
|
@@ -136,6 +136,28 @@ module DuckDB
|
|
|
136
136
|
appender.close
|
|
137
137
|
end
|
|
138
138
|
|
|
139
|
+
if Appender.respond_to?(:create_query)
|
|
140
|
+
# :call-seq:
|
|
141
|
+
# connection.appender_from_query(query, types, table_name = nil, column_names = nil) -> DuckDB::Appender
|
|
142
|
+
#
|
|
143
|
+
# Creates an appender object that executes the given query with any data appended to it.
|
|
144
|
+
# The `table_name` parameter is used to refer to the appended data in the query. If omitted, it defaults to "appended_data".
|
|
145
|
+
# The `column_names` parameter provides names for the columns of the appended data. If omitted, it defaults to "col1", "col2", etc.
|
|
146
|
+
#
|
|
147
|
+
# require 'duckdb'
|
|
148
|
+
# db = DuckDB::Database.open
|
|
149
|
+
# con = db.connect
|
|
150
|
+
# con.query('CREATE TABLE t (i INT PRIMARY KEY, value VARCHAR)')
|
|
151
|
+
# query = 'INSERT OR REPLACE INTO t SELECT i, val FROM my_appended_data'
|
|
152
|
+
# types = [DuckDB::LogicalType::INTEGER, DuckDB::LogicalType::VARCHAR]
|
|
153
|
+
# appender = con.appender_from_query(query, types, 'my_appended_data', %w[i val])
|
|
154
|
+
# appender.append_row(1, 'hello world')
|
|
155
|
+
# appender.close
|
|
156
|
+
def appender_from_query(query, types, table_name = nil, column_names = nil)
|
|
157
|
+
Appender.create_query(self, query, types, table_name, column_names)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
139
161
|
private
|
|
140
162
|
|
|
141
163
|
def create_appender(table)
|
data/lib/duckdb/logical_type.rb
CHANGED
|
@@ -5,6 +5,55 @@ module DuckDB
|
|
|
5
5
|
alias :alias get_alias
|
|
6
6
|
alias :alias= set_alias
|
|
7
7
|
|
|
8
|
+
@logical_types = {}
|
|
9
|
+
|
|
10
|
+
{
|
|
11
|
+
boolean: 1,
|
|
12
|
+
tinyint: 2,
|
|
13
|
+
smallint: 3,
|
|
14
|
+
integer: 4,
|
|
15
|
+
bigint: 5,
|
|
16
|
+
utinyint: 6,
|
|
17
|
+
usmallint: 7,
|
|
18
|
+
uinteger: 8,
|
|
19
|
+
ubigint: 9,
|
|
20
|
+
float: 10,
|
|
21
|
+
double: 11,
|
|
22
|
+
timestamp: 12,
|
|
23
|
+
date: 13,
|
|
24
|
+
time: 14,
|
|
25
|
+
interval: 15,
|
|
26
|
+
hugeint: 16,
|
|
27
|
+
uhugeint: 32,
|
|
28
|
+
varchar: 17,
|
|
29
|
+
blob: 18,
|
|
30
|
+
# decimal: 19,
|
|
31
|
+
timestamp_s: 20,
|
|
32
|
+
timestamp_ms: 21,
|
|
33
|
+
timestamp_ns: 22,
|
|
34
|
+
# enum: 23,
|
|
35
|
+
# list: 24,
|
|
36
|
+
# struct: 25,
|
|
37
|
+
# map: 26,
|
|
38
|
+
# array: 33,
|
|
39
|
+
# uuid: 27,
|
|
40
|
+
# union: 28,
|
|
41
|
+
bit: 29,
|
|
42
|
+
time_tz: 30,
|
|
43
|
+
timestamp_tz: 31,
|
|
44
|
+
any: 34,
|
|
45
|
+
bignum: 35,
|
|
46
|
+
sqlnull: 36,
|
|
47
|
+
string_literal: 37,
|
|
48
|
+
integer_literal: 38
|
|
49
|
+
# time_ns: 39
|
|
50
|
+
}.each do |method_name, type_id|
|
|
51
|
+
define_singleton_method(method_name) do
|
|
52
|
+
@logical_types[type_id] ||= DuckDB::LogicalType.new(type_id)
|
|
53
|
+
end
|
|
54
|
+
const_set(method_name.upcase, send(method_name))
|
|
55
|
+
end
|
|
56
|
+
|
|
8
57
|
# returns logical type's type symbol
|
|
9
58
|
# `:unknown` means that the logical type's type is unknown/unsupported by ruby-duckdb.
|
|
10
59
|
# `:invalid` means that the logical type's type is invalid in duckdb.
|
data/lib/duckdb/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: duckdb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.4.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Masaki Suketa
|
|
@@ -143,8 +143,12 @@ files:
|
|
|
143
143
|
- ext/duckdb/result.c
|
|
144
144
|
- ext/duckdb/result.h
|
|
145
145
|
- ext/duckdb/ruby-duckdb.h
|
|
146
|
+
- ext/duckdb/scalar_function.c
|
|
147
|
+
- ext/duckdb/scalar_function.h
|
|
146
148
|
- ext/duckdb/util.c
|
|
147
149
|
- ext/duckdb/util.h
|
|
150
|
+
- ext/duckdb/value_impl.c
|
|
151
|
+
- ext/duckdb/value_impl.h
|
|
148
152
|
- getduckdb.sh
|
|
149
153
|
- lib/duckdb.rb
|
|
150
154
|
- lib/duckdb/appender.rb
|
|
@@ -181,14 +185,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
181
185
|
requirements:
|
|
182
186
|
- - ">="
|
|
183
187
|
- !ruby/object:Gem::Version
|
|
184
|
-
version: 3.
|
|
188
|
+
version: 3.2.0
|
|
185
189
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
186
190
|
requirements:
|
|
187
191
|
- - ">="
|
|
188
192
|
- !ruby/object:Gem::Version
|
|
189
193
|
version: '0'
|
|
190
194
|
requirements: []
|
|
191
|
-
rubygems_version: 3.6.
|
|
195
|
+
rubygems_version: 3.6.9
|
|
192
196
|
specification_version: 4
|
|
193
197
|
summary: This module is Ruby binding for DuckDB database engine.
|
|
194
198
|
test_files: []
|