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 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