duckdb 0.2.8.0 → 0.3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
}
|