duckdb 0.9.0 → 0.9.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/CHANGELOG.md +8 -0
- data/Dockerfile +1 -1
- data/Gemfile.lock +1 -1
- data/README.md +11 -0
- data/ext/duckdb/extconf.rb +2 -0
- data/ext/duckdb/prepared_statement.c +49 -0
- data/lib/duckdb/connection.rb +12 -5
- data/lib/duckdb/prepared_statement.rb +32 -12
- data/lib/duckdb/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2948812978266d6ca2040d2071479f0484fe39719be860282e238b1e786a53e7
|
4
|
+
data.tar.gz: 3a3d10a5dd8e318b7a6274e6e32f0fc4850eeafada95673b42ed6c6121a36af5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f4bf27bf6c3e378650584e9226bd0c2e16a76a2d5e68c96451f5abafb4dfe6fbb4df705ceb754ac8df30ed36bc6fe67299f61861fa882ef11acac79dea1e80cf
|
7
|
+
data.tar.gz: 71f42787f8368ab322c5d8c9a9a74227117dbf0454601d9ac3ec407188497c34e437fd5de14bec2038d6f3df3233098b580a8e116f8590dedd8004b7ba934f5a
|
@@ -15,8 +15,8 @@ jobs:
|
|
15
15
|
runs-on: macos-latest
|
16
16
|
strategy:
|
17
17
|
matrix:
|
18
|
-
ruby: ['2.7.8', '3.0.6', '3.1.4', '3.2.2', '3.3.0-
|
19
|
-
duckdb: ['0.9.
|
18
|
+
ruby: ['2.7.8', '3.0.6', '3.1.4', '3.2.2', '3.3.0-preview2', 'head']
|
19
|
+
duckdb: ['0.9.1', '0.8.1']
|
20
20
|
|
21
21
|
steps:
|
22
22
|
- uses: actions/checkout@v3
|
@@ -15,8 +15,8 @@ jobs:
|
|
15
15
|
runs-on: ubuntu-latest
|
16
16
|
strategy:
|
17
17
|
matrix:
|
18
|
-
ruby: ['2.7.8', '3.0.6', '3.1.4', '3.2.2', '3.3.0-
|
19
|
-
duckdb: ['0.9.
|
18
|
+
ruby: ['2.7.8', '3.0.6', '3.1.4', '3.2.2', '3.3.0-preview2', 'head']
|
19
|
+
duckdb: ['0.9.1', '0.8.1']
|
20
20
|
|
21
21
|
steps:
|
22
22
|
- uses: actions/checkout@v3
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# ChangeLog
|
2
2
|
|
3
|
+
# 0.9.1
|
4
|
+
- add `DuckDB::PreparedStatement#parameter_name`.
|
5
|
+
- bump duckdb to 0.9.1.
|
6
|
+
|
7
|
+
# 0.9.0.1
|
8
|
+
- add `DuckDB::PreparedStatement#bind_parameter_index`.
|
9
|
+
- DuckDB::Connection#query accepts SQL with named bind parameters.
|
10
|
+
|
3
11
|
# 0.9.0
|
4
12
|
- bump duckdb to 0.9.0.
|
5
13
|
|
data/Dockerfile
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -94,6 +94,17 @@ DuckDB::Database.open do |db|
|
|
94
94
|
end
|
95
95
|
```
|
96
96
|
|
97
|
+
### using bind variables
|
98
|
+
|
99
|
+
You can use bind variables.
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
con.query('SELECT * FROM users WHERE name = ? AND email = ?', 'Alice', 'alice@example.com')
|
103
|
+
# or
|
104
|
+
con.query('SELECT * FROM users WHERE name = $name AND email = $email', name: 'Alice', email: 'alice@example.com')
|
105
|
+
```
|
106
|
+
|
107
|
+
|
97
108
|
### using BLOB column
|
98
109
|
|
99
110
|
BLOB is available with DuckDB v0.2.5 or later.
|
data/ext/duckdb/extconf.rb
CHANGED
@@ -9,6 +9,14 @@ static VALUE duckdb_prepared_statement_initialize(VALUE self, VALUE con, VALUE q
|
|
9
9
|
static VALUE duckdb_prepared_statement_nparams(VALUE self);
|
10
10
|
static VALUE duckdb_prepared_statement_execute(VALUE self);
|
11
11
|
static idx_t check_index(VALUE vidx);
|
12
|
+
|
13
|
+
#ifdef HAVE_DUCKDB_H_GE_V090
|
14
|
+
static VALUE duckdb_prepared_statement_bind_parameter_index(VALUE self, VALUE name);
|
15
|
+
#ifdef HAVE_DUCKDB_PARAMETER_NAME
|
16
|
+
static VALUE duckdb_prepared_statement_parameter_name(VALUE self, VALUE vidx);
|
17
|
+
#endif
|
18
|
+
#endif
|
19
|
+
|
12
20
|
static VALUE duckdb_prepared_statement_bind_bool(VALUE self, VALUE vidx, VALUE val);
|
13
21
|
static VALUE duckdb_prepared_statement_bind_int8(VALUE self, VALUE vidx, VALUE val);
|
14
22
|
static VALUE duckdb_prepared_statement_bind_int16(VALUE self, VALUE vidx, VALUE val);
|
@@ -93,6 +101,39 @@ static idx_t check_index(VALUE vidx) {
|
|
93
101
|
return idx;
|
94
102
|
}
|
95
103
|
|
104
|
+
#ifdef HAVE_DUCKDB_H_GE_V090
|
105
|
+
static VALUE duckdb_prepared_statement_bind_parameter_index(VALUE self, VALUE name) {
|
106
|
+
rubyDuckDBPreparedStatement *ctx;
|
107
|
+
idx_t idx;
|
108
|
+
|
109
|
+
TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
|
110
|
+
|
111
|
+
if (duckdb_bind_parameter_index(ctx->prepared_statement, &idx, StringValuePtr(name)) == DuckDBError) {;
|
112
|
+
rb_raise(rb_eArgError, "parameter '%s' not found", StringValuePtr(name));
|
113
|
+
}
|
114
|
+
return ULL2NUM(idx);
|
115
|
+
}
|
116
|
+
|
117
|
+
#ifdef HAVE_DUCKDB_PARAMETER_NAME
|
118
|
+
static VALUE duckdb_prepared_statement_parameter_name(VALUE self, VALUE vidx) {
|
119
|
+
rubyDuckDBPreparedStatement *ctx;
|
120
|
+
VALUE vname;
|
121
|
+
const char *name;
|
122
|
+
idx_t idx = check_index(vidx);
|
123
|
+
|
124
|
+
TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
|
125
|
+
|
126
|
+
name = duckdb_parameter_name(ctx->prepared_statement, idx);
|
127
|
+
if (name == NULL) {
|
128
|
+
rb_raise(eDuckDBError, "fail to get name of %llu parameter", (unsigned long long)idx);
|
129
|
+
}
|
130
|
+
vname = rb_str_new2(name);
|
131
|
+
duckdb_free((void *)name);
|
132
|
+
return vname;
|
133
|
+
}
|
134
|
+
#endif /* HAVE_DUCKDB_PARAMETER_NAME */
|
135
|
+
#endif /* HAVE_DUCKDB_H_GE_V090 */
|
136
|
+
|
96
137
|
static VALUE duckdb_prepared_statement_bind_bool(VALUE self, VALUE vidx, VALUE val) {
|
97
138
|
rubyDuckDBPreparedStatement *ctx;
|
98
139
|
idx_t idx = check_index(vidx);
|
@@ -308,6 +349,14 @@ void init_duckdb_prepared_statement(void) {
|
|
308
349
|
rb_define_method(cDuckDBPreparedStatement, "initialize", duckdb_prepared_statement_initialize, 2);
|
309
350
|
rb_define_method(cDuckDBPreparedStatement, "execute", duckdb_prepared_statement_execute, 0);
|
310
351
|
rb_define_method(cDuckDBPreparedStatement, "nparams", duckdb_prepared_statement_nparams, 0);
|
352
|
+
|
353
|
+
#ifdef HAVE_DUCKDB_H_GE_V090
|
354
|
+
rb_define_method(cDuckDBPreparedStatement, "bind_parameter_index", duckdb_prepared_statement_bind_parameter_index, 1);
|
355
|
+
#ifdef HAVE_DUCKDB_PARAMETER_NAME
|
356
|
+
rb_define_method(cDuckDBPreparedStatement, "parameter_name", duckdb_prepared_statement_parameter_name, 1);
|
357
|
+
#endif
|
358
|
+
#endif
|
359
|
+
|
311
360
|
rb_define_method(cDuckDBPreparedStatement, "bind_bool", duckdb_prepared_statement_bind_bool, 2);
|
312
361
|
rb_define_method(cDuckDBPreparedStatement, "bind_int8", duckdb_prepared_statement_bind_int8, 2);
|
313
362
|
rb_define_method(cDuckDBPreparedStatement, "bind_int16", duckdb_prepared_statement_bind_int16, 2);
|
data/lib/duckdb/connection.rb
CHANGED
@@ -12,7 +12,6 @@ module DuckDB
|
|
12
12
|
# executes sql with args.
|
13
13
|
# The first argument sql must be SQL string.
|
14
14
|
# The rest arguments are parameters of SQL string.
|
15
|
-
# The parameters must be '?' in SQL statement.
|
16
15
|
#
|
17
16
|
# require 'duckdb'
|
18
17
|
# db = DuckDB::Database.open('duckdb_file')
|
@@ -21,12 +20,20 @@ module DuckDB
|
|
21
20
|
# sql = 'SELECT * FROM users WHERE name = ? AND email = ?'
|
22
21
|
# dave = con.query(sql, 'Dave', 'dave@example.com')
|
23
22
|
#
|
24
|
-
|
25
|
-
|
23
|
+
# # or You can use named parameter.
|
24
|
+
#
|
25
|
+
# sql = 'SELECT * FROM users WHERE name = $name AND email = $email'
|
26
|
+
# dave = con.query(sql, name: 'Dave', email: 'dave@example.com')
|
27
|
+
#
|
28
|
+
def query(sql, *args, **hash)
|
29
|
+
return query_sql(sql) if args.empty? && hash.empty?
|
26
30
|
|
27
31
|
stmt = PreparedStatement.new(self, sql)
|
28
|
-
args.
|
29
|
-
stmt.bind(i
|
32
|
+
args.each.with_index(1) do |arg, i|
|
33
|
+
stmt.bind(i, arg)
|
34
|
+
end
|
35
|
+
hash.each do |key, value|
|
36
|
+
stmt.bind(key, value)
|
30
37
|
end
|
31
38
|
stmt.execute
|
32
39
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'date'
|
2
2
|
require 'bigdecimal'
|
3
|
-
require_relative '
|
3
|
+
require_relative 'converter'
|
4
4
|
|
5
5
|
module DuckDB
|
6
6
|
# The DuckDB::PreparedStatement encapsulates connection with DuckDB prepared
|
@@ -167,35 +167,55 @@ module DuckDB
|
|
167
167
|
# sql ='SELECT name, email FROM users WHERE email = ?'
|
168
168
|
# stmt = PreparedStatement.new(con, sql)
|
169
169
|
# stmt.bind(1, 'email@example.com')
|
170
|
-
def bind(
|
170
|
+
def bind(index, value)
|
171
|
+
case index
|
172
|
+
when Integer
|
173
|
+
bind_with_index(index, value)
|
174
|
+
when String
|
175
|
+
bind_with_name(index, value)
|
176
|
+
when Symbol
|
177
|
+
bind_with_name(index.to_s, value)
|
178
|
+
else
|
179
|
+
raise(ArgumentError, "1st argument `#{index}` must be Integer or String or Symbol.")
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
private
|
184
|
+
|
185
|
+
def bind_with_index(index, value)
|
171
186
|
case value
|
172
187
|
when NilClass
|
173
|
-
bind_null(
|
188
|
+
bind_null(index)
|
174
189
|
when Float
|
175
|
-
bind_double(
|
190
|
+
bind_double(index, value)
|
176
191
|
when Integer
|
177
192
|
case value
|
178
193
|
when RANGE_INT64
|
179
|
-
bind_int64(
|
194
|
+
bind_int64(index, value)
|
180
195
|
else
|
181
|
-
bind_varchar(
|
196
|
+
bind_varchar(index, value.to_s)
|
182
197
|
end
|
183
198
|
when String
|
184
|
-
blob?(value) ? bind_blob(
|
199
|
+
blob?(value) ? bind_blob(index, value) : bind_varchar(index, value)
|
185
200
|
when TrueClass, FalseClass
|
186
|
-
bind_bool(
|
201
|
+
bind_bool(index, value)
|
187
202
|
when Time
|
188
|
-
bind_varchar(
|
203
|
+
bind_varchar(index, value.strftime('%Y-%m-%d %H:%M:%S.%N'))
|
189
204
|
when Date
|
190
|
-
bind_varchar(
|
205
|
+
bind_varchar(index, value.strftime('%Y-%m-%d'))
|
191
206
|
when BigDecimal
|
192
|
-
bind_varchar(
|
207
|
+
bind_varchar(index, value.to_s('F'))
|
193
208
|
else
|
194
209
|
raise(DuckDB::Error, "not supported type `#{value}` (#{value.class})")
|
195
210
|
end
|
196
211
|
end
|
197
212
|
|
198
|
-
|
213
|
+
def bind_with_name(name, value)
|
214
|
+
raise DuckDB::Error, 'not supported binding with name' unless respond_to?(:bind_parameter_index)
|
215
|
+
|
216
|
+
i = bind_parameter_index(name)
|
217
|
+
bind_with_index(i, value)
|
218
|
+
end
|
199
219
|
|
200
220
|
def blob?(value)
|
201
221
|
value.instance_of?(DuckDB::Blob) || value.encoding == Encoding::BINARY
|
data/lib/duckdb/version.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: 0.9.
|
4
|
+
version: 0.9.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: 2023-
|
11
|
+
date: 2023-10-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|