duckdb 0.2.8.0 → 0.3.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 +21 -4
- data/.github/workflows/test_on_ubuntu.yml +26 -37
- data/.github/workflows/test_on_windows.yml +22 -9
- data/CHANGELOG.md +37 -0
- data/CONTRIBUTION.md +24 -0
- data/Gemfile.lock +2 -1
- data/README.md +31 -3
- data/duckdb.gemspec +2 -2
- data/ext/duckdb/appender.c +117 -4
- data/ext/duckdb/blob.c +1 -5
- data/ext/duckdb/blob.h +0 -4
- data/ext/duckdb/config.c +3 -5
- data/ext/duckdb/connection.c +14 -15
- data/ext/duckdb/database.c +10 -16
- data/ext/duckdb/duckdb.c +1 -7
- data/ext/duckdb/error.c +1 -2
- data/ext/duckdb/extconf.rb +29 -8
- data/ext/duckdb/prepared_statement.c +136 -40
- data/ext/duckdb/result.c +70 -41
- data/ext/duckdb/ruby-duckdb.h +1 -16
- data/ext/duckdb/util.c +45 -0
- data/ext/duckdb/util.h +13 -0
- data/lib/duckdb/appender.rb +158 -10
- data/lib/duckdb/config.rb +1 -4
- data/lib/duckdb/converter.rb +52 -0
- data/lib/duckdb/prepared_statement.rb +114 -10
- data/lib/duckdb/version.rb +1 -1
- data/lib/duckdb.rb +1 -0
- metadata +8 -5
- data/.travis.yml +0 -18
data/ext/duckdb/database.c
CHANGED
@@ -7,28 +7,26 @@ static void deallocate(void * ctx);
|
|
7
7
|
static VALUE allocate(VALUE klass);
|
8
8
|
static VALUE duckdb_database_s_open(int argc, VALUE *argv, VALUE cDuckDBDatabase);
|
9
9
|
static VALUE duckdb_database_s_open_ext(int argc, VALUE *argv, VALUE cDuckDBDatabase);
|
10
|
+
static VALUE duckdb_database_connect(VALUE self);
|
11
|
+
static VALUE duckdb_database_close(VALUE self);
|
10
12
|
|
11
|
-
static void close_database(rubyDuckDB *p)
|
12
|
-
{
|
13
|
+
static void close_database(rubyDuckDB *p) {
|
13
14
|
duckdb_close(&(p->db));
|
14
15
|
}
|
15
16
|
|
16
|
-
static void deallocate(void * ctx)
|
17
|
-
{
|
17
|
+
static void deallocate(void * ctx) {
|
18
18
|
rubyDuckDB *p = (rubyDuckDB *)ctx;
|
19
19
|
|
20
20
|
close_database(p);
|
21
21
|
xfree(p);
|
22
22
|
}
|
23
23
|
|
24
|
-
static VALUE allocate(VALUE klass)
|
25
|
-
{
|
24
|
+
static VALUE allocate(VALUE klass) {
|
26
25
|
rubyDuckDB *ctx = xcalloc((size_t)1, sizeof(rubyDuckDB));
|
27
26
|
return Data_Wrap_Struct(klass, NULL, deallocate, ctx);
|
28
27
|
}
|
29
28
|
|
30
|
-
static VALUE duckdb_database_s_open(int argc, VALUE *argv, VALUE cDuckDBDatabase)
|
31
|
-
{
|
29
|
+
static VALUE duckdb_database_s_open(int argc, VALUE *argv, VALUE cDuckDBDatabase) {
|
32
30
|
rubyDuckDB *ctx;
|
33
31
|
VALUE obj;
|
34
32
|
|
@@ -50,8 +48,7 @@ static VALUE duckdb_database_s_open(int argc, VALUE *argv, VALUE cDuckDBDatabase
|
|
50
48
|
}
|
51
49
|
|
52
50
|
#ifdef HAVE_DUCKDB_OPEN_EXT
|
53
|
-
static VALUE duckdb_database_s_open_ext(int argc, VALUE *argv, VALUE cDuckDBDatabase)
|
54
|
-
{
|
51
|
+
static VALUE duckdb_database_s_open_ext(int argc, VALUE *argv, VALUE cDuckDBDatabase) {
|
55
52
|
rubyDuckDB *ctx;
|
56
53
|
VALUE obj;
|
57
54
|
rubyDuckDBConfig *ctx_config;
|
@@ -86,8 +83,7 @@ static VALUE duckdb_database_s_open_ext(int argc, VALUE *argv, VALUE cDuckDBData
|
|
86
83
|
}
|
87
84
|
#endif /* HAVE_DUCKDB_OPEN_EXT */
|
88
85
|
|
89
|
-
static VALUE duckdb_database_connect(VALUE self)
|
90
|
-
{
|
86
|
+
static VALUE duckdb_database_connect(VALUE self) {
|
91
87
|
return create_connection(self);
|
92
88
|
}
|
93
89
|
|
@@ -97,16 +93,14 @@ static VALUE duckdb_database_connect(VALUE self)
|
|
97
93
|
*
|
98
94
|
* closes DuckDB database.
|
99
95
|
*/
|
100
|
-
static VALUE duckdb_database_close(VALUE self)
|
101
|
-
{
|
96
|
+
static VALUE duckdb_database_close(VALUE self) {
|
102
97
|
rubyDuckDB *ctx;
|
103
98
|
Data_Get_Struct(self, rubyDuckDB, ctx);
|
104
99
|
close_database(ctx);
|
105
100
|
return self;
|
106
101
|
}
|
107
102
|
|
108
|
-
void init_duckdb_database(void)
|
109
|
-
{
|
103
|
+
void init_duckdb_database(void) {
|
110
104
|
cDuckDBDatabase = rb_define_class_under(mDuckDB, "Database", rb_cObject);
|
111
105
|
rb_define_alloc_func(cDuckDBDatabase, allocate);
|
112
106
|
rb_define_singleton_method(cDuckDBDatabase, "_open", duckdb_database_s_open, -1);
|
data/ext/duckdb/duckdb.c
CHANGED
@@ -3,8 +3,7 @@
|
|
3
3
|
VALUE mDuckDB;
|
4
4
|
|
5
5
|
void
|
6
|
-
Init_duckdb_native(void)
|
7
|
-
{
|
6
|
+
Init_duckdb_native(void) {
|
8
7
|
mDuckDB = rb_define_module("DuckDB");
|
9
8
|
|
10
9
|
init_duckdb_error();
|
@@ -12,13 +11,8 @@ Init_duckdb_native(void)
|
|
12
11
|
init_duckdb_connection();
|
13
12
|
init_duckdb_result();
|
14
13
|
init_duckdb_prepared_statement();
|
15
|
-
|
16
|
-
#ifdef HAVE_DUCKDB_VALUE_BLOB
|
17
|
-
|
18
14
|
init_duckdb_blob();
|
19
15
|
|
20
|
-
#endif /* HAVE_DUCKDB_VALUE_BLOB */
|
21
|
-
|
22
16
|
#ifdef HAVE_DUCKDB_APPENDER_CREATE
|
23
17
|
|
24
18
|
init_duckdb_appender();
|
data/ext/duckdb/error.c
CHANGED
data/ext/duckdb/extconf.rb
CHANGED
@@ -1,12 +1,33 @@
|
|
1
1
|
require 'mkmf'
|
2
2
|
|
3
3
|
dir_config('duckdb')
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
4
|
+
|
5
|
+
raise 'duckdb library is not found. Install duckdb library file and header file.' unless have_library('duckdb')
|
6
|
+
|
7
|
+
raise 'duckdb >= 0.2.9 is required. Install duckdb >= 0.2.9' unless have_func('duckdb_value_is_null', 'duckdb.h')
|
8
|
+
|
9
|
+
if have_func('duckdb_nparams(NULL)', 'duckdb.h')
|
10
|
+
$defs << '-DHAVE_DUCKDB_NPARAMS_029'
|
11
|
+
elsif have_func('duckdb_nparams(NULL, NULL)', 'duckdb.h')
|
12
|
+
$defs << '-DHAVE_DUCKDB_NPARAMS_028'
|
12
13
|
end
|
14
|
+
|
15
|
+
have_func('duckdb_appender_create', 'duckdb.h')
|
16
|
+
have_func('duckdb_free', 'duckdb.h')
|
17
|
+
|
18
|
+
have_func('duckdb_create_config', 'duckdb.h')
|
19
|
+
have_func('duckdb_open_ext', 'duckdb.h')
|
20
|
+
have_func('duckdb_prepare_error', 'duckdb.h')
|
21
|
+
|
22
|
+
have_func('duckdb_append_date', 'duckdb.h')
|
23
|
+
have_func('duckdb_append_interval', 'duckdb.h')
|
24
|
+
have_func('duckdb_append_time', 'duckdb.h')
|
25
|
+
have_func('duckdb_append_timestamp', 'duckdb.h')
|
26
|
+
have_func('duckdb_append_hugeint', 'duckdb.h')
|
27
|
+
|
28
|
+
have_func('duckdb_bind_date', 'duckdb.h')
|
29
|
+
have_func('duckdb_bind_time', 'duckdb.h')
|
30
|
+
have_func('duckdb_bind_timestamp', 'duckdb.h')
|
31
|
+
have_func('duckdb_bind_interval', 'duckdb.h')
|
32
|
+
|
33
|
+
create_makefile('duckdb/duckdb_native')
|
@@ -2,22 +2,53 @@
|
|
2
2
|
|
3
3
|
static VALUE cDuckDBPreparedStatement;
|
4
4
|
|
5
|
-
static void deallocate(void *ctx)
|
6
|
-
|
5
|
+
static void deallocate(void *ctx);
|
6
|
+
static VALUE allocate(VALUE klass);
|
7
|
+
static VALUE duckdb_prepared_statement_initialize(VALUE self, VALUE con, VALUE query);
|
8
|
+
static VALUE duckdb_prepared_statement_nparams(VALUE self);
|
9
|
+
static VALUE duckdb_prepared_statement_execute(VALUE self);
|
10
|
+
static idx_t check_index(VALUE vidx);
|
11
|
+
static VALUE duckdb_prepared_statement_bind_bool(VALUE self, VALUE vidx, VALUE val);
|
12
|
+
static VALUE duckdb_prepared_statement_bind_int8(VALUE self, VALUE vidx, VALUE val);
|
13
|
+
static VALUE duckdb_prepared_statement_bind_int16(VALUE self, VALUE vidx, VALUE val);
|
14
|
+
static VALUE duckdb_prepared_statement_bind_int32(VALUE self, VALUE vidx, VALUE val);
|
15
|
+
static VALUE duckdb_prepared_statement_bind_int64(VALUE self, VALUE vidx, VALUE val);
|
16
|
+
static VALUE duckdb_prepared_statement_bind_float(VALUE self, VALUE vidx, VALUE val);
|
17
|
+
static VALUE duckdb_prepared_statement_bind_double(VALUE self, VALUE vidx, VALUE val);
|
18
|
+
static VALUE duckdb_prepared_statement_bind_varchar(VALUE self, VALUE vidx, VALUE str);
|
19
|
+
static VALUE duckdb_prepared_statement_bind_blob(VALUE self, VALUE vidx, VALUE blob);
|
20
|
+
static VALUE duckdb_prepared_statement_bind_null(VALUE self, VALUE vidx);
|
21
|
+
|
22
|
+
#ifdef HAVE_DUCKDB_BIND_DATE
|
23
|
+
static VALUE duckdb_prepared_statement__bind_date(VALUE self, VALUE vidx, VALUE year, VALUE month, VALUE day);
|
24
|
+
#endif
|
25
|
+
|
26
|
+
#ifdef HAVE_DUCKDB_BIND_TIME
|
27
|
+
static VALUE duckdb_prepared_statement__bind_time(VALUE self, VALUE vidx, VALUE hour, VALUE min, VALUE sec, VALUE micros);
|
28
|
+
#endif
|
29
|
+
|
30
|
+
#ifdef HAVE_DUCKDB_BIND_TIMESTAMP
|
31
|
+
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);
|
32
|
+
#endif
|
33
|
+
|
34
|
+
#ifdef HAVE_DUCKDB_BIND_INTERVAL
|
35
|
+
static VALUE duckdb_prepared_statement__bind_interval(VALUE self, VALUE vidx, VALUE months, VALUE days, VALUE micros);
|
36
|
+
#endif
|
37
|
+
|
38
|
+
|
39
|
+
static void deallocate(void *ctx) {
|
7
40
|
rubyDuckDBPreparedStatement *p = (rubyDuckDBPreparedStatement *)ctx;
|
8
41
|
|
9
42
|
duckdb_destroy_prepare(&(p->prepared_statement));
|
10
43
|
xfree(p);
|
11
44
|
}
|
12
45
|
|
13
|
-
static VALUE allocate(VALUE klass)
|
14
|
-
{
|
46
|
+
static VALUE allocate(VALUE klass) {
|
15
47
|
rubyDuckDBPreparedStatement *ctx = xcalloc((size_t)1, sizeof(rubyDuckDBPreparedStatement));
|
16
48
|
return Data_Wrap_Struct(klass, NULL, deallocate, ctx);
|
17
49
|
}
|
18
50
|
|
19
|
-
static VALUE duckdb_prepared_statement_initialize(VALUE self, VALUE con, VALUE query)
|
20
|
-
{
|
51
|
+
static VALUE duckdb_prepared_statement_initialize(VALUE self, VALUE con, VALUE query) {
|
21
52
|
rubyDuckDBConnection *ctxcon;
|
22
53
|
rubyDuckDBPreparedStatement *ctx;
|
23
54
|
|
@@ -29,26 +60,32 @@ static VALUE duckdb_prepared_statement_initialize(VALUE self, VALUE con, VALUE q
|
|
29
60
|
Data_Get_Struct(con, rubyDuckDBConnection, ctxcon);
|
30
61
|
|
31
62
|
if (duckdb_prepare(ctxcon->con, StringValuePtr(query), &(ctx->prepared_statement)) == DuckDBError) {
|
63
|
+
#ifdef HAVE_DUCKDB_PREPARE_ERROR
|
64
|
+
const char *error = duckdb_prepare_error(ctx->prepared_statement);
|
65
|
+
rb_raise(eDuckDBError, "%s", error);
|
66
|
+
#else
|
32
67
|
/* TODO: include query parameter information in error message. */
|
33
68
|
rb_raise(eDuckDBError, "failed to prepare statement");
|
69
|
+
#endif
|
34
70
|
}
|
35
71
|
return self;
|
36
72
|
}
|
37
73
|
|
38
|
-
static VALUE duckdb_prepared_statement_nparams(VALUE self)
|
39
|
-
{
|
74
|
+
static VALUE duckdb_prepared_statement_nparams(VALUE self) {
|
40
75
|
rubyDuckDBPreparedStatement *ctx;
|
41
76
|
Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
|
42
|
-
|
77
|
+
#ifdef HAVE_DUCKDB_NPARAMS_029
|
78
|
+
return rb_int2big(duckdb_nparams(ctx->prepared_statement));
|
79
|
+
#else
|
43
80
|
if (duckdb_nparams(ctx->prepared_statement, &(ctx->nparams)) == DuckDBError) {
|
44
81
|
rb_raise(eDuckDBError, "failed to get number of parameters");
|
45
82
|
}
|
46
83
|
return rb_int2big(ctx->nparams);
|
84
|
+
#endif
|
47
85
|
}
|
48
86
|
|
49
87
|
|
50
|
-
static VALUE duckdb_prepared_statement_execute(VALUE self)
|
51
|
-
{
|
88
|
+
static VALUE duckdb_prepared_statement_execute(VALUE self) {
|
52
89
|
rubyDuckDBPreparedStatement *ctx;
|
53
90
|
rubyDuckDBResult *ctxr;
|
54
91
|
VALUE result = create_result();
|
@@ -56,13 +93,12 @@ static VALUE duckdb_prepared_statement_execute(VALUE self)
|
|
56
93
|
Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
|
57
94
|
Data_Get_Struct(result, rubyDuckDBResult, ctxr);
|
58
95
|
if (duckdb_execute_prepared(ctx->prepared_statement, &(ctxr->result)) == DuckDBError) {
|
59
|
-
rb_raise(eDuckDBError, "%s", ctxr->result
|
96
|
+
rb_raise(eDuckDBError, "%s", duckdb_result_error(&(ctxr->result)));
|
60
97
|
}
|
61
98
|
return result;
|
62
99
|
}
|
63
100
|
|
64
|
-
static idx_t check_index(VALUE vidx)
|
65
|
-
{
|
101
|
+
static idx_t check_index(VALUE vidx) {
|
66
102
|
idx_t idx = FIX2INT(vidx);
|
67
103
|
if (idx <= 0) {
|
68
104
|
rb_raise(rb_eArgError, "index of parameter must be greater than 0");
|
@@ -70,8 +106,7 @@ static idx_t check_index(VALUE vidx)
|
|
70
106
|
return idx;
|
71
107
|
}
|
72
108
|
|
73
|
-
static VALUE duckdb_prepared_statement_bind_bool(VALUE self, VALUE vidx, VALUE val)
|
74
|
-
{
|
109
|
+
static VALUE duckdb_prepared_statement_bind_bool(VALUE self, VALUE vidx, VALUE val) {
|
75
110
|
rubyDuckDBPreparedStatement *ctx;
|
76
111
|
idx_t idx = check_index(vidx);
|
77
112
|
|
@@ -86,8 +121,7 @@ static VALUE duckdb_prepared_statement_bind_bool(VALUE self, VALUE vidx, VALUE v
|
|
86
121
|
return self;
|
87
122
|
}
|
88
123
|
|
89
|
-
static VALUE duckdb_prepared_statement_bind_int8(VALUE self, VALUE vidx, VALUE val)
|
90
|
-
{
|
124
|
+
static VALUE duckdb_prepared_statement_bind_int8(VALUE self, VALUE vidx, VALUE val) {
|
91
125
|
rubyDuckDBPreparedStatement *ctx;
|
92
126
|
idx_t idx = check_index(vidx);
|
93
127
|
int8_t i8val = (int8_t)NUM2INT(val);
|
@@ -100,8 +134,7 @@ static VALUE duckdb_prepared_statement_bind_int8(VALUE self, VALUE vidx, VALUE v
|
|
100
134
|
return self;
|
101
135
|
}
|
102
136
|
|
103
|
-
static VALUE duckdb_prepared_statement_bind_int16(VALUE self, VALUE vidx, VALUE val)
|
104
|
-
{
|
137
|
+
static VALUE duckdb_prepared_statement_bind_int16(VALUE self, VALUE vidx, VALUE val) {
|
105
138
|
rubyDuckDBPreparedStatement *ctx;
|
106
139
|
idx_t idx = check_index(vidx);
|
107
140
|
int16_t i16val = NUM2INT(val);
|
@@ -114,8 +147,7 @@ static VALUE duckdb_prepared_statement_bind_int16(VALUE self, VALUE vidx, VALUE
|
|
114
147
|
return self;
|
115
148
|
}
|
116
149
|
|
117
|
-
static VALUE duckdb_prepared_statement_bind_int32(VALUE self, VALUE vidx, VALUE val)
|
118
|
-
{
|
150
|
+
static VALUE duckdb_prepared_statement_bind_int32(VALUE self, VALUE vidx, VALUE val) {
|
119
151
|
rubyDuckDBPreparedStatement *ctx;
|
120
152
|
idx_t idx = check_index(vidx);
|
121
153
|
int32_t i32val = NUM2INT(val);
|
@@ -128,8 +160,7 @@ static VALUE duckdb_prepared_statement_bind_int32(VALUE self, VALUE vidx, VALUE
|
|
128
160
|
return self;
|
129
161
|
}
|
130
162
|
|
131
|
-
static VALUE duckdb_prepared_statement_bind_int64(VALUE self, VALUE vidx, VALUE val)
|
132
|
-
{
|
163
|
+
static VALUE duckdb_prepared_statement_bind_int64(VALUE self, VALUE vidx, VALUE val) {
|
133
164
|
rubyDuckDBPreparedStatement *ctx;
|
134
165
|
idx_t idx = check_index(vidx);
|
135
166
|
int64_t i64val = NUM2LL(val);
|
@@ -142,8 +173,7 @@ static VALUE duckdb_prepared_statement_bind_int64(VALUE self, VALUE vidx, VALUE
|
|
142
173
|
return self;
|
143
174
|
}
|
144
175
|
|
145
|
-
static VALUE duckdb_prepared_statement_bind_float(VALUE self, VALUE vidx, VALUE val)
|
146
|
-
{
|
176
|
+
static VALUE duckdb_prepared_statement_bind_float(VALUE self, VALUE vidx, VALUE val) {
|
147
177
|
rubyDuckDBPreparedStatement *ctx;
|
148
178
|
idx_t idx = check_index(vidx);
|
149
179
|
double dbl = NUM2DBL(val);
|
@@ -156,8 +186,7 @@ static VALUE duckdb_prepared_statement_bind_float(VALUE self, VALUE vidx, VALUE
|
|
156
186
|
return self;
|
157
187
|
}
|
158
188
|
|
159
|
-
static VALUE duckdb_prepared_statement_bind_double(VALUE self, VALUE vidx, VALUE val)
|
160
|
-
{
|
189
|
+
static VALUE duckdb_prepared_statement_bind_double(VALUE self, VALUE vidx, VALUE val) {
|
161
190
|
rubyDuckDBPreparedStatement *ctx;
|
162
191
|
idx_t idx = check_index(vidx);
|
163
192
|
double dbl = NUM2DBL(val);
|
@@ -170,8 +199,7 @@ static VALUE duckdb_prepared_statement_bind_double(VALUE self, VALUE vidx, VALUE
|
|
170
199
|
return self;
|
171
200
|
}
|
172
201
|
|
173
|
-
static VALUE duckdb_prepared_statement_bind_varchar(VALUE self, VALUE vidx, VALUE str)
|
174
|
-
{
|
202
|
+
static VALUE duckdb_prepared_statement_bind_varchar(VALUE self, VALUE vidx, VALUE str) {
|
175
203
|
rubyDuckDBPreparedStatement *ctx;
|
176
204
|
idx_t idx = check_index(vidx);
|
177
205
|
|
@@ -182,9 +210,7 @@ static VALUE duckdb_prepared_statement_bind_varchar(VALUE self, VALUE vidx, VALU
|
|
182
210
|
return self;
|
183
211
|
}
|
184
212
|
|
185
|
-
|
186
|
-
static VALUE duckdb_prepared_statement_bind_blob(VALUE self, VALUE vidx, VALUE blob)
|
187
|
-
{
|
213
|
+
static VALUE duckdb_prepared_statement_bind_blob(VALUE self, VALUE vidx, VALUE blob) {
|
188
214
|
rubyDuckDBPreparedStatement *ctx;
|
189
215
|
idx_t idx = check_index(vidx);
|
190
216
|
|
@@ -194,10 +220,8 @@ static VALUE duckdb_prepared_statement_bind_blob(VALUE self, VALUE vidx, VALUE b
|
|
194
220
|
}
|
195
221
|
return self;
|
196
222
|
}
|
197
|
-
#endif /* HAVE_DUCKDB_VALUE_BLOB */
|
198
223
|
|
199
|
-
static VALUE duckdb_prepared_statement_bind_null(VALUE self, VALUE vidx)
|
200
|
-
{
|
224
|
+
static VALUE duckdb_prepared_statement_bind_null(VALUE self, VALUE vidx) {
|
201
225
|
rubyDuckDBPreparedStatement *ctx;
|
202
226
|
idx_t idx = check_index(vidx);
|
203
227
|
|
@@ -208,8 +232,72 @@ static VALUE duckdb_prepared_statement_bind_null(VALUE self, VALUE vidx)
|
|
208
232
|
return self;
|
209
233
|
}
|
210
234
|
|
211
|
-
|
212
|
-
{
|
235
|
+
#ifdef HAVE_DUCKDB_BIND_DATE
|
236
|
+
static VALUE duckdb_prepared_statement__bind_date(VALUE self, VALUE vidx, VALUE year, VALUE month, VALUE day) {
|
237
|
+
rubyDuckDBPreparedStatement *ctx;
|
238
|
+
duckdb_date dt;
|
239
|
+
idx_t idx = check_index(vidx);
|
240
|
+
|
241
|
+
dt = to_duckdb_date_from_value(year, month, day);
|
242
|
+
|
243
|
+
Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
|
244
|
+
if (duckdb_bind_date(ctx->prepared_statement, idx, dt) == DuckDBError) {
|
245
|
+
rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
|
246
|
+
}
|
247
|
+
return self;
|
248
|
+
}
|
249
|
+
#endif
|
250
|
+
|
251
|
+
#ifdef HAVE_DUCKDB_BIND_TIME
|
252
|
+
static VALUE duckdb_prepared_statement__bind_time(VALUE self, VALUE vidx, VALUE hour, VALUE min, VALUE sec, VALUE micros){
|
253
|
+
rubyDuckDBPreparedStatement *ctx;
|
254
|
+
duckdb_time time;
|
255
|
+
|
256
|
+
idx_t idx = check_index(vidx);
|
257
|
+
|
258
|
+
time = to_duckdb_time_from_value(hour, min, sec, micros);
|
259
|
+
|
260
|
+
Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
|
261
|
+
if (duckdb_bind_time(ctx->prepared_statement, idx, time) == DuckDBError) {
|
262
|
+
rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
|
263
|
+
}
|
264
|
+
return self;
|
265
|
+
}
|
266
|
+
#endif
|
267
|
+
|
268
|
+
#ifdef HAVE_DUCKDB_BIND_TIMESTAMP
|
269
|
+
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) {
|
270
|
+
duckdb_timestamp timestamp;
|
271
|
+
rubyDuckDBPreparedStatement *ctx;
|
272
|
+
idx_t idx = check_index(vidx);
|
273
|
+
|
274
|
+
timestamp = to_duckdb_timestamp_from_value(year, month, day, hour, min, sec, micros);
|
275
|
+
Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
|
276
|
+
|
277
|
+
if (duckdb_bind_timestamp(ctx->prepared_statement, idx, timestamp) == DuckDBError) {
|
278
|
+
rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
|
279
|
+
}
|
280
|
+
return self;
|
281
|
+
}
|
282
|
+
#endif
|
283
|
+
|
284
|
+
#ifdef HAVE_DUCKDB_BIND_INTERVAL
|
285
|
+
static VALUE duckdb_prepared_statement__bind_interval(VALUE self, VALUE vidx, VALUE months, VALUE days, VALUE micros) {
|
286
|
+
duckdb_interval interval;
|
287
|
+
rubyDuckDBPreparedStatement *ctx;
|
288
|
+
idx_t idx = check_index(vidx);
|
289
|
+
|
290
|
+
Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
|
291
|
+
to_duckdb_interval_from_value(&interval, months, days, micros);
|
292
|
+
|
293
|
+
if (duckdb_bind_interval(ctx->prepared_statement, idx, interval) == DuckDBError) {
|
294
|
+
rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
|
295
|
+
}
|
296
|
+
return self;
|
297
|
+
}
|
298
|
+
#endif
|
299
|
+
|
300
|
+
void init_duckdb_prepared_statement(void) {
|
213
301
|
cDuckDBPreparedStatement = rb_define_class_under(mDuckDB, "PreparedStatement", rb_cObject);
|
214
302
|
|
215
303
|
rb_define_alloc_func(cDuckDBPreparedStatement, allocate);
|
@@ -225,8 +313,16 @@ void init_duckdb_prepared_statement(void)
|
|
225
313
|
rb_define_method(cDuckDBPreparedStatement, "bind_float", duckdb_prepared_statement_bind_float, 2);
|
226
314
|
rb_define_method(cDuckDBPreparedStatement, "bind_double", duckdb_prepared_statement_bind_double, 2);
|
227
315
|
rb_define_method(cDuckDBPreparedStatement, "bind_varchar", duckdb_prepared_statement_bind_varchar, 2);
|
228
|
-
#ifdef HAVE_DUCKDB_VALUE_BLOB
|
229
316
|
rb_define_method(cDuckDBPreparedStatement, "bind_blob", duckdb_prepared_statement_bind_blob, 2);
|
230
|
-
#endif /* HAVE_DUCKDB_VALUE_BLOB */
|
231
317
|
rb_define_method(cDuckDBPreparedStatement, "bind_null", duckdb_prepared_statement_bind_null, 1);
|
318
|
+
rb_define_private_method(cDuckDBPreparedStatement, "_bind_date", duckdb_prepared_statement__bind_date, 4);
|
319
|
+
#ifdef HAVE_DUCKDB_BIND_TIME
|
320
|
+
rb_define_private_method(cDuckDBPreparedStatement, "_bind_time", duckdb_prepared_statement__bind_time, 5);
|
321
|
+
#endif
|
322
|
+
#ifdef HAVE_DUCKDB_BIND_TIMESTAMP
|
323
|
+
rb_define_private_method(cDuckDBPreparedStatement, "_bind_timestamp", duckdb_prepared_statement__bind_timestamp, 8);
|
324
|
+
#endif
|
325
|
+
#ifdef HAVE_DUCKDB_BIND_INTERVAL
|
326
|
+
rb_define_private_method(cDuckDBPreparedStatement, "_bind_interval", duckdb_prepared_statement__bind_interval, 4);
|
327
|
+
#endif
|
232
328
|
}
|
data/ext/duckdb/result.c
CHANGED
@@ -2,59 +2,64 @@
|
|
2
2
|
|
3
3
|
static VALUE cDuckDBResult;
|
4
4
|
|
5
|
-
static void deallocate(void *ctx)
|
6
|
-
|
5
|
+
static void deallocate(void *ctx);
|
6
|
+
static VALUE allocate(VALUE klass);
|
7
|
+
static VALUE to_ruby_obj_boolean(duckdb_result *result, idx_t col_idx, idx_t row_idx);
|
8
|
+
static VALUE to_ruby_obj_smallint(duckdb_result *result, idx_t col_idx, idx_t row_idx);
|
9
|
+
static VALUE to_ruby_obj_integer(duckdb_result *result, idx_t col_idx, idx_t row_idx);
|
10
|
+
static VALUE to_ruby_obj_bigint(duckdb_result *result, idx_t col_idx, idx_t row_idx);
|
11
|
+
static VALUE to_ruby_obj_float(duckdb_result *result, idx_t col_idx, idx_t row_idx);
|
12
|
+
static VALUE to_ruby_obj_double(duckdb_result *result, idx_t col_idx, idx_t row_idx);
|
13
|
+
static VALUE to_ruby_obj_string_from_blob(duckdb_result *result, idx_t col_idx, idx_t row_idx);
|
14
|
+
static VALUE to_ruby_obj(duckdb_result *result, idx_t col_idx, idx_t row_idx);
|
15
|
+
static VALUE row_array(rubyDuckDBResult *ctx, idx_t row_idx);
|
16
|
+
static VALUE duckdb_result_row_size(VALUE oDuckDBResult, VALUE args, VALUE obj);
|
17
|
+
static VALUE duckdb_result_each(VALUE oDuckDBResult);
|
18
|
+
static VALUE duckdb_result_rows_changed(VALUE oDuckDBResult);
|
19
|
+
|
20
|
+
static void deallocate(void *ctx) {
|
7
21
|
rubyDuckDBResult *p = (rubyDuckDBResult *)ctx;
|
8
22
|
|
9
23
|
duckdb_destroy_result(&(p->result));
|
10
24
|
xfree(p);
|
11
25
|
}
|
12
26
|
|
13
|
-
static VALUE allocate(VALUE klass)
|
14
|
-
{
|
27
|
+
static VALUE allocate(VALUE klass) {
|
15
28
|
rubyDuckDBResult *ctx = xcalloc((size_t)1, sizeof(rubyDuckDBResult));
|
16
29
|
return Data_Wrap_Struct(klass, NULL, deallocate, ctx);
|
17
30
|
}
|
18
31
|
|
19
|
-
static VALUE to_ruby_obj_boolean(duckdb_result *result, idx_t col_idx, idx_t row_idx)
|
20
|
-
{
|
32
|
+
static VALUE to_ruby_obj_boolean(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
|
21
33
|
bool bval = duckdb_value_boolean(result, col_idx, row_idx);
|
22
34
|
return bval ? Qtrue : Qnil;
|
23
35
|
}
|
24
36
|
|
25
|
-
static VALUE to_ruby_obj_smallint(duckdb_result *result, idx_t col_idx, idx_t row_idx)
|
26
|
-
{
|
37
|
+
static VALUE to_ruby_obj_smallint(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
|
27
38
|
int16_t i16val = duckdb_value_int16(result, col_idx, row_idx);
|
28
39
|
return INT2FIX(i16val);
|
29
40
|
}
|
30
41
|
|
31
|
-
static VALUE to_ruby_obj_integer(duckdb_result *result, idx_t col_idx, idx_t row_idx)
|
32
|
-
{
|
42
|
+
static VALUE to_ruby_obj_integer(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
|
33
43
|
int32_t i32val = duckdb_value_int32(result, col_idx, row_idx);
|
34
44
|
return INT2NUM(i32val);
|
35
45
|
}
|
36
46
|
|
37
|
-
static VALUE to_ruby_obj_bigint(duckdb_result *result, idx_t col_idx, idx_t row_idx)
|
38
|
-
{
|
47
|
+
static VALUE to_ruby_obj_bigint(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
|
39
48
|
int64_t i64val = duckdb_value_int64(result, col_idx, row_idx);
|
40
49
|
return rb_int2big(i64val);
|
41
50
|
}
|
42
51
|
|
43
|
-
static VALUE to_ruby_obj_float(duckdb_result *result, idx_t col_idx, idx_t row_idx)
|
44
|
-
{
|
52
|
+
static VALUE to_ruby_obj_float(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
|
45
53
|
float fval = duckdb_value_float(result, col_idx, row_idx);
|
46
54
|
return DBL2NUM(fval);
|
47
55
|
}
|
48
56
|
|
49
|
-
static VALUE to_ruby_obj_double(duckdb_result *result, idx_t col_idx, idx_t row_idx)
|
50
|
-
{
|
57
|
+
static VALUE to_ruby_obj_double(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
|
51
58
|
double dval = duckdb_value_double(result, col_idx, row_idx);
|
52
59
|
return DBL2NUM(dval);
|
53
60
|
}
|
54
61
|
|
55
|
-
|
56
|
-
static VALUE to_ruby_obj_string_from_blob(duckdb_result *result, idx_t col_idx, idx_t row_idx)
|
57
|
-
{
|
62
|
+
static VALUE to_ruby_obj_string_from_blob(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
|
58
63
|
VALUE str;
|
59
64
|
duckdb_blob bval = duckdb_value_blob(result, col_idx, row_idx);
|
60
65
|
str = rb_str_new(bval.data, bval.size);
|
@@ -69,16 +74,14 @@ static VALUE to_ruby_obj_string_from_blob(duckdb_result *result, idx_t col_idx,
|
|
69
74
|
|
70
75
|
return str;
|
71
76
|
}
|
72
|
-
#endif /* HAVE_DUCKDB_VALUE_BLOB */
|
73
77
|
|
74
|
-
static VALUE to_ruby_obj(duckdb_result *result, idx_t col_idx, idx_t row_idx)
|
75
|
-
{
|
78
|
+
static VALUE to_ruby_obj(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
|
76
79
|
char *p;
|
77
80
|
VALUE obj = Qnil;
|
78
|
-
if (result
|
81
|
+
if (duckdb_value_is_null(result, col_idx, row_idx)) {
|
79
82
|
return obj;
|
80
83
|
}
|
81
|
-
switch(result
|
84
|
+
switch(duckdb_column_type(result, col_idx)) {
|
82
85
|
case DUCKDB_TYPE_BOOLEAN:
|
83
86
|
return to_ruby_obj_boolean(result, col_idx, row_idx);
|
84
87
|
case DUCKDB_TYPE_SMALLINT:
|
@@ -91,10 +94,8 @@ static VALUE to_ruby_obj(duckdb_result *result, idx_t col_idx, idx_t row_idx)
|
|
91
94
|
return to_ruby_obj_float(result, col_idx, row_idx);
|
92
95
|
case DUCKDB_TYPE_DOUBLE:
|
93
96
|
return to_ruby_obj_double(result, col_idx, row_idx);
|
94
|
-
#ifdef HAVE_DUCKDB_VALUE_BLOB
|
95
97
|
case DUCKDB_TYPE_BLOB:
|
96
98
|
return to_ruby_obj_string_from_blob(result, col_idx, row_idx);
|
97
|
-
#endif /* HAVE_DUCKDB_VALUE_BLOB */
|
98
99
|
default:
|
99
100
|
p = duckdb_value_varchar(result, col_idx, row_idx);
|
100
101
|
if (p) {
|
@@ -104,7 +105,7 @@ static VALUE to_ruby_obj(duckdb_result *result, idx_t col_idx, idx_t row_idx)
|
|
104
105
|
#else
|
105
106
|
free(p);
|
106
107
|
#endif /* HAVE_DUCKDB_FREE */
|
107
|
-
if (result
|
108
|
+
if (duckdb_column_type(result, col_idx) == DUCKDB_TYPE_HUGEINT) {
|
108
109
|
obj = rb_funcall(obj, rb_intern("to_i"), 0);
|
109
110
|
}
|
110
111
|
}
|
@@ -112,47 +113,75 @@ static VALUE to_ruby_obj(duckdb_result *result, idx_t col_idx, idx_t row_idx)
|
|
112
113
|
return obj;
|
113
114
|
}
|
114
115
|
|
115
|
-
static VALUE row_array(rubyDuckDBResult *ctx, idx_t row_idx)
|
116
|
-
{
|
116
|
+
static VALUE row_array(rubyDuckDBResult *ctx, idx_t row_idx) {
|
117
117
|
idx_t col_idx;
|
118
|
-
|
119
|
-
|
118
|
+
idx_t column_count = duckdb_column_count(&(ctx->result));
|
119
|
+
|
120
|
+
VALUE ary = rb_ary_new2(column_count);
|
121
|
+
for(col_idx = 0; col_idx < column_count; col_idx++) {
|
120
122
|
rb_ary_store(ary, col_idx, to_ruby_obj(&(ctx->result), col_idx, row_idx));
|
121
123
|
}
|
122
124
|
return ary;
|
123
125
|
}
|
124
126
|
|
125
|
-
static VALUE duckdb_result_row_size(VALUE oDuckDBResult, VALUE args, VALUE obj)
|
126
|
-
{
|
127
|
+
static VALUE duckdb_result_row_size(VALUE oDuckDBResult, VALUE args, VALUE obj) {
|
127
128
|
rubyDuckDBResult *ctx;
|
128
129
|
Data_Get_Struct(oDuckDBResult, rubyDuckDBResult, ctx);
|
129
130
|
|
130
|
-
return LONG2FIX(ctx->result
|
131
|
+
return LONG2FIX(duckdb_row_count(&(ctx->result)));
|
131
132
|
}
|
132
133
|
|
133
|
-
static VALUE duckdb_result_each(VALUE oDuckDBResult)
|
134
|
-
{
|
134
|
+
static VALUE duckdb_result_each(VALUE oDuckDBResult) {
|
135
135
|
rubyDuckDBResult *ctx;
|
136
136
|
idx_t row_idx = 0;
|
137
|
+
idx_t row_count = 0;
|
137
138
|
|
138
139
|
RETURN_SIZED_ENUMERATOR(oDuckDBResult, 0, 0, duckdb_result_row_size);
|
139
140
|
|
140
141
|
Data_Get_Struct(oDuckDBResult, rubyDuckDBResult, ctx);
|
141
|
-
|
142
|
+
row_count = duckdb_row_count(&(ctx->result));
|
143
|
+
for (row_idx = 0; row_idx < row_count; row_idx++) {
|
142
144
|
rb_yield(row_array(ctx, row_idx));
|
143
145
|
}
|
144
146
|
return oDuckDBResult;
|
145
147
|
}
|
146
148
|
|
147
|
-
|
148
|
-
|
149
|
+
/*
|
150
|
+
* call-seq:
|
151
|
+
* result.rows_changed -> integer
|
152
|
+
*
|
153
|
+
* Returns the count of rows changed.
|
154
|
+
*
|
155
|
+
* DuckDB::Database.open do |db|
|
156
|
+
* db.connect do |con|
|
157
|
+
* r = con.query('CREATE TABLE t2 (id INT)')
|
158
|
+
* r.rows_changed # => 0
|
159
|
+
* r = con.query('INSERT INTO t2 VALUES (1), (2), (3)')
|
160
|
+
* r.rows_changed # => 3
|
161
|
+
* r = con.query('UPDATE t2 SET id = id + 1 WHERE id > 1')
|
162
|
+
* r.rows_changed # => 2
|
163
|
+
* r = con.query('DELETE FROM t2 WHERE id = 0')
|
164
|
+
* r.rows_changed # => 0
|
165
|
+
* r = con.query('DELETE FROM t2 WHERE id = 4')
|
166
|
+
* r.rows_changed # => 1
|
167
|
+
* end
|
168
|
+
* end
|
169
|
+
*
|
170
|
+
*/
|
171
|
+
static VALUE duckdb_result_rows_changed(VALUE oDuckDBResult) {
|
172
|
+
rubyDuckDBResult *ctx;
|
173
|
+
Data_Get_Struct(oDuckDBResult, rubyDuckDBResult, ctx);
|
174
|
+
return LL2NUM(duckdb_rows_changed(&(ctx->result)));
|
175
|
+
}
|
176
|
+
|
177
|
+
VALUE create_result(void) {
|
149
178
|
return allocate(cDuckDBResult);
|
150
179
|
}
|
151
180
|
|
152
|
-
void init_duckdb_result(void)
|
153
|
-
{
|
181
|
+
void init_duckdb_result(void) {
|
154
182
|
cDuckDBResult = rb_define_class_under(mDuckDB, "Result", rb_cObject);
|
155
183
|
rb_define_alloc_func(cDuckDBResult, allocate);
|
156
184
|
|
157
185
|
rb_define_method(cDuckDBResult, "each", duckdb_result_each, 0);
|
186
|
+
rb_define_method(cDuckDBResult, "rows_changed", duckdb_result_rows_changed, 0);
|
158
187
|
}
|