duckdb 1.1.1.0 → 1.1.2.1
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 +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
|