duckdb 1.1.2.1 → 1.1.3.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: f326104e9d96a1fce6a508d481101c37eca2b12a421eb2ddb07acb838f14c118
4
- data.tar.gz: 999db21104bb772564ecb41bbc2fee06d728f65618bb8538d14bc20c22173424
3
+ metadata.gz: 97d0a0fdf67bcfdd00102540f9dd675e1fe87176e349ef06db6f1c72f78b5219
4
+ data.tar.gz: da34340b078ae95c6b9fa7ddb872de4be16f3bc298169004761d532a9f378f20
5
5
  SHA512:
6
- metadata.gz: 6cb7f30f39a2b768d1d6441e324f2c86f910f7af2cff9ca403b91eeb13cacbc0bee56dc54d3786f58e27af9276ae91d4a2ce22c705727b0c8ef5cd3251ab83fe
7
- data.tar.gz: f17ea13a5aca9640e17e8983a37f9ba88e6ace381d5ad7e979232b0158028b92aa07ddea758ffdd9868511fb2b868354f7f15c20d6c14fb4f2e537613f8ee670
6
+ metadata.gz: 924d05547e0f9bf6f4772db3a93085930cd48961a0eee92d114815ea8286cd4ad6d1454764ffd97caa0cc6be103a2b084d1f402e98a973dc529b674754b4cfd7
7
+ data.tar.gz: 022f30d9b659b487f109d91b7d9818a26bb6d0a7fffd62fc8ae0375453688b3981b652fcb00826a826f15503ee119ca73830fe251329d51235d46ffa6c17ff50
@@ -15,8 +15,9 @@ 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-preview2', 'head']
19
- duckdb: ['1.1.2', '1.1.1', '1.0.0']
18
+ # ruby: ['3.1.6', '3.2.6', '3.3.6', '3.4.0-preview2', 'head']
19
+ ruby: ['3.1.6', '3.2.6', '3.3.6', '3.4.0-preview2']
20
+ duckdb: ['1.1.3', '1.1.1', '1.0.0']
20
21
 
21
22
  steps:
22
23
  - 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-preview2', 'head']
19
- duckdb: ['1.1.2', '1.1.1', '1.0.0']
18
+ ruby: ['3.1.6', '3.2.6', '3.3.6', '3.4.0-preview2', 'head']
19
+ duckdb: ['1.1.3', '1.1.1', '1.0.0']
20
20
 
21
21
  steps:
22
22
  - uses: actions/checkout@v4
@@ -16,7 +16,7 @@ jobs:
16
16
  strategy:
17
17
  matrix:
18
18
  ruby: ['3.1.6', '3.2.5', '3.3.5', 'ucrt', 'mingw', 'mswin', 'head']
19
- duckdb: ['1.1.2', '1.1.1', '1.0.0']
19
+ duckdb: ['1.1.3', '1.1.1', '1.0.0']
20
20
 
21
21
  steps:
22
22
  - uses: actions/checkout@v4
data/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
  # Unreleased
5
+ # 1.1.3.1 - 2024-11-27
6
+ - fix to `DuckDB::Connection#query` with multiple SQL statements. Calling PreparedStatement#destroy after each statement executed.
7
+ - install valgrind in docker development environment.
8
+ - add `DuckDB::Appender#append_default`.
9
+
10
+ # 1.1.3.0 - 2024-11-10
11
+ - add `DuckDB::PreparedStatement#bind_decimal`. (Thanks to @otegami)
12
+ - bump duckdb to 1.1.3.
5
13
 
6
14
  # 1.1.2.1 - 2024-11-04
7
15
  - `DuckDB::Connection#query` accepts multiple SQL statement.
data/Dockerfile CHANGED
@@ -1,21 +1,32 @@
1
- ARG RUBY_VERSION=3.3.5
1
+ ARG RUBY_VERSION=3.3.6
2
2
  FROM ruby:${RUBY_VERSION}
