duckdb 0.9.0 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f7738df010c1fb1aab32b61077ff9409566cfaddecfef3b27aa6e7ee7a8651f2
4
- data.tar.gz: 6357f43da56b7c4fbea72ec7b3c549f598f3a91b88c1c91ab5320a01606f3589
3
+ metadata.gz: 2948812978266d6ca2040d2071479f0484fe39719be860282e238b1e786a53e7
4
+ data.tar.gz: 3a3d10a5dd8e318b7a6274e6e32f0fc4850eeafada95673b42ed6c6121a36af5
5
5
  SHA512:
6
- metadata.gz: e417badc1b301fdea9f3f4b27648e7e1c7d8e125a0a1323bb69e93a992467eca0a57a320b0bb14f7fda45bf8d9d3706b59eb586a71e3c9f77bd2ec18c88b8b3a
7
- data.tar.gz: b1486d0d525fa93a8485504eac95015a07ac064a4dfb15bb0689aa7be4cb41edcf03436324e822bda26a8c3c6e8a9e2a690efcd49f7180f675777f75284df5e8
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-preview1', 'head']
19
- duckdb: ['0.9.0', '0.8.1']
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-preview1', 'head']
19
- duckdb: ['0.9.0', '0.8.1']
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
@@ -16,7 +16,7 @@ jobs:
16
16
  strategy:
17
17
  matrix:
18
18
  ruby: ['2.7.8', '3.0.6', '3.1.4', '3.2.2', 'ucrt', 'mingw', 'mswin', 'head']
19
- duckdb: ['0.9.0', '0.8.1']
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
@@ -1,7 +1,7 @@
1
1
  ARG RUBY_VERSION=3.2.2
2
2
  FROM ruby:${RUBY_VERSION}
3
3
 
4
- ARG DUCKDB_VERSION=0.9.0
4
+ ARG DUCKDB_VERSION=0.9.1
5
5
 
6
6
  RUN apt update -qq && \
7
7
  apt install -y build-essential curl git wget
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- duckdb (0.9.0)
4
+ duckdb (0.9.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
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.
@@ -31,4 +31,6 @@ have_func('duckdb_string_is_inlined', 'duckdb.h')
31
31
  # check duckdb >= 0.9.0
32
32
  have_func('duckdb_bind_parameter_index', 'duckdb.h')
33
33
 
34
+ have_func('duckdb_parameter_name', 'duckdb.h')
35
+
34
36
  create_makefile('duckdb/duckdb_native')
@@ -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);
@@ -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
- def query(sql, *args)
25
- return query_sql(sql) if args.empty?
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.each_with_index do |arg, i|
29
- stmt.bind(i + 1, arg)
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 './converter'
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(i, value)
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(i)
188
+ bind_null(index)
174
189
  when Float
175
- bind_double(i, value)
190
+ bind_double(index, value)
176
191
  when Integer
177
192
  case value
178
193
  when RANGE_INT64
179
- bind_int64(i, value)
194
+ bind_int64(index, value)
180
195
  else
181
- bind_varchar(i, value.to_s)
196
+ bind_varchar(index, value.to_s)
182
197
  end
183
198
  when String
184
- blob?(value) ? bind_blob(i, value) : bind_varchar(i, value)
199
+ blob?(value) ? bind_blob(index, value) : bind_varchar(index, value)
185
200
  when TrueClass, FalseClass
186
- bind_bool(i, value)
201
+ bind_bool(index, value)
187
202
  when Time
188
- bind_varchar(i, value.strftime('%Y-%m-%d %H:%M:%S.%N'))
203
+ bind_varchar(index, value.strftime('%Y-%m-%d %H:%M:%S.%N'))
189
204
  when Date
190
- bind_varchar(i, value.strftime('%Y-%m-%d'))
205
+ bind_varchar(index, value.strftime('%Y-%m-%d'))
191
206
  when BigDecimal
192
- bind_varchar(i, value.to_s('F'))
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
- private
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
@@ -3,5 +3,5 @@
3
3
  module DuckDB
4
4
  # The version string of ruby-duckdb.
5
5
  # Currently, ruby-duckdb is NOT semantic versioning.
6
- VERSION = '0.9.0'
6
+ VERSION = '0.9.1'
7
7
  end
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.0
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-09-29 00:00:00.000000000 Z
11
+ date: 2023-10-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler