duckdb 1.1.1.0 → 1.1.2.1
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 +2 -2
- data/.github/workflows/test_on_ubuntu.yml +2 -2
- data/.github/workflows/test_on_windows.yml +1 -1
- data/.gitignore +1 -0
- data/CHANGELOG.md +22 -1
- data/CONTRIBUTION.md +1 -1
- data/Dockerfile +1 -1
- data/Gemfile +1 -1
- data/Gemfile.lock +1 -1
- data/ext/duckdb/extracted_statements.c +14 -2
- data/ext/duckdb/prepared_statement.c +53 -4
- data/lib/duckdb/appender.rb +30 -22
- data/lib/duckdb/connection.rb +37 -12
- data/lib/duckdb/extracted_statements.rb +20 -0
- data/lib/duckdb/prepared_statement.rb +25 -0
- data/lib/duckdb/version.rb +1 -1
- data/lib/duckdb.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f326104e9d96a1fce6a508d481101c37eca2b12a421eb2ddb07acb838f14c118
|
4
|
+
data.tar.gz: 999db21104bb772564ecb41bbc2fee06d728f65618bb8538d14bc20c22173424
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6cb7f30f39a2b768d1d6441e324f2c86f910f7af2cff9ca403b91eeb13cacbc0bee56dc54d3786f58e27af9276ae91d4a2ce22c705727b0c8ef5cd3251ab83fe
|
7
|
+
data.tar.gz: f17ea13a5aca9640e17e8983a37f9ba88e6ace381d5ad7e979232b0158028b92aa07ddea758ffdd9868511fb2b868354f7f15c20d6c14fb4f2e537613f8ee670
|
@@ -15,8 +15,8 @@ jobs:
|
|
15
15
|
runs-on: macos-latest
|
16
16
|
strategy:
|
17
17
|
matrix:
|
18
|
-
ruby: ['3.1.6', '3.2.5', '3.3.5', '3.4.0-
|
19
|
-
duckdb: ['1.1.
|
18
|
+
ruby: ['3.1.6', '3.2.5', '3.3.5', '3.4.0-preview2', 'head']
|
19
|
+
duckdb: ['1.1.2', '1.1.1', '1.0.0']
|
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.1.6', '3.2.5', '3.3.5', '3.4.0-
|
19
|
-
duckdb: ['1.1.
|
18
|
+
ruby: ['3.1.6', '3.2.5', '3.3.5', '3.4.0-preview2', 'head']
|
19
|
+
duckdb: ['1.1.2', '1.1.1', '1.0.0']
|
20
20
|
|
21
21
|
steps:
|
22
22
|
- uses: actions/checkout@v4
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -3,8 +3,29 @@
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
# Unreleased
|
5
5
|
|
6
|
+
# 1.1.2.1 - 2024-11-04
|
7
|
+
- `DuckDB::Connection#query` accepts multiple SQL statement.
|
8
|
+
- When multiple SQL statements are given, `DuckDB::Connection#query` returns the last statement result.
|
9
|
+
- `DuckDB::Connection#query` does not support multiple SQL statements with bind parameters. If you pass 2 or more argument,
|
10
|
+
`DuckDB::Connection#query` will regard first argument as only one SQL statement and the rest as bind parameters.
|
11
|
+
- add `DuckDB::ExtracteStatements#each` method.
|
12
|
+
- add `DuckDB::ExtracteStatementsImpl#destroy` method.
|
13
|
+
- add `DuckDB::PreparedStatement#prepare`.
|
14
|
+
- `DuckDB::Connection#prepared_statement` accepts block and calls `PreparedStatement#destroy` after block executed.
|
15
|
+
```ruby
|
16
|
+
con.prepared_statement('SELECT * FROM table WHERE id = ?') do |stmt|
|
17
|
+
stmt.bind(1)
|
18
|
+
stmt.execute
|
19
|
+
end
|
20
|
+
```
|
21
|
+
# 1.1.2.0 - 2024-10-20
|
22
|
+
- bump duckdb to 1.1.2.
|
23
|
+
- add `DuckDB::PreparedStatement#destroy`.
|
24
|
+
- `DuckDB::Connection#query`, `DuckDB::Connection#async_query`, `DuckDB::Connection#async_query_stream` call
|
25
|
+
`DuckDB::PreparedStatement#destroy` to free the prepared statement immediately (#775, #781).
|
26
|
+
|
6
27
|
# 1.1.1.0 - 2024-10-06
|
7
|
-
- bump duckdb 1.1.1.
|
28
|
+
- bump duckdb to 1.1.1.
|
8
29
|
## Breaking changes
|
9
30
|
- drop duckdb v0.10.x.
|
10
31
|
|
data/CONTRIBUTION.md
CHANGED
@@ -14,7 +14,7 @@ docker compose run --rm ubuntu bash
|
|
14
14
|
|
15
15
|
In case you want custom ruby or duckdb versions, use `--build-arg` options
|
16
16
|
```
|
17
|
-
docker
|
17
|
+
docker compose build ubuntu --build-arg RUBY_VERSION=3.1.3 --build-arg DUCKDB_VERSION=1.0.0
|
18
18
|
```
|
19
19
|
|
20
20
|
### Without docker
|
data/Dockerfile
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -17,6 +17,7 @@ static VALUE allocate(VALUE klass);
|
|
17
17
|
static size_t memsize(const void *p);
|
18
18
|
|
19
19
|
static VALUE duckdb_extracted_statements_initialize(VALUE self, VALUE con, VALUE query);
|
20
|
+
static VALUE duckdb_extracted_statements_destroy(VALUE self);
|
20
21
|
static VALUE duckdb_extracted_statements_size(VALUE self);
|
21
22
|
static VALUE duckdb_extracted_statements_prepared_statement(VALUE self, VALUE con, VALUE index);
|
22
23
|
|
@@ -56,12 +57,22 @@ static VALUE duckdb_extracted_statements_initialize(VALUE self, VALUE con, VALUE
|
|
56
57
|
|
57
58
|
if (ctx->num_statements == 0) {
|
58
59
|
error = duckdb_extract_statements_error(ctx->extracted_statements);
|
59
|
-
rb_raise(eDuckDBError, "%s", error);
|
60
|
+
rb_raise(eDuckDBError, "%s", error ? error : "Failed to extract statements(Database connection closed?).");
|
60
61
|
}
|
61
62
|
|
62
63
|
return self;
|
63
64
|
}
|
64
65
|
|
66
|
+
static VALUE duckdb_extracted_statements_destroy(VALUE self) {
|
67
|
+
rubyDuckDBExtractedStatements *ctx;
|
68
|
+
|
69
|
+
TypedData_Get_Struct(self, rubyDuckDBExtractedStatements, &extract_statements_data_type, ctx);
|
70
|
+
|
71
|
+
duckdb_destroy_extracted(&(ctx->extracted_statements));
|
72
|
+
|
73
|
+
return Qnil;
|
74
|
+
}
|
75
|
+
|
65
76
|
static VALUE duckdb_extracted_statements_size(VALUE self) {
|
66
77
|
rubyDuckDBExtractedStatements *ctx;
|
67
78
|
|
@@ -85,10 +96,11 @@ static VALUE duckdb_extracted_statements_prepared_statement(VALUE self, VALUE co
|
|
85
96
|
}
|
86
97
|
|
87
98
|
void rbduckdb_init_duckdb_extracted_statements(void) {
|
88
|
-
cDuckDBExtractedStatements = rb_define_class_under(mDuckDB, "
|
99
|
+
cDuckDBExtractedStatements = rb_define_class_under(mDuckDB, "ExtractedStatementsImpl", rb_cObject);
|
89
100
|
|
90
101
|
rb_define_alloc_func(cDuckDBExtractedStatements, allocate);
|
91
102
|
rb_define_method(cDuckDBExtractedStatements, "initialize", duckdb_extracted_statements_initialize, 2);
|
103
|
+
rb_define_method(cDuckDBExtractedStatements, "destroy", duckdb_extracted_statements_destroy, 0);
|
92
104
|
rb_define_method(cDuckDBExtractedStatements, "size", duckdb_extracted_statements_size, 0);
|
93
105
|
rb_define_method(cDuckDBExtractedStatements, "prepared_statement", duckdb_extracted_statements_prepared_statement, 2);
|
94
106
|
}
|
@@ -2,12 +2,14 @@
|
|
2
2
|
|
3
3
|
VALUE cDuckDBPreparedStatement;
|
4
4
|
|
5
|
+
static void destroy_prepared_statement(rubyDuckDBPreparedStatement *p);
|
5
6
|
static void deallocate(void *ctx);
|
6
7
|
static VALUE allocate(VALUE klass);
|
7
8
|
static size_t memsize(const void *p);
|
8
9
|
static VALUE duckdb_prepared_statement_initialize(VALUE self, VALUE con, VALUE query);
|
9
10
|
static VALUE duckdb_prepared_statement_nparams(VALUE self);
|
10
11
|
static VALUE duckdb_prepared_statement_execute(VALUE self);
|
12
|
+
static VALUE duckdb_prepared_statement_destroy(VALUE self);
|
11
13
|
static idx_t check_index(VALUE vidx);
|
12
14
|
|
13
15
|
static VALUE duckdb_prepared_statement_bind_parameter_index(VALUE self, VALUE name);
|
@@ -30,6 +32,7 @@ static VALUE duckdb_prepared_statement__bind_time(VALUE self, VALUE vidx, VALUE
|
|
30
32
|
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);
|
31
33
|
static VALUE duckdb_prepared_statement__bind_interval(VALUE self, VALUE vidx, VALUE months, VALUE days, VALUE micros);
|
32
34
|
static VALUE duckdb_prepared_statement__bind_hugeint(VALUE self, VALUE vidx, VALUE lower, VALUE upper);
|
35
|
+
static VALUE duckdb_prepared_statement__bind_decimal(VALUE self, VALUE vidx, VALUE lower, VALUE upper, VALUE width, VALUE scale);
|
33
36
|
|
34
37
|
static const rb_data_type_t prepared_statement_data_type = {
|
35
38
|
"DuckDB/PreparedStatement",
|
@@ -37,10 +40,17 @@ static const rb_data_type_t prepared_statement_data_type = {
|
|
37
40
|
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
38
41
|
};
|
39
42
|
|
43
|
+
static void destroy_prepared_statement(rubyDuckDBPreparedStatement *p) {
|
44
|
+
if (p->prepared_statement) {
|
45
|
+
duckdb_destroy_prepare(&(p->prepared_statement));
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
40
49
|
static void deallocate(void *ctx) {
|
41
50
|
rubyDuckDBPreparedStatement *p = (rubyDuckDBPreparedStatement *)ctx;
|
42
51
|
|
43
|
-
|
52
|
+
destroy_prepared_statement(p);
|
53
|
+
// duckdb_destroy_prepare(&(p->prepared_statement));
|
44
54
|
xfree(p);
|
45
55
|
}
|
46
56
|
|
@@ -62,7 +72,7 @@ VALUE rbduckdb_prepared_statement_new(duckdb_connection con, duckdb_extracted_st
|
|
62
72
|
TypedData_Get_Struct(obj, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
|
63
73
|
|
64
74
|
if (duckdb_prepare_extracted_statement(con, extracted_statements, index, &(ctx->prepared_statement)) == DuckDBError) {
|
65
|
-
rb_raise(eDuckDBError, "
|
75
|
+
rb_raise(eDuckDBError, "Failed to create DuckDB::PreparedStatement object.");
|
66
76
|
}
|
67
77
|
return obj;
|
68
78
|
}
|
@@ -91,20 +101,37 @@ static VALUE duckdb_prepared_statement_nparams(VALUE self) {
|
|
91
101
|
return ULL2NUM(duckdb_nparams(ctx->prepared_statement));
|
92
102
|
}
|
93
103
|
|
94
|
-
|
95
104
|
static VALUE duckdb_prepared_statement_execute(VALUE self) {
|
96
105
|
rubyDuckDBPreparedStatement *ctx;
|
97
106
|
rubyDuckDBResult *ctxr;
|
98
107
|
VALUE result = rbduckdb_create_result();
|
108
|
+
const char *p = NULL;
|
99
109
|
|
100
110
|
TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
|
101
111
|
ctxr = get_struct_result(result);
|
102
112
|
if (duckdb_execute_prepared(ctx->prepared_statement, &(ctxr->result)) == DuckDBError) {
|
103
|
-
|
113
|
+
p = duckdb_result_error(&(ctxr->result));
|
114
|
+
if (p == NULL) {
|
115
|
+
p = duckdb_prepare_error(ctx->prepared_statement);
|
116
|
+
}
|
117
|
+
rb_raise(eDuckDBError, "%s", p ? p : "Failed to execute prepared statement.");
|
104
118
|
}
|
105
119
|
return result;
|
106
120
|
}
|
107
121
|
|
122
|
+
/*
|
123
|
+
* :nodoc:
|
124
|
+
*/
|
125
|
+
static VALUE duckdb_prepared_statement_destroy(VALUE self) {
|
126
|
+
rubyDuckDBPreparedStatement *ctx;
|
127
|
+
TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
|
128
|
+
destroy_prepared_statement(ctx);
|
129
|
+
/*
|
130
|
+
ctx->prepared_statement = NULL;
|
131
|
+
*/
|
132
|
+
return Qnil;
|
133
|
+
}
|
134
|
+
|
108
135
|
static idx_t check_index(VALUE vidx) {
|
109
136
|
idx_t idx = NUM2ULL(vidx);
|
110
137
|
if (idx <= 0) {
|
@@ -378,6 +405,26 @@ static VALUE duckdb_prepared_statement__bind_hugeint(VALUE self, VALUE vidx, VAL
|
|
378
405
|
return self;
|
379
406
|
}
|
380
407
|
|
408
|
+
static VALUE duckdb_prepared_statement__bind_decimal(VALUE self, VALUE vidx, VALUE lower, VALUE upper, VALUE width, VALUE scale) {
|
409
|
+
duckdb_hugeint hugeint;
|
410
|
+
duckdb_decimal decimal;
|
411
|
+
rubyDuckDBPreparedStatement *ctx;
|
412
|
+
idx_t idx = check_index(vidx);
|
413
|
+
|
414
|
+
TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
|
415
|
+
hugeint.lower = NUM2ULL(lower);
|
416
|
+
hugeint.upper = NUM2LL(upper);
|
417
|
+
decimal.value = hugeint;
|
418
|
+
decimal.width = (uint8_t)NUM2UINT(width);
|
419
|
+
decimal.scale = (uint8_t)NUM2UINT(scale);
|
420
|
+
|
421
|
+
if (duckdb_bind_decimal(ctx->prepared_statement, idx, decimal) == DuckDBError) {
|
422
|
+
rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
|
423
|
+
}
|
424
|
+
|
425
|
+
return self;
|
426
|
+
}
|
427
|
+
|
381
428
|
rubyDuckDBPreparedStatement *get_struct_prepared_statement(VALUE self) {
|
382
429
|
rubyDuckDBPreparedStatement *ctx;
|
383
430
|
TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
|
@@ -391,6 +438,7 @@ void rbduckdb_init_duckdb_prepared_statement(void) {
|
|
391
438
|
|
392
439
|
rb_define_method(cDuckDBPreparedStatement, "initialize", duckdb_prepared_statement_initialize, 2);
|
393
440
|
rb_define_method(cDuckDBPreparedStatement, "execute", duckdb_prepared_statement_execute, 0);
|
441
|
+
rb_define_method(cDuckDBPreparedStatement, "destroy", duckdb_prepared_statement_destroy, 0);
|
394
442
|
rb_define_method(cDuckDBPreparedStatement, "nparams", duckdb_prepared_statement_nparams, 0);
|
395
443
|
rb_define_method(cDuckDBPreparedStatement, "bind_parameter_index", duckdb_prepared_statement_bind_parameter_index, 1);
|
396
444
|
rb_define_method(cDuckDBPreparedStatement, "parameter_name", duckdb_prepared_statement_parameter_name, 1);
|
@@ -412,4 +460,5 @@ void rbduckdb_init_duckdb_prepared_statement(void) {
|
|
412
460
|
rb_define_private_method(cDuckDBPreparedStatement, "_bind_timestamp", duckdb_prepared_statement__bind_timestamp, 8);
|
413
461
|
rb_define_private_method(cDuckDBPreparedStatement, "_bind_interval", duckdb_prepared_statement__bind_interval, 4);
|
414
462
|
rb_define_private_method(cDuckDBPreparedStatement, "_bind_hugeint", duckdb_prepared_statement__bind_hugeint, 3);
|
463
|
+
rb_define_private_method(cDuckDBPreparedStatement, "_bind_decimal", duckdb_prepared_statement__bind_decimal, 5);
|
415
464
|
}
|
data/lib/duckdb/appender.rb
CHANGED
@@ -74,16 +74,7 @@ module DuckDB
|
|
74
74
|
# appender.flush
|
75
75
|
#
|
76
76
|
def append_date(value)
|
77
|
-
date =
|
78
|
-
when Date, Time
|
79
|
-
value
|
80
|
-
else
|
81
|
-
begin
|
82
|
-
Date.parse(value)
|
83
|
-
rescue
|
84
|
-
raise(ArgumentError, "Cannot parse argument `#{value}` to Date.")
|
85
|
-
end
|
86
|
-
end
|
77
|
+
date = to_date(value)
|
87
78
|
|
88
79
|
_append_date(date.year, date.month, date.day)
|
89
80
|
end
|
@@ -126,18 +117,7 @@ module DuckDB
|
|
126
117
|
# appender.flush
|
127
118
|
#
|
128
119
|
def append_timestamp(value)
|
129
|
-
time =
|
130
|
-
when Time
|
131
|
-
value
|
132
|
-
when Date
|
133
|
-
value.to_time
|
134
|
-
else
|
135
|
-
begin
|
136
|
-
Time.parse(value)
|
137
|
-
rescue
|
138
|
-
raise(ArgumentError, "Cannot parse argument `#{value}` to Time or Date.")
|
139
|
-
end
|
140
|
-
end
|
120
|
+
time = to_time(value)
|
141
121
|
|
142
122
|
_append_timestamp(time.year, time.month, time.day, time.hour, time.min, time.sec, time.nsec / 1000)
|
143
123
|
end
|
@@ -233,5 +213,33 @@ module DuckDB
|
|
233
213
|
def blob?(value)
|
234
214
|
value.instance_of?(DuckDB::Blob) || value.encoding == Encoding::BINARY
|
235
215
|
end
|
216
|
+
|
217
|
+
def to_date(value)
|
218
|
+
case value
|
219
|
+
when Date, Time
|
220
|
+
value
|
221
|
+
else
|
222
|
+
begin
|
223
|
+
Date.parse(value)
|
224
|
+
rescue StandardError
|
225
|
+
raise(ArgumentError, "Cannot parse argument `#{value}` to Date.")
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def to_time(value)
|
231
|
+
case value
|
232
|
+
when Time
|
233
|
+
value
|
234
|
+
when Date
|
235
|
+
value.to_time
|
236
|
+
else
|
237
|
+
begin
|
238
|
+
Time.parse(value)
|
239
|
+
rescue StandardError
|
240
|
+
raise(ArgumentError, "Cannot parse argument `#{value}` to Time or Date.")
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
236
244
|
end
|
237
245
|
end
|
data/lib/duckdb/connection.rb
CHANGED
@@ -26,11 +26,23 @@ module DuckDB
|
|
26
26
|
# dave = con.query(sql, name: 'Dave', email: 'dave@example.com')
|
27
27
|
#
|
28
28
|
def query(sql, *args, **kwargs)
|
29
|
-
return
|
29
|
+
return query_multi_sql(sql) if args.empty? && kwargs.empty?
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
31
|
+
prepare(sql) do |stmt|
|
32
|
+
stmt.bind_args(*args, **kwargs)
|
33
|
+
stmt.execute
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def query_multi_sql(sql)
|
38
|
+
stmts = ExtractedStatements.new(self, sql)
|
39
|
+
result = nil
|
40
|
+
stmts.each do |stmt|
|
41
|
+
result = stmt.execute
|
42
|
+
end
|
43
|
+
result
|
44
|
+
ensure
|
45
|
+
stmts&.destroy
|
34
46
|
end
|
35
47
|
|
36
48
|
#
|
@@ -50,9 +62,10 @@ module DuckDB
|
|
50
62
|
# result.each.first
|
51
63
|
#
|
52
64
|
def async_query(sql, *args, **kwargs)
|
53
|
-
|
54
|
-
|
55
|
-
|
65
|
+
prepare(sql) do |stmt|
|
66
|
+
stmt.bind_args(*args, **kwargs)
|
67
|
+
stmt.pending_prepared
|
68
|
+
end
|
56
69
|
end
|
57
70
|
|
58
71
|
#
|
@@ -73,9 +86,10 @@ module DuckDB
|
|
73
86
|
# result.each.first
|
74
87
|
#
|
75
88
|
def async_query_stream(sql, *args, **kwargs)
|
76
|
-
|
77
|
-
|
78
|
-
|
89
|
+
prepare(sql) do |stmt|
|
90
|
+
stmt.bind_args(*args, **kwargs)
|
91
|
+
stmt.pending_prepared_stream
|
92
|
+
end
|
79
93
|
end
|
80
94
|
|
81
95
|
#
|
@@ -96,6 +110,8 @@ module DuckDB
|
|
96
110
|
#
|
97
111
|
# returns PreparedStatement object.
|
98
112
|
# The first argument is SQL string.
|
113
|
+
# If block is given, the block is executed with PreparedStatement object
|
114
|
+
# and the object is cleaned up immediately.
|
99
115
|
#
|
100
116
|
# require 'duckdb'
|
101
117
|
# db = DuckDB::Database.open('duckdb_file')
|
@@ -105,8 +121,17 @@ module DuckDB
|
|
105
121
|
# stmt = con.prepared_statement(sql)
|
106
122
|
# stmt.bind_args(name: 'Dave', email: 'dave@example.com')
|
107
123
|
# result = stmt.execute
|
108
|
-
|
109
|
-
|
124
|
+
#
|
125
|
+
# # or
|
126
|
+
# result = con.prepared_statement(sql) do |stmt|
|
127
|
+
# stmt.bind_args(name: 'Dave', email: 'dave@example.com')
|
128
|
+
# stmt.execute
|
129
|
+
# end
|
130
|
+
#
|
131
|
+
def prepared_statement(str, &)
|
132
|
+
return PreparedStatement.new(self, str) unless block_given?
|
133
|
+
|
134
|
+
PreparedStatement.prepare(self, str, &)
|
110
135
|
end
|
111
136
|
|
112
137
|
#
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DuckDB
|
4
|
+
class ExtractedStatements < ExtractedStatementsImpl
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
def initialize(con, sql)
|
8
|
+
@con = con
|
9
|
+
super(con, sql)
|
10
|
+
end
|
11
|
+
|
12
|
+
def each
|
13
|
+
return to_enum(__method__) { size } unless block_given?
|
14
|
+
|
15
|
+
size.times do |i|
|
16
|
+
yield prepared_statement(@con, i)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -22,6 +22,31 @@ module DuckDB
|
|
22
22
|
RANGE_INT32 = -2_147_483_648..2_147_483_647
|
23
23
|
RANGE_INT64 = -9_223_372_036_854_775_808..9_223_372_036_854_775_807
|
24
24
|
|
25
|
+
class << self
|
26
|
+
# return DuckDB::PreparedStatement object.
|
27
|
+
# The first argument is DuckDB::Connection object.
|
28
|
+
# The second argument is SQL string.
|
29
|
+
# If block is given, the block is executed and the statement is destroyed.
|
30
|
+
#
|
31
|
+
# require 'duckdb'
|
32
|
+
# db = DuckDB::Database.open('duckdb_database')
|
33
|
+
# con = db.connection
|
34
|
+
# DuckDB::PreparedStatement.prepare(con, 'SELECT * FROM users WHERE id = ?') do |stmt|
|
35
|
+
# stmt.bind(1, 1)
|
36
|
+
# stmt.execute
|
37
|
+
# end
|
38
|
+
def prepare(con, sql)
|
39
|
+
stmt = new(con, sql)
|
40
|
+
return stmt unless block_given?
|
41
|
+
|
42
|
+
begin
|
43
|
+
yield stmt
|
44
|
+
ensure
|
45
|
+
stmt.destroy
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
25
50
|
def pending_prepared
|
26
51
|
PendingResult.new(self)
|
27
52
|
end
|
data/lib/duckdb/version.rb
CHANGED
data/lib/duckdb.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: duckdb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.1
|
4
|
+
version: 1.1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Masaki Suketa
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-11-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bigdecimal
|
@@ -149,6 +149,7 @@ files:
|
|
149
149
|
- lib/duckdb/converter.rb
|
150
150
|
- lib/duckdb/converter/int_to_sym.rb
|
151
151
|
- lib/duckdb/database.rb
|
152
|
+
- lib/duckdb/extracted_statements.rb
|
152
153
|
- lib/duckdb/infinity.rb
|
153
154
|
- lib/duckdb/interval.rb
|
154
155
|
- lib/duckdb/library_version.rb
|