3
3
 
4
- ARG DUCKDB_VERSION=1.1.2
4
+ ARG DUCKDB_VERSION=1.1.3
5
+ ARG VALGRIND_VERSION=3.21.0
5
6
 
6
7
  RUN apt update -qq && \
7
- apt install -y build-essential curl git wget
8
+ apt install -y build-essential curl git wget libc6-dbg
8
9
 
9
10
  COPY getduckdb.sh .
10
11
  RUN ./getduckdb.sh
11
12
 
12
- RUN unzip duckdb.zip -d libduckdb
13
- RUN mv libduckdb/duckdb.* /usr/local/include
14
- RUN mv libduckdb/libduckdb.so /usr/local/lib
15
- RUN ldconfig /usr/local/lib
13
+ RUN unzip duckdb.zip -d libduckdb && \
14
+ mv libduckdb/duckdb.* /usr/local/include && \
15
+ mv libduckdb/libduckdb.so /usr/local/lib && \
16
+ ldconfig /usr/local/lib
17
+
18
+ RUN mkdir valgrind-tmp && \
19
+ cd valgrind-tmp && \
20
+ wget https://sourceware.org/pub/valgrind/valgrind-${VALGRIND_VERSION}.tar.bz2 && \
21
+ tar xf valgrind-${VALGRIND_VERSION}.tar.bz2 && \
22
+ cd valgrind-${VALGRIND_VERSION} && \
23
+ ./configure && \
24
+ make -s && \
25
+ make -s install && \
26
+ cd .. && \
27
+ rm -rf /valgrind-tmp
16
28
 
17
29
  COPY . /root/ruby-duckdb
18
30
  WORKDIR /root/ruby-duckdb
19
31
  RUN git config --global --add safe.directory /root/ruby-duckdb
20
- RUN bundle install
21
- RUN rake build
32
+ RUN bundle install && rake build
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- duckdb (1.1.2.1)
4
+ duckdb (1.1.3.1)
5
5
  bigdecimal (>= 3.1.4)
6
6
 
7
7
  GEM
@@ -9,10 +9,16 @@ GEM
9
9
  specs:
10
10
  benchmark-ips (2.14.0)
11
11
  bigdecimal (3.1.8)
12
- mini_portile2 (2.8.7)
13
- minitest (5.25.1)
14
- nokogiri (1.16.7)
15
- mini_portile2 (~> 2.8.2)
12
+ minitest (5.25.2)
13
+ nokogiri (1.16.7-aarch64-linux)
14
+ racc (~> 1.4)
15
+ nokogiri (1.16.7-arm-linux)
16
+ racc (~> 1.4)
17
+ nokogiri (1.16.7-arm64-darwin)
18
+ racc (~> 1.4)
19
+ nokogiri (1.16.7-x86-linux)
20
+ racc (~> 1.4)
21
+ nokogiri (1.16.7-x86_64-darwin)
16
22
  racc (~> 1.4)
17
23
  nokogiri (1.16.7-x86_64-linux)
18
24
  racc (~> 1.4)
@@ -25,7 +31,11 @@ GEM
25
31
  stackprof (0.2.26)
26
32
 
27
33
  PLATFORMS
28
- ruby
34
+ aarch64-linux
35
+ arm-linux
36
+ arm64-darwin
37
+ x86-linux
38
+ x86_64-darwin
29
39
  x86_64-linux
30
40
 
31
41
  DEPENDENCIES
@@ -39,4 +49,4 @@ DEPENDENCIES
39
49
  stackprof
40
50
 
41
51
  BUNDLED WITH
42
- 2.5.9
52
+ 2.5.22
data/README.md CHANGED
@@ -46,7 +46,7 @@ brew install duckdb
46
46
 
47
47
  Using [Ruby + Devkit](https://rubyinstaller.org/downloads/) is recommended.
48
48
 
49
- 1. Download libduckdb-windows-amd64.zip from [DuckDB](https://github.com/duckdb/duckdb/releases) and extranct it.
49
+ 1. Download libduckdb-windows-amd64.zip from [DuckDB](https://github.com/duckdb/duckdb/releases) and extract it.
50
50
  2. Copy `duckdb.dll` into `C:\Windows\System32`
51
51
 
52
52
  ## How to install
@@ -115,7 +115,7 @@ con.query('SELECT * FROM users WHERE name = $name AND email = $email', name: 'Al
115
115
  ```
116
116
  ### Using prepared statement
117
117
 
118
- You can use prepared statement.
118
+ You can use prepared statement. Prepared statement object is created by `Connection#prepare` method or `DuckDB::PreparedStatement.new`.
119
119
 
120
120
  ```ruby
121
121
  stmt = con.prepare('SELECT * FROM users WHERE name = $name AND email = $email')
@@ -125,7 +125,20 @@ stmt = con.prepare('SELECT * FROM users WHERE name = $name AND email = $email')
125
125
  # stmt = DuckDB::PreparedStatement.new(con, 'SELECT * FROM users WHERE name = $name AND email = $email')
126
126
  stmt.bind(name: 'Alice', email: 'alice@example.com')
127
127
  result = stmt.execute
128
+ stmt.destroy
128
129
  ```
130
+ You must call `PreparedStatement#destroy` method after using prepared statement. Otherwise, automatically destroyed
131
+ when the PreparedStatement object is garbage collected.
132
+
133
+ Instead of calling `PreparedStatement#destroy`, you can use block.
134
+
135
+ ```ruby
136
+ result = con.prepare('SELECT * FROM users WHERE name = $name AND email = $email') do |stmt|
137
+ stmt.bind(name: 'Alice', email: 'alice@example.com')
138
+ stmt.execute
139
+ end
140
+ ```
141
+
129
142
  ### Using async query
130
143
 
131
144
  You can use async query.
@@ -23,6 +23,11 @@ static VALUE appender_append_varchar(VALUE self, VALUE val);
23
23
  static VALUE appender_append_varchar_length(VALUE self, VALUE val, VALUE len);
24
24
  static VALUE appender_append_blob(VALUE self, VALUE val);
25
25
  static VALUE appender_append_null(VALUE self);
26
+
27
+ #ifdef HAVE_DUCKDB_H_GE_V1_1_0
28
+ static VALUE appender_append_default(VALUE self);
29
+ #endif
30
+
26
31
  static VALUE appender__append_date(VALUE self, VALUE yearval, VALUE monthval, VALUE dayval);
27
32
  static VALUE appender__append_interval(VALUE self, VALUE months, VALUE days, VALUE micros);
28
33
  static VALUE appender__append_time(VALUE self, VALUE hour, VALUE min, VALUE sec, VALUE micros);
@@ -281,6 +286,18 @@ static VALUE appender_append_null(VALUE self) {
281
286
  return self;
282
287
  }
283
288
 
289
+ #ifdef HAVE_DUCKDB_H_GE_V1_1_0
290
+ static VALUE appender_append_default(VALUE self) {
291
+ rubyDuckDBAppender *ctx;
292
+ TypedData_Get_Struct(self, rubyDuckDBAppender, &appender_data_type, ctx);
293
+
294
+ if (duckdb_append_default(ctx->appender) == DuckDBError) {
295
+ rb_raise(eDuckDBError, "failed to append");
296
+ }
297
+ return self;
298
+ }
299
+ #endif
300
+
284
301
  static VALUE appender__append_date(VALUE self, VALUE year, VALUE month, VALUE day) {
285
302
  duckdb_date dt;
286
303
  rubyDuckDBAppender *ctx;
@@ -406,6 +423,11 @@ void rbduckdb_init_duckdb_appender(void) {
406
423
  rb_define_method(cDuckDBAppender, "append_varchar_length", appender_append_varchar_length, 2);
407
424
  rb_define_method(cDuckDBAppender, "append_blob", appender_append_blob, 1);
408
425
  rb_define_method(cDuckDBAppender, "append_null", appender_append_null, 0);
426
+
427
+ #ifdef HAVE_DUCKDB_H_GE_V1_1_0
428
+ rb_define_method(cDuckDBAppender, "append_default", appender_append_default, 0);
429
+ #endif
430
+
409
431
  rb_define_private_method(cDuckDBAppender, "_append_date", appender__append_date, 3);
410
432
  rb_define_private_method(cDuckDBAppender, "_append_interval", appender__append_interval, 3);
411
433
  rb_define_private_method(cDuckDBAppender, "_append_time", appender__append_time, 4);
@@ -81,7 +81,6 @@ static VALUE duckdb_extracted_statements_size(VALUE self) {
81
81
  return ULL2NUM(ctx->num_statements);
82
82
  }
83
83
 
84
-
85
84
  static VALUE duckdb_extracted_statements_prepared_statement(VALUE self, VALUE con, VALUE index) {
86
85
  rubyDuckDBConnection *pcon;
87
86
  rubyDuckDBExtractedStatements *ctx;
@@ -72,7 +72,8 @@ VALUE rbduckdb_prepared_statement_new(duckdb_connection con, duckdb_extracted_st
72
72
  TypedData_Get_Struct(obj, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
73
73
 
74
74
  if (duckdb_prepare_extracted_statement(con, extracted_statements, index, &(ctx->prepared_statement)) == DuckDBError) {
75
- rb_raise(eDuckDBError, "Failed to create DuckDB::PreparedStatement object.");
75
+ const char *error = duckdb_prepare_error(ctx->prepared_statement);
76
+ rb_raise(eDuckDBError, "%s", error ? error : "Failed to create DuckDB::PreparedStatement object.");
76
77
  }
77
78
  return obj;
78
79
  }
@@ -90,7 +91,7 @@ static VALUE duckdb_prepared_statement_initialize(VALUE self, VALUE con, VALUE q
90
91
 
91
92
  if (duckdb_prepare(ctxcon->con, StringValuePtr(query), &(ctx->prepared_statement)) == DuckDBError) {
92
93
  const char *error = duckdb_prepare_error(ctx->prepared_statement);
93
- rb_raise(eDuckDBError, "%s", error);
94
+ rb_raise(eDuckDBError, "%s", error ? error : "Failed to prepare statement(Database connection closed?).");
94
95
  }
95
96
  return self;
96
97
  }
@@ -8,7 +8,6 @@ module DuckDB
8
8
  # con = db.connect
9
9
  # con.query(sql)
10
10
  class Connection
11
- #
12
11
  # executes sql with args.
13
12
  # The first argument sql must be SQL string.
14
13
  # The rest arguments are parameters of SQL string.
@@ -24,7 +23,6 @@ module DuckDB
24
23
  #
25
24
  # sql = 'SELECT * FROM users WHERE name = $name AND email = $email'
26
25
  # dave = con.query(sql, name: 'Dave', email: 'dave@example.com')
27
- #
28
26
  def query(sql, *args, **kwargs)
29
27
  return query_multi_sql(sql) if args.empty? && kwargs.empty?
30
28
 
@@ -39,13 +37,13 @@ module DuckDB
39
37
  result = nil
40
38
  stmts.each do |stmt|
41
39
  result = stmt.execute
40
+ stmt.destroy
42
41
  end
43
42
  result
44
43
  ensure
45
44
  stmts&.destroy
46
45
  end
47
46
 
48
- #
49
47
  # executes sql with args asynchronously.
50
48
  # The first argument sql must be SQL string.
51
49
  # The rest arguments are parameters of SQL string.
@@ -60,7 +58,6 @@ module DuckDB
60
58
  # pending_result.execute_task while pending_result.state == :not_ready
61
59
  # result = pending_result.execute_pending
62
60
  # result.each.first
63
- #
64
61
  def async_query(sql, *args, **kwargs)
65
62
  prepare(sql) do |stmt|
66
63
  stmt.bind_args(*args, **kwargs)
@@ -68,7 +65,6 @@ module DuckDB
68
65
  end
69
66
  end
70
67
 
71
- #
72
68
  # executes sql with args asynchronously and provides streaming result.
73
69
  # The first argument sql must be SQL string.
74
70
  # The rest arguments are parameters of SQL string.
@@ -84,7 +80,6 @@ module DuckDB
84
80
  # pending_result.execute_task while pending_result.state == :not_ready
85
81
  # result = pending_result.execute_pending
86
82
  # result.each.first
87
- #
88
83
  def async_query_stream(sql, *args, **kwargs)
89
84
  prepare(sql) do |stmt|
90
85
  stmt.bind_args(*args, **kwargs)
@@ -92,10 +87,8 @@ module DuckDB
92
87
  end
93
88
  end
94
89
 
95
- #
96
90
  # connects DuckDB database
97
91
  # The first argument is DuckDB::Database object
98
- #
99
92
  def connect(db)
100
93
  conn = _connect(db)
101
94
  return conn unless block_given?
@@ -107,7 +100,6 @@ module DuckDB
107
100
  end
108
101
  end
109
102
 
110
- #
111
103
  # returns PreparedStatement object.
112
104
  # The first argument is SQL string.
113
105
  # If block is given, the block is executed with PreparedStatement object
@@ -127,17 +119,14 @@ module DuckDB
127
119
  # stmt.bind_args(name: 'Dave', email: 'dave@example.com')
128
120
  # stmt.execute
129
121
  # end
130
- #
131
122
  def prepared_statement(str, &)
132
123
  return PreparedStatement.new(self, str) unless block_given?
133
124
 
134
125
  PreparedStatement.prepare(self, str, &)
135
126
  end
136
127
 
137
- #
138
128
  # returns Appender object.
139
129
  # The first argument is table name
140
- #
141
130
  def appender(table)
142
131
  appender = create_appender(table)
143
132
 
@@ -155,6 +155,19 @@ module DuckDB
155
155
  end
156
156
  end
157
157
 
158
+ def _parse_deciaml(value)
159
+ case value
160
+ when BigDecimal
161
+ value
162
+ else
163
+ begin
164
+ BigDecimal(value.to_s)
165
+ rescue StandardError => e
166
+ raise(ArgumentError, "Cannot parse `#{value.inspect}` to BigDecimal object. #{e.message}")
167
+ end
168
+ end
169
+ end
170
+
158
171
  def _to_query_progress(percentage, rows_processed, total_rows_to_process)
159
172
  DuckDB::QueryProgress.new(percentage, rows_processed, total_rows_to_process).freeze
160
173
  end
@@ -171,5 +184,12 @@ module DuckDB
171
184
  raise(ArgumentError, "The argument `#{value.inspect}` must be Integer.")
172
185
  end
173
186
  end
187
+
188
+ def decimal_to_hugeint(value)
189
+ integer_value = (value * (10 ** value.scale)).to_i
190
+ integer_to_hugeint(integer_value)
191
+ rescue FloatDomainError => e
192
+ raise(ArgumentError, "The argument `#{value.inspect}` must be converted to Integer. #{e.message}")
193
+ end
174
194
  end
175
195
  end
@@ -20,13 +20,11 @@ module DuckDB
20
20
  # result.each do |row|
21
21
  # p row
22
22
  # end
23
- #
24
23
  class Database
25
24
  private_class_method :_open
26
25
  private_class_method :_open_ext
27
26
 
28
27
  class << self
29
- ##
30
28
  # Opens database.
31
29
  # The first argument is DuckDB database file path to open.
32
30
  # If there is no argument, the method opens DuckDB database in memory.
@@ -40,7 +38,6 @@ module DuckDB
40
38
  # con = db.connect
41
39
  # con.query('CREATE TABLE users (id INTEGER, name VARCHAR(30))')
42
40
  # end
43
- #
44
41
  def open(dbpath = nil, config = nil)
45
42
  db = _db_open(dbpath, config)
46
43
  return db unless block_given?
@@ -54,7 +51,7 @@ module DuckDB
54
51
 
55
52
  private
56
53
 
57
- def _db_open(dbpath, config)
54
+ def _db_open(dbpath, config) # :nodoc:
58
55
  if config
59
56
  _open_ext(dbpath, config)
60
57
  else
@@ -63,7 +60,6 @@ module DuckDB
63
60
  end
64
61
  end
65
62
 
66
- ##
67
63
  # connects database.
68
64
  #
69
65
  # The method yields block and disconnects the database if block given
@@ -75,7 +71,6 @@ module DuckDB
75
71
  # db.connect do |con|
76
72
  # con.query('CREATE TABLE users (id INTEGER, name VARCHAR(30))')
77
73
  # end
78
- #
79
74
  def connect
80
75
  conn = _connect
81
76
  return conn unless block_given?
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DuckDB
4
+ # represents the version of the DuckDB library.
5
+ # If DuckDB.library_version is v0.2.0, then DuckDB::LIBRARY_VERSION is 0.2.0.
4
6
  LIBRARY_VERSION = library_version[1..]
5
7
  end
@@ -216,6 +216,25 @@ module DuckDB
216
216
  _bind_interval(index, value.interval_months, value.interval_days, value.interval_micros)
217
217
  end
218
218
 
219
+ # binds i-th parameter with SQL prepared statement.
220
+ # The first argument is index of parameter.
221
+ # The index of first parameter is 1 not 0.
222
+ # The second argument value is to expected BigDecimal value or any value
223
+ # that can be parsed into a BigDecimal.
224
+ #
225
+ # require 'duckdb'
226
+ # db = DuckDB::Database.open('duckdb_database')
227
+ # con = db.connect
228
+ # sql ='SELECT value FROM decimals WHERE decimal = ?'
229
+ # stmt = PreparedStatement.new(con, sql)
230
+ # stmt.bind_decimal(1, BigDecimal('987654.321'))
231
+ def bind_decimal(index, value)
232
+ decimal = _parse_deciaml(value)
233
+ lower, upper = decimal_to_hugeint(decimal)
234
+ width = decimal.to_s('F').gsub(/[^0-9]/, '').length
235
+ _bind_decimal(index, lower, upper, width, decimal.scale)
236
+ end
237
+
219
238
  # binds i-th parameter with SQL prepared statement.
220
239
  # The first argument is index of parameter.
221
240
  # The index of first parameter is 1 not 0.
@@ -264,7 +283,7 @@ module DuckDB
264
283
  when Date
265
284
  bind_varchar(index, value.strftime('%Y-%m-%d'))
266
285
  when BigDecimal
267
- bind_varchar(index, value.to_s('F'))
286
+ bind_decimal(index, value)
268
287
  else
269
288
  raise(DuckDB::Error, "not supported type `#{value}` (#{value.class})")
270
289
  end
@@ -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 = '1.1.2.1'
6
+ VERSION = '1.1.3.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: 1.1.2.1
4
+ version: 1.1.3.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-04 00:00:00.000000000 Z
11
+ date: 2024-11-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bigdecimal
@@ -181,7 +181,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
181
181
  - !ruby/object:Gem::Version
182
182
  version: '0'
183
183
  requirements: []
184
- rubygems_version: 3.5.16
184
+ rubygems_version: 3.5.22
185
185
  signing_key:
186
186
  specification_version: 4
187
187
  summary: This module is Ruby binding for DuckDB database engine.