duckdb 0.3.1.0 → 0.3.2.0

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: ba5fa57fc1eaf1a2b0bb6ffa7379b8982d3858d17075c83b949af79331322a1e
4
- data.tar.gz: cbe87ed1de6de024e9941e063102e7bf31a5407945d99180121a38fde703a8d4
3
+ metadata.gz: 96ad27d302c878ca4d207d86e1eb24e61be890c8585d6bd9231237900479053d
4
+ data.tar.gz: 4e0fb0daf725f53acd454ee77c179ef1af57a96b9308bc6f303853e28fe9b9a6
5
5
  SHA512:
6
- metadata.gz: 52d8cff8db75e7e2d7f86632573fda6d1fe021e7ff38524edf9307e2d3c4720541daab609caee24307c3a8b6a0fa40d6b1cca4151d1edbb8b17f3c7f770bb7d3
7
- data.tar.gz: 371925fa099235c382cdd370f0d43d346f40b9dc45332931956f953ab742b0a55ec7afa52f73aa942695fe30b1df78722e7afadb1de66a6250381fdf0ed990f8
6
+ metadata.gz: b407a06ebf245a9534362a5106fe7d8bd74a55f2234bf2c734da067f2a8ef150472f8b40a312acd9d0957fb27515ec67fb536cf019375825e6e62d2c1ea82e8e
7
+ data.tar.gz: e2da40b4d0cb0eb25a77a6e1b383cf54a4bd8618cc31d670f59d5068c74603e41d14c4f57f9e3f909a339798f7e2a0d0143239483aef8ea8094c92cdcac417f4
@@ -1,14 +1,22 @@
1
1
  name: MacOS
2
2
 
3
- on: [push]
3
+ on:
4
+ push:
5
+ branches:
6
+ - master
7
+ pull_request:
8
+ types:
9
+ - opened
10
+ - synchronize
11
+ - reopened
4
12
 
5
13
  jobs:
6
14
  build:
7
15
  runs-on: macos-latest
8
16
  strategy:
9
17
  matrix:
10
- ruby: ['2.6.8', '2.7.4', '3.0.2', 'head']
11
- duckdb: ['0.3.0', '0.3.1']
18
+ ruby: ['2.6.9', '2.7.5', '3.0.3', '3.1.1', 'head']
19
+ duckdb: ['0.3.2', '0.3.1']
12
20
 
13
21
  steps:
14
22
  - uses: actions/checkout@v2
@@ -1,6 +1,14 @@
1
1
  name: Ubuntu
2
2
 
3
- on: [push]
3
+ on:
4
+ push:
5
+ branches:
6
+ - master
7
+ pull_request:
8
+ types:
9
+ - opened
10
+ - synchronize
11
+ - reopened
4
12
 
5
13
  jobs:
6
14
  build:
@@ -8,8 +16,8 @@ jobs:
8
16
  runs-on: ubuntu-latest
9
17
  strategy:
10
18
  matrix:
11
- ruby: ['2.6.8', '2.7.4', '3.0.2', 'head']
12
- duckdb: ['0.3.0', '0.3.1']
19
+ ruby: ['2.6.9', '2.7.5', '3.0.3', '3.1.1', 'head']
20
+ duckdb: ['0.3.2', '0.3.1']
13
21
 
14
22
  steps:
15
23
  - uses: actions/checkout@v2
@@ -1,14 +1,22 @@
1
1
  name: Windows
2
2
 
3
- on: [push]
3
+ on:
4
+ push:
5
+ branches:
6
+ - master
7
+ pull_request:
8
+ types:
9
+ - opened
10
+ - synchronize
11
+ - reopened
4
12
 
5
13
  jobs:
6
14
  build:
7
15
  runs-on: windows-latest
8
16
  strategy:
9
17
  matrix:
10
- ruby: ['2.6.8', '2.7.4', '3.0.2', 'head']
11
- duckdb: ['0.3.0', '0.3.1']
18
+ ruby: ['2.6.9', '2.7.5', '3.0.3', '3.1.1', 'mingw', 'head']
19
+ duckdb: ['0.3.2', '0.3.1']
12
20
 
13
21
  steps:
14
22
  - uses: actions/checkout@v2
@@ -26,15 +34,16 @@ jobs:
26
34
 
27
35
  - name: extract zip file
28
36
  run: |
29
- 7z x libduckdb-windows-amd64.zip
37
+ unzip libduckdb-windows-amd64.zip
38
+
39
+ - name: setup duckdb.dll
40
+ run: |
41
+ cp duckdb.dll C:/Windows/System32/
30
42
 
31
43
  - name: Build with Rake with Ruby ${{ matrix.ruby }}
32
44
  run: |
33
45
  bundle install
34
46
  bundle exec rake build -- --with-duckdb-include=../../../.. --with-duckdb-lib=../../../..
35
- - name: setup duckdb.dll
36
- run: |
37
- cp duckdb.dll C:/Windows/System32/
38
47
 
39
48
  - name: rake test
40
49
  run: |
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # ChangeLog
2
2
 
3
+ # 0.3.2.0
4
+
5
+ - bind_time, bind_timestamp, bind_date, bind_timeinterval to DuckDB::PreparedStatement
6
+ - bump duckdb 0.3.2
7
+ - bump Ruby 3.1.1, add Ruby mingw in CI.
8
+ - bump Ruby 2.6.9, 2.7.5, 3.0.3 in CI.
9
+
10
+ ## BREAKING CHANGE
11
+ - drop duckdb <= 0.2.8
12
+
3
13
  # 0.3.1.0
4
14
 
5
15
  - bump duckdb to 0.3.1 in CI.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- duckdb (0.3.1.0)
4
+ duckdb (0.3.2.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -12,6 +12,7 @@ GEM
12
12
  rake
13
13
 
14
14
  PLATFORMS
15
+ ruby
15
16
  x86_64-linux
16
17
 
17
18
  DEPENDENCIES
data/README.md CHANGED
@@ -12,11 +12,39 @@ ruby-duckdb is Ruby binding for [DuckDB](http://www.duckdb.org) database engine
12
12
 
13
13
  You must have [DuckDB](http://www.duckdb.org) engine installed in order to build/use this module.
14
14
 
15
+ ## Pre-requisite setup (Linux):
16
+ 1. Head over to the [DuckDB](https://duckdb.org/) webpage
17
+
18
+ 2. Download the latest C++ package release for DuckDB
19
+
20
+ 3. Move the files to their respective location:
21
+ - Extract the `duckdb.h` and `duckdb.hpp` file to `/usr/local/include`
22
+ - Extract the `libduckdb.so` file to `/usr/local/lib`
23
+
24
+ ```sh
25
+ unzip libduckdb-linux-amd64.zip -d libduckdb
26
+ sudo mv libduckdb/duckdb.* /usr/local/include/
27
+ sudo mv libduckdb/libduckdb.so /usr/local/lib
28
+ ```
29
+ 4. To create the necessary link, run `ldconfig` as root:
30
+
31
+ ```sh
32
+ sudo ldconfig /usr/local/lib # adding a --verbose flag is optional - but this will let you know if the libduckdb.so library has been linked
33
+ ```
34
+ ## Pre-requisite setup (MacOS):
35
+
36
+ Using `brew install` is recommended.
37
+
38
+ ```sh
39
+ brew install duckdb
40
+ ```
41
+
15
42
  ## How to Install
16
43
 
17
44
  ```
18
45
  gem install duckdb
19
46
  ```
47
+ > this will work fine with the above pre-requisite setup.
20
48
 
21
49
  or you must specify the location of the C header and library files:
22
50
 
@@ -48,16 +48,14 @@ static VALUE appender__append_hugeint(VALUE self, VALUE lower, VALUE upper);
48
48
  static VALUE appender_flush(VALUE self);
49
49
  static VALUE appender_close(VALUE self);
50
50
 
51
- static void deallocate(void * ctx)
52
- {
51
+ static void deallocate(void * ctx) {
53
52
  rubyDuckDBAppender *p = (rubyDuckDBAppender *)ctx;
54
53
 
55
54
  duckdb_appender_destroy(&(p->appender));
56
55
  xfree(p);
57
56
  }
58
57
 
59
- static VALUE allocate(VALUE klass)
60
- {
58
+ static VALUE allocate(VALUE klass) {
61
59
  rubyDuckDBAppender *ctx = xcalloc((size_t)1, sizeof(rubyDuckDBAppender));
62
60
  return Data_Wrap_Struct(klass, NULL, deallocate, ctx);
63
61
  }
@@ -290,16 +288,12 @@ static VALUE appender_append_null(VALUE self) {
290
288
  }
291
289
 
292
290
  #ifdef HAVE_DUCKDB_APPEND_DATE
293
- static VALUE appender__append_date(VALUE self, VALUE yearval, VALUE monthval, VALUE dayval) {
294
- duckdb_date_struct dt_struct;
291
+ static VALUE appender__append_date(VALUE self, VALUE year, VALUE month, VALUE day) {
295
292
  duckdb_date dt;
296
293
  rubyDuckDBAppender *ctx;
297
294
 
298
295
  Data_Get_Struct(self, rubyDuckDBAppender, ctx);
299
- dt_struct.year = NUM2INT(yearval);
300
- dt_struct.month = NUM2INT(monthval);
301
- dt_struct.day = NUM2INT(dayval);
302
- dt = duckdb_to_date(dt_struct);
296
+ dt = to_duckdb_date_from_value(year, month, day);
303
297
 
304
298
  if (duckdb_append_date(ctx->appender, dt) == DuckDBError) {
305
299
  rb_raise(eDuckDBError, "failed to append date");
@@ -314,9 +308,7 @@ static VALUE appender__append_interval(VALUE self, VALUE months, VALUE days, VAL
314
308
  rubyDuckDBAppender *ctx;
315
309
 
316
310
  Data_Get_Struct(self, rubyDuckDBAppender, ctx);
317
- interval.months = NUM2INT(months);
318
- interval.days = NUM2INT(days);
319
- interval.micros = NUM2LL(micros);
311
+ to_duckdb_interval_from_value(&interval, months, days, micros);
320
312
 
321
313
  if (duckdb_append_interval(ctx->appender, interval) == DuckDBError) {
322
314
  rb_raise(eDuckDBError, "failed to append interval");
@@ -327,17 +319,11 @@ static VALUE appender__append_interval(VALUE self, VALUE months, VALUE days, VAL
327
319
 
328
320
  #ifdef HAVE_DUCKDB_APPEND_TIME
329
321
  static VALUE appender__append_time(VALUE self, VALUE hour, VALUE min, VALUE sec, VALUE micros) {
330
- duckdb_time_struct time_st;
331
322
  duckdb_time time;
332
323
  rubyDuckDBAppender *ctx;
333
324
 
334
325
  Data_Get_Struct(self, rubyDuckDBAppender, ctx);
335
- time_st.hour = NUM2INT(hour);
336
- time_st.min = NUM2INT(min);
337
- time_st.sec = NUM2INT(sec);
338
- time_st.micros = NUM2INT(micros);
339
-
340
- time = duckdb_to_time(time_st);
326
+ time = to_duckdb_time_from_value(hour, min, sec, micros);
341
327
 
342
328
  if (duckdb_append_time(ctx->appender, time) == DuckDBError) {
343
329
  rb_raise(eDuckDBError, "failed to append time");
@@ -348,22 +334,13 @@ static VALUE appender__append_time(VALUE self, VALUE hour, VALUE min, VALUE sec,
348
334
 
349
335
  #ifdef HAVE_DUCKDB_APPEND_TIMESTAMP
350
336
  static VALUE appender__append_timestamp(VALUE self, VALUE year, VALUE month, VALUE day, VALUE hour, VALUE min, VALUE sec, VALUE micros) {
351
- duckdb_timestamp_struct timestamp_st;
352
337
  duckdb_timestamp timestamp;
353
338
 
354
339
  rubyDuckDBAppender *ctx;
355
340
 
356
341
  Data_Get_Struct(self, rubyDuckDBAppender, ctx);
357
342
 
358
- timestamp_st.date.year = NUM2INT(year);
359
- timestamp_st.date.month = NUM2INT(month);
360
- timestamp_st.date.day = NUM2INT(day);
361
- timestamp_st.time.hour = NUM2INT(hour);
362
- timestamp_st.time.min = NUM2INT(min);
363
- timestamp_st.time.sec = NUM2INT(sec);
364
- timestamp_st.time.micros = NUM2INT(micros);
365
-
366
- timestamp = duckdb_to_timestamp(timestamp_st);
343
+ timestamp = to_duckdb_timestamp_from_value(year, month, day, hour, min, sec, micros);
367
344
 
368
345
  if (duckdb_append_timestamp(ctx->appender, timestamp) == DuckDBError) {
369
346
  rb_raise(eDuckDBError, "failed to append timestamp");
data/ext/duckdb/blob.c CHANGED
@@ -1,11 +1,7 @@
1
1
  #include "ruby-duckdb.h"
2
2
 
3
- #ifdef HAVE_DUCKDB_VALUE_BLOB
4
-
5
3
  VALUE cDuckDBBlob;
6
4
 
7
- void init_duckdb_blob(void)
8
- {
5
+ void init_duckdb_blob(void) {
9
6
  cDuckDBBlob = rb_define_class_under(mDuckDB, "Blob", rb_cString);
10
7
  }
11
- #endif /* HAVE_DUCKDB_VALUE_BLOB */
data/ext/duckdb/blob.h CHANGED
@@ -4,11 +4,7 @@
4
4
  /*
5
5
  * blob is supported by duckdb v0.2.5 or later
6
6
  */
7
- #ifdef HAVE_DUCKDB_VALUE_BLOB
8
-
9
7
  void init_duckdb_blob(void);
10
8
 
11
- #endif /* HAVE_DUCKDB_VALUE_BLOB */
12
-
13
9
  #endif
14
10
 
data/ext/duckdb/config.c CHANGED
@@ -11,16 +11,14 @@ static VALUE config_s_get_config_flag(VALUE self, VALUE value);
11
11
  static VALUE config_initialize(VALUE self);
12
12
  static VALUE config_set_config(VALUE self, VALUE key, VALUE value);
13
13
 
14
- static void deallocate(void * ctx)
15
- {
14
+ static void deallocate(void * ctx) {
16
15
  rubyDuckDBConfig *p = (rubyDuckDBConfig *)ctx;
17
16
 
18
17
  duckdb_destroy_config(&(p->config));
19
18
  xfree(p);
20
19
  }
21
20
 
22
- static VALUE allocate(VALUE klass)
23
- {
21
+ static VALUE allocate(VALUE klass) {
24
22
  rubyDuckDBConfig *ctx = xcalloc((size_t)1, sizeof(rubyDuckDBConfig));
25
23
  return Data_Wrap_Struct(klass, NULL, deallocate, ctx);
26
24
  }
@@ -78,13 +78,12 @@ static VALUE duckdb_connection_query_sql(VALUE self, VALUE str) {
78
78
  }
79
79
 
80
80
  if (duckdb_query(ctx->con, StringValueCStr(str), &(ctxr->result)) == DuckDBError) {
81
- rb_raise(eDuckDBError, "%s", ctxr->result.error_message);
81
+ rb_raise(eDuckDBError, "%s", duckdb_result_error(&(ctxr->result)));
82
82
  }
83
83
  return result;
84
84
  }
85
85
 
86
- void init_duckdb_connection(void)
87
- {
86
+ void init_duckdb_connection(void) {
88
87
  cDuckDBConnection = rb_define_class_under(mDuckDB, "Connection", rb_cObject);
89
88
  rb_define_alloc_func(cDuckDBConnection, allocate);
90
89
 
data/ext/duckdb/duckdb.c CHANGED
@@ -3,8 +3,7 @@
3
3
  VALUE mDuckDB;
4
4
 
5
5
  void
6
- Init_duckdb_native(void)
7
- {
6
+ Init_duckdb_native(void) {
8
7
  mDuckDB = rb_define_module("DuckDB");
9
8
 
10
9
  init_duckdb_error();
@@ -12,13 +11,8 @@ Init_duckdb_native(void)
12
11
  init_duckdb_connection();
13
12
  init_duckdb_result();
14
13
  init_duckdb_prepared_statement();
15
-
16
- #ifdef HAVE_DUCKDB_VALUE_BLOB
17
-
18
14
  init_duckdb_blob();
19
15
 
20
- #endif /* HAVE_DUCKDB_VALUE_BLOB */
21
-
22
16
  #ifdef HAVE_DUCKDB_APPENDER_CREATE
23
17
 
24
18
  init_duckdb_appender();
data/ext/duckdb/error.c CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  VALUE eDuckDBError;
4
4
 
5
- void init_duckdb_error(void)
6
- {
5
+ void init_duckdb_error(void) {
7
6
  eDuckDBError = rb_define_class_under(mDuckDB, "Error", rb_eStandardError);
8
7
  }
@@ -1,24 +1,33 @@
1
1
  require 'mkmf'
2
2
 
3
3
  dir_config('duckdb')
4
- if have_library('duckdb')
5
- if have_func('duckdb_nparams(NULL)', 'duckdb.h')
6
- $defs << '-DHAVE_DUCKDB_NPARAMS_029'
7
- elsif have_func('duckdb_nparams(NULL, NULL)', 'duckdb.h')
8
- $defs << '-DHAVE_DUCKDB_NPARAMS_028'
9
- end
10
-
11
- have_func('duckdb_value_blob', 'duckdb.h')
12
- have_func('duckdb_bind_blob', 'duckdb.h')
13
- have_func('duckdb_appender_create', 'duckdb.h')
14
- have_func('duckdb_free', 'duckdb.h')
15
- have_func('duckdb_create_config', 'duckdb.h')
16
- have_func('duckdb_open_ext', 'duckdb.h')
17
- have_func('duckdb_prepare_error', 'duckdb.h')
18
- have_func('duckdb_append_date', 'duckdb.h')
19
- have_func('duckdb_append_interval', 'duckdb.h')
20
- have_func('duckdb_append_time', 'duckdb.h')
21
- have_func('duckdb_append_timestamp', 'duckdb.h')
22
- have_func('duckdb_append_hugeint', 'duckdb.h')
23
- create_makefile('duckdb/duckdb_native')
4
+
5
+ raise 'duckdb library is not found. Install duckdb library file and header file.' unless have_library('duckdb')
6
+
7
+ raise 'duckdb >= 0.2.9 is required. Install duckdb >= 0.2.9' unless have_func('duckdb_value_is_null', 'duckdb.h')
8
+
9
+ if have_func('duckdb_nparams(NULL)', 'duckdb.h')
10
+ $defs << '-DHAVE_DUCKDB_NPARAMS_029'
11
+ elsif have_func('duckdb_nparams(NULL, NULL)', 'duckdb.h')
12
+ $defs << '-DHAVE_DUCKDB_NPARAMS_028'
24
13
  end
14
+
15
+ have_func('duckdb_appender_create', 'duckdb.h')
16
+ have_func('duckdb_free', 'duckdb.h')
17
+
18
+ have_func('duckdb_create_config', 'duckdb.h')
19
+ have_func('duckdb_open_ext', 'duckdb.h')
20
+ have_func('duckdb_prepare_error', 'duckdb.h')
21
+
22
+ have_func('duckdb_append_date', 'duckdb.h')
23
+ have_func('duckdb_append_interval', 'duckdb.h')
24
+ have_func('duckdb_append_time', 'duckdb.h')
25
+ have_func('duckdb_append_timestamp', 'duckdb.h')
26
+ have_func('duckdb_append_hugeint', 'duckdb.h')
27
+
28
+ have_func('duckdb_bind_date', 'duckdb.h')
29
+ have_func('duckdb_bind_time', 'duckdb.h')
30
+ have_func('duckdb_bind_timestamp', 'duckdb.h')
31
+ have_func('duckdb_bind_interval', 'duckdb.h')
32
+
33
+ create_makefile('duckdb/duckdb_native')
@@ -2,22 +2,53 @@
2
2
 
3
3
  static VALUE cDuckDBPreparedStatement;
4
4
 
5
- static void deallocate(void *ctx)
6
- {
5
+ static void deallocate(void *ctx);
6
+ static VALUE allocate(VALUE klass);
7
+ static VALUE duckdb_prepared_statement_initialize(VALUE self, VALUE con, VALUE query);
8
+ static VALUE duckdb_prepared_statement_nparams(VALUE self);
9
+ static VALUE duckdb_prepared_statement_execute(VALUE self);
10
+ static idx_t check_index(VALUE vidx);
11
+ static VALUE duckdb_prepared_statement_bind_bool(VALUE self, VALUE vidx, VALUE val);
12
+ static VALUE duckdb_prepared_statement_bind_int8(VALUE self, VALUE vidx, VALUE val);
13
+ static VALUE duckdb_prepared_statement_bind_int16(VALUE self, VALUE vidx, VALUE val);
14
+ static VALUE duckdb_prepared_statement_bind_int32(VALUE self, VALUE vidx, VALUE val);
15
+ static VALUE duckdb_prepared_statement_bind_int64(VALUE self, VALUE vidx, VALUE val);
16
+ static VALUE duckdb_prepared_statement_bind_float(VALUE self, VALUE vidx, VALUE val);
17
+ static VALUE duckdb_prepared_statement_bind_double(VALUE self, VALUE vidx, VALUE val);
18
+ static VALUE duckdb_prepared_statement_bind_varchar(VALUE self, VALUE vidx, VALUE str);
19
+ static VALUE duckdb_prepared_statement_bind_blob(VALUE self, VALUE vidx, VALUE blob);
20
+ static VALUE duckdb_prepared_statement_bind_null(VALUE self, VALUE vidx);
21
+
22
+ #ifdef HAVE_DUCKDB_BIND_DATE
23
+ static VALUE duckdb_prepared_statement__bind_date(VALUE self, VALUE vidx, VALUE year, VALUE month, VALUE day);
24
+ #endif
25
+
26
+ #ifdef HAVE_DUCKDB_BIND_TIME
27
+ static VALUE duckdb_prepared_statement__bind_time(VALUE self, VALUE vidx, VALUE hour, VALUE min, VALUE sec, VALUE micros);
28
+ #endif
29
+
30
+ #ifdef HAVE_DUCKDB_BIND_TIMESTAMP
31
+ 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);
32
+ #endif
33
+
34
+ #ifdef HAVE_DUCKDB_BIND_INTERVAL
35
+ static VALUE duckdb_prepared_statement__bind_interval(VALUE self, VALUE vidx, VALUE months, VALUE days, VALUE micros);
36
+ #endif
37
+
38
+
39
+ static void deallocate(void *ctx) {
7
40
  rubyDuckDBPreparedStatement *p = (rubyDuckDBPreparedStatement *)ctx;
8
41
 
9
42
  duckdb_destroy_prepare(&(p->prepared_statement));
10
43
  xfree(p);
11
44
  }
12
45
 
13
- static VALUE allocate(VALUE klass)
14
- {
46
+ static VALUE allocate(VALUE klass) {
15
47
  rubyDuckDBPreparedStatement *ctx = xcalloc((size_t)1, sizeof(rubyDuckDBPreparedStatement));
16
48
  return Data_Wrap_Struct(klass, NULL, deallocate, ctx);
17
49
  }
18
50
 
19
- static VALUE duckdb_prepared_statement_initialize(VALUE self, VALUE con, VALUE query)
20
- {
51
+ static VALUE duckdb_prepared_statement_initialize(VALUE self, VALUE con, VALUE query) {
21
52
  rubyDuckDBConnection *ctxcon;
22
53
  rubyDuckDBPreparedStatement *ctx;
23
54
 
@@ -40,8 +71,7 @@ static VALUE duckdb_prepared_statement_initialize(VALUE self, VALUE con, VALUE q
40
71
  return self;
41
72
  }
42
73
 
43
- static VALUE duckdb_prepared_statement_nparams(VALUE self)
44
- {
74
+ static VALUE duckdb_prepared_statement_nparams(VALUE self) {
45
75
  rubyDuckDBPreparedStatement *ctx;
46
76
  Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
47
77
  #ifdef HAVE_DUCKDB_NPARAMS_029
@@ -55,8 +85,7 @@ static VALUE duckdb_prepared_statement_nparams(VALUE self)
55
85
  }
56
86
 
57
87
 
58
- static VALUE duckdb_prepared_statement_execute(VALUE self)
59
- {
88
+ static VALUE duckdb_prepared_statement_execute(VALUE self) {
60
89
  rubyDuckDBPreparedStatement *ctx;
61
90
  rubyDuckDBResult *ctxr;
62
91
  VALUE result = create_result();
@@ -64,13 +93,12 @@ static VALUE duckdb_prepared_statement_execute(VALUE self)
64
93
  Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
65
94
  Data_Get_Struct(result, rubyDuckDBResult, ctxr);
66
95
  if (duckdb_execute_prepared(ctx->prepared_statement, &(ctxr->result)) == DuckDBError) {
67
- rb_raise(eDuckDBError, "%s", ctxr->result.error_message);
96
+ rb_raise(eDuckDBError, "%s", duckdb_result_error(&(ctxr->result)));
68
97
  }
69
98
  return result;
70
99
  }
71
100
 
72
- static idx_t check_index(VALUE vidx)
73
- {
101
+ static idx_t check_index(VALUE vidx) {
74
102
  idx_t idx = FIX2INT(vidx);
75
103
  if (idx <= 0) {
76
104
  rb_raise(rb_eArgError, "index of parameter must be greater than 0");
@@ -78,8 +106,7 @@ static idx_t check_index(VALUE vidx)
78
106
  return idx;
79
107
  }
80
108
 
81
- static VALUE duckdb_prepared_statement_bind_bool(VALUE self, VALUE vidx, VALUE val)
82
- {
109
+ static VALUE duckdb_prepared_statement_bind_bool(VALUE self, VALUE vidx, VALUE val) {
83
110
  rubyDuckDBPreparedStatement *ctx;
84
111
  idx_t idx = check_index(vidx);
85
112
 
@@ -94,8 +121,7 @@ static VALUE duckdb_prepared_statement_bind_bool(VALUE self, VALUE vidx, VALUE v
94
121
  return self;
95
122
  }
96
123
 
97
- static VALUE duckdb_prepared_statement_bind_int8(VALUE self, VALUE vidx, VALUE val)
98
- {
124
+ static VALUE duckdb_prepared_statement_bind_int8(VALUE self, VALUE vidx, VALUE val) {
99
125
  rubyDuckDBPreparedStatement *ctx;
100
126
  idx_t idx = check_index(vidx);
101
127
  int8_t i8val = (int8_t)NUM2INT(val);
@@ -108,8 +134,7 @@ static VALUE duckdb_prepared_statement_bind_int8(VALUE self, VALUE vidx, VALUE v
108
134
  return self;
109
135
  }
110
136
 
111
- static VALUE duckdb_prepared_statement_bind_int16(VALUE self, VALUE vidx, VALUE val)
112
- {
137
+ static VALUE duckdb_prepared_statement_bind_int16(VALUE self, VALUE vidx, VALUE val) {
113
138
  rubyDuckDBPreparedStatement *ctx;
114
139
  idx_t idx = check_index(vidx);
115
140
  int16_t i16val = NUM2INT(val);
@@ -122,8 +147,7 @@ static VALUE duckdb_prepared_statement_bind_int16(VALUE self, VALUE vidx, VALUE
122
147
  return self;
123
148
  }
124
149
 
125
- static VALUE duckdb_prepared_statement_bind_int32(VALUE self, VALUE vidx, VALUE val)
126
- {
150
+ static VALUE duckdb_prepared_statement_bind_int32(VALUE self, VALUE vidx, VALUE val) {
127
151
  rubyDuckDBPreparedStatement *ctx;
128
152
  idx_t idx = check_index(vidx);
129
153
  int32_t i32val = NUM2INT(val);
@@ -136,8 +160,7 @@ static VALUE duckdb_prepared_statement_bind_int32(VALUE self, VALUE vidx, VALUE
136
160
  return self;
137
161
  }
138
162
 
139
- static VALUE duckdb_prepared_statement_bind_int64(VALUE self, VALUE vidx, VALUE val)
140
- {
163
+ static VALUE duckdb_prepared_statement_bind_int64(VALUE self, VALUE vidx, VALUE val) {
141
164
  rubyDuckDBPreparedStatement *ctx;
142
165
  idx_t idx = check_index(vidx);
143
166
  int64_t i64val = NUM2LL(val);
@@ -150,8 +173,7 @@ static VALUE duckdb_prepared_statement_bind_int64(VALUE self, VALUE vidx, VALUE
150
173
  return self;
151
174
  }
152
175
 
153
- static VALUE duckdb_prepared_statement_bind_float(VALUE self, VALUE vidx, VALUE val)
154
- {
176
+ static VALUE duckdb_prepared_statement_bind_float(VALUE self, VALUE vidx, VALUE val) {
155
177
  rubyDuckDBPreparedStatement *ctx;
156
178
  idx_t idx = check_index(vidx);
157
179
  double dbl = NUM2DBL(val);
@@ -164,8 +186,7 @@ static VALUE duckdb_prepared_statement_bind_float(VALUE self, VALUE vidx, VALUE
164
186
  return self;
165
187
  }
166
188
 
167
- static VALUE duckdb_prepared_statement_bind_double(VALUE self, VALUE vidx, VALUE val)
168
- {
189
+ static VALUE duckdb_prepared_statement_bind_double(VALUE self, VALUE vidx, VALUE val) {
169
190
  rubyDuckDBPreparedStatement *ctx;
170
191
  idx_t idx = check_index(vidx);
171
192
  double dbl = NUM2DBL(val);
@@ -178,8 +199,7 @@ static VALUE duckdb_prepared_statement_bind_double(VALUE self, VALUE vidx, VALUE
178
199
  return self;
179
200
  }
180
201
 
181
- static VALUE duckdb_prepared_statement_bind_varchar(VALUE self, VALUE vidx, VALUE str)
182
- {
202
+ static VALUE duckdb_prepared_statement_bind_varchar(VALUE self, VALUE vidx, VALUE str) {
183
203
  rubyDuckDBPreparedStatement *ctx;
184
204
  idx_t idx = check_index(vidx);
185
205
 
@@ -190,9 +210,7 @@ static VALUE duckdb_prepared_statement_bind_varchar(VALUE self, VALUE vidx, VALU
190
210
  return self;
191
211
  }
192
212
 
193
- #ifdef HAVE_DUCKDB_VALUE_BLOB
194
- static VALUE duckdb_prepared_statement_bind_blob(VALUE self, VALUE vidx, VALUE blob)
195
- {
213
+ static VALUE duckdb_prepared_statement_bind_blob(VALUE self, VALUE vidx, VALUE blob) {
196
214
  rubyDuckDBPreparedStatement *ctx;
197
215
  idx_t idx = check_index(vidx);
198
216
 
@@ -202,10 +220,8 @@ static VALUE duckdb_prepared_statement_bind_blob(VALUE self, VALUE vidx, VALUE b
202
220
  }
203
221
  return self;
204
222
  }
205
- #endif /* HAVE_DUCKDB_VALUE_BLOB */
206
223
 
207
- static VALUE duckdb_prepared_statement_bind_null(VALUE self, VALUE vidx)
208
- {
224
+ static VALUE duckdb_prepared_statement_bind_null(VALUE self, VALUE vidx) {
209
225
  rubyDuckDBPreparedStatement *ctx;
210
226
  idx_t idx = check_index(vidx);
211
227
 
@@ -216,8 +232,72 @@ static VALUE duckdb_prepared_statement_bind_null(VALUE self, VALUE vidx)
216
232
  return self;
217
233
  }
218
234
 
219
- void init_duckdb_prepared_statement(void)
220
- {
235
+ #ifdef HAVE_DUCKDB_BIND_DATE
236
+ static VALUE duckdb_prepared_statement__bind_date(VALUE self, VALUE vidx, VALUE year, VALUE month, VALUE day) {
237
+ rubyDuckDBPreparedStatement *ctx;
238
+ duckdb_date dt;
239
+ idx_t idx = check_index(vidx);
240
+
241
+ dt = to_duckdb_date_from_value(year, month, day);
242
+
243
+ Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
244
+ if (duckdb_bind_date(ctx->prepared_statement, idx, dt) == DuckDBError) {
245
+ rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
246
+ }
247
+ return self;
248
+ }
249
+ #endif
250
+
251
+ #ifdef HAVE_DUCKDB_BIND_TIME
252
+ static VALUE duckdb_prepared_statement__bind_time(VALUE self, VALUE vidx, VALUE hour, VALUE min, VALUE sec, VALUE micros){
253
+ rubyDuckDBPreparedStatement *ctx;
254
+ duckdb_time time;
255
+
256
+ idx_t idx = check_index(vidx);
257
+
258
+ time = to_duckdb_time_from_value(hour, min, sec, micros);
259
+
260
+ Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
261
+ if (duckdb_bind_time(ctx->prepared_statement, idx, time) == DuckDBError) {
262
+ rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
263
+ }
264
+ return self;
265
+ }
266
+ #endif
267
+
268
+ #ifdef HAVE_DUCKDB_BIND_TIMESTAMP
269
+ 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) {
270
+ duckdb_timestamp timestamp;
271
+ rubyDuckDBPreparedStatement *ctx;
272
+ idx_t idx = check_index(vidx);
273
+
274
+ timestamp = to_duckdb_timestamp_from_value(year, month, day, hour, min, sec, micros);
275
+ Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
276
+
277
+ if (duckdb_bind_timestamp(ctx->prepared_statement, idx, timestamp) == DuckDBError) {
278
+ rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
279
+ }
280
+ return self;
281
+ }
282
+ #endif
283
+
284
+ #ifdef HAVE_DUCKDB_BIND_INTERVAL
285
+ static VALUE duckdb_prepared_statement__bind_interval(VALUE self, VALUE vidx, VALUE months, VALUE days, VALUE micros) {
286
+ duckdb_interval interval;
287
+ rubyDuckDBPreparedStatement *ctx;
288
+ idx_t idx = check_index(vidx);
289
+
290
+ Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
291
+ to_duckdb_interval_from_value(&interval, months, days, micros);
292
+
293
+ if (duckdb_bind_interval(ctx->prepared_statement, idx, interval) == DuckDBError) {
294
+ rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
295
+ }
296
+ return self;
297
+ }
298
+ #endif
299
+
300
+ void init_duckdb_prepared_statement(void) {
221
301
  cDuckDBPreparedStatement = rb_define_class_under(mDuckDB, "PreparedStatement", rb_cObject);
222
302
 
223
303
  rb_define_alloc_func(cDuckDBPreparedStatement, allocate);
@@ -233,8 +313,16 @@ void init_duckdb_prepared_statement(void)
233
313
  rb_define_method(cDuckDBPreparedStatement, "bind_float", duckdb_prepared_statement_bind_float, 2);
234
314
  rb_define_method(cDuckDBPreparedStatement, "bind_double", duckdb_prepared_statement_bind_double, 2);
235
315
  rb_define_method(cDuckDBPreparedStatement, "bind_varchar", duckdb_prepared_statement_bind_varchar, 2);
236
- #ifdef HAVE_DUCKDB_VALUE_BLOB
237
316
  rb_define_method(cDuckDBPreparedStatement, "bind_blob", duckdb_prepared_statement_bind_blob, 2);
238
- #endif /* HAVE_DUCKDB_VALUE_BLOB */
239
317
  rb_define_method(cDuckDBPreparedStatement, "bind_null", duckdb_prepared_statement_bind_null, 1);
318
+ rb_define_private_method(cDuckDBPreparedStatement, "_bind_date", duckdb_prepared_statement__bind_date, 4);
319
+ #ifdef HAVE_DUCKDB_BIND_TIME
320
+ rb_define_private_method(cDuckDBPreparedStatement, "_bind_time", duckdb_prepared_statement__bind_time, 5);
321
+ #endif
322
+ #ifdef HAVE_DUCKDB_BIND_TIMESTAMP
323
+ rb_define_private_method(cDuckDBPreparedStatement, "_bind_timestamp", duckdb_prepared_statement__bind_timestamp, 8);
324
+ #endif
325
+ #ifdef HAVE_DUCKDB_BIND_INTERVAL
326
+ rb_define_private_method(cDuckDBPreparedStatement, "_bind_interval", duckdb_prepared_statement__bind_interval, 4);
327
+ #endif
240
328
  }
data/ext/duckdb/result.c CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
  static VALUE cDuckDBResult;
4
4
 
5
+ static void deallocate(void *ctx);
6
+ static VALUE allocate(VALUE klass);
7
+ static VALUE to_ruby_obj_boolean(duckdb_result *result, idx_t col_idx, idx_t row_idx);
8
+ static VALUE to_ruby_obj_smallint(duckdb_result *result, idx_t col_idx, idx_t row_idx);
9
+ static VALUE to_ruby_obj_integer(duckdb_result *result, idx_t col_idx, idx_t row_idx);
10
+ static VALUE to_ruby_obj_bigint(duckdb_result *result, idx_t col_idx, idx_t row_idx);
11
+ static VALUE to_ruby_obj_float(duckdb_result *result, idx_t col_idx, idx_t row_idx);
12
+ static VALUE to_ruby_obj_double(duckdb_result *result, idx_t col_idx, idx_t row_idx);
13
+ static VALUE to_ruby_obj_string_from_blob(duckdb_result *result, idx_t col_idx, idx_t row_idx);
14
+ static VALUE to_ruby_obj(duckdb_result *result, idx_t col_idx, idx_t row_idx);
15
+ static VALUE row_array(rubyDuckDBResult *ctx, idx_t row_idx);
16
+ static VALUE duckdb_result_row_size(VALUE oDuckDBResult, VALUE args, VALUE obj);
17
+ static VALUE duckdb_result_each(VALUE oDuckDBResult);
18
+ static VALUE duckdb_result_rows_changed(VALUE oDuckDBResult);
19
+
5
20
  static void deallocate(void *ctx) {
6
21
  rubyDuckDBResult *p = (rubyDuckDBResult *)ctx;
7
22
 
@@ -44,7 +59,6 @@ static VALUE to_ruby_obj_double(duckdb_result *result, idx_t col_idx, idx_t row_
44
59
  return DBL2NUM(dval);
45
60
  }
46
61
 
47
- #ifdef HAVE_DUCKDB_VALUE_BLOB
48
62
  static VALUE to_ruby_obj_string_from_blob(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
49
63
  VALUE str;
50
64
  duckdb_blob bval = duckdb_value_blob(result, col_idx, row_idx);
@@ -60,15 +74,14 @@ static VALUE to_ruby_obj_string_from_blob(duckdb_result *result, idx_t col_idx,
60
74
 
61
75
  return str;
62
76
  }
63
- #endif /* HAVE_DUCKDB_VALUE_BLOB */
64
77
 
65
78
  static VALUE to_ruby_obj(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
66
79
  char *p;
67
80
  VALUE obj = Qnil;
68
- if (result->columns[col_idx].nullmask[row_idx]) {
81
+ if (duckdb_value_is_null(result, col_idx, row_idx)) {
69
82
  return obj;
70
83
  }
71
- switch(result->columns[col_idx].type) {
84
+ switch(duckdb_column_type(result, col_idx)) {
72
85
  case DUCKDB_TYPE_BOOLEAN:
73
86
  return to_ruby_obj_boolean(result, col_idx, row_idx);
74
87
  case DUCKDB_TYPE_SMALLINT:
@@ -81,10 +94,8 @@ static VALUE to_ruby_obj(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
81
94
  return to_ruby_obj_float(result, col_idx, row_idx);
82
95
  case DUCKDB_TYPE_DOUBLE:
83
96
  return to_ruby_obj_double(result, col_idx, row_idx);
84
- #ifdef HAVE_DUCKDB_VALUE_BLOB
85
97
  case DUCKDB_TYPE_BLOB:
86
98
  return to_ruby_obj_string_from_blob(result, col_idx, row_idx);
87
- #endif /* HAVE_DUCKDB_VALUE_BLOB */
88
99
  default:
89
100
  p = duckdb_value_varchar(result, col_idx, row_idx);
90
101
  if (p) {
@@ -94,7 +105,7 @@ static VALUE to_ruby_obj(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
94
105
  #else
95
106
  free(p);
96
107
  #endif /* HAVE_DUCKDB_FREE */
97
- if (result->columns[col_idx].type == DUCKDB_TYPE_HUGEINT) {
108
+ if (duckdb_column_type(result, col_idx) == DUCKDB_TYPE_HUGEINT) {
98
109
  obj = rb_funcall(obj, rb_intern("to_i"), 0);
99
110
  }
100
111
  }
@@ -104,8 +115,10 @@ static VALUE to_ruby_obj(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
104
115
 
105
116
  static VALUE row_array(rubyDuckDBResult *ctx, idx_t row_idx) {
106
117
  idx_t col_idx;
107
- VALUE ary = rb_ary_new2(ctx->result.column_count);
108
- for(col_idx = 0; col_idx < ctx->result.column_count; col_idx++) {
118
+ idx_t column_count = duckdb_column_count(&(ctx->result));
119
+
120
+ VALUE ary = rb_ary_new2(column_count);
121
+ for(col_idx = 0; col_idx < column_count; col_idx++) {
109
122
  rb_ary_store(ary, col_idx, to_ruby_obj(&(ctx->result), col_idx, row_idx));
110
123
  }
111
124
  return ary;
@@ -115,17 +128,19 @@ static VALUE duckdb_result_row_size(VALUE oDuckDBResult, VALUE args, VALUE obj)
115
128
  rubyDuckDBResult *ctx;
116
129
  Data_Get_Struct(oDuckDBResult, rubyDuckDBResult, ctx);
117
130
 
118
- return LONG2FIX(ctx->result.row_count);
131
+ return LONG2FIX(duckdb_row_count(&(ctx->result)));
119
132
  }
120
133
 
121
134
  static VALUE duckdb_result_each(VALUE oDuckDBResult) {
122
135
  rubyDuckDBResult *ctx;
123
136
  idx_t row_idx = 0;
137
+ idx_t row_count = 0;
124
138
 
125
139
  RETURN_SIZED_ENUMERATOR(oDuckDBResult, 0, 0, duckdb_result_row_size);
126
140
 
127
141
  Data_Get_Struct(oDuckDBResult, rubyDuckDBResult, ctx);
128
- for (row_idx = 0; row_idx < ctx->result.row_count; row_idx++) {
142
+ row_count = duckdb_row_count(&(ctx->result));
143
+ for (row_idx = 0; row_idx < row_count; row_idx++) {
129
144
  rb_yield(row_array(ctx, row_idx));
130
145
  }
131
146
  return oDuckDBResult;
@@ -156,7 +171,7 @@ static VALUE duckdb_result_each(VALUE oDuckDBResult) {
156
171
  static VALUE duckdb_result_rows_changed(VALUE oDuckDBResult) {
157
172
  rubyDuckDBResult *ctx;
158
173
  Data_Get_Struct(oDuckDBResult, rubyDuckDBResult, ctx);
159
- return LL2NUM(ctx->result.rows_changed);
174
+ return LL2NUM(duckdb_rows_changed(&(ctx->result)));
160
175
  }
161
176
 
162
177
  VALUE create_result(void) {
@@ -8,13 +8,9 @@
8
8
  #include "./connection.h"
9
9
  #include "./result.h"
10
10
  #include "./prepared_statement.h"
11
-
12
- #ifdef HAVE_DUCKDB_VALUE_BLOB
11
+ #include "./util.h"
13
12
 
14
13
  #include "./blob.h"
15
-
16
- #endif /* HAVE_DUCKDB_VALUE_BLOB */
17
-
18
14
  #ifdef HAVE_DUCKDB_APPENDER_CREATE
19
15
 
20
16
  #include "./appender.h"
@@ -30,19 +26,8 @@
30
26
  extern VALUE mDuckDB;
31
27
  extern VALUE cDuckDBDatabase;
32
28
  extern VALUE cDuckDBConnection;
33
-
34
- #ifdef HAVE_DUCKDB_VALUE_BLOB
35
-
36
29
  extern VALUE cDuckDBBlob;
37
-
38
- #endif /* HAVE_DUCKDB_VALUE_BLOB */
39
-
40
- #ifdef HAVE_DUCKDB_CREATE_CONFIG
41
-
42
30
  extern VALUE cDuckDBConfig;
43
-
44
- #endif /* HAVE_DUCKDB_CREATE_CONFIG */
45
-
46
31
  extern VALUE eDuckDBError;
47
32
 
48
33
  #endif
data/ext/duckdb/util.c ADDED
@@ -0,0 +1,45 @@
1
+ #include "ruby-duckdb.h"
2
+
3
+ #ifdef HAVE_DUCKDB_APPEND_DATE
4
+
5
+ duckdb_date to_duckdb_date_from_value(VALUE year, VALUE month, VALUE day) {
6
+ duckdb_date_struct dt_struct;
7
+
8
+ dt_struct.year = NUM2INT(year);
9
+ dt_struct.month = NUM2INT(month);
10
+ dt_struct.day = NUM2INT(day);
11
+
12
+ return duckdb_to_date(dt_struct);
13
+ }
14
+
15
+ duckdb_time to_duckdb_time_from_value(VALUE hour, VALUE min, VALUE sec, VALUE micros) {
16
+ duckdb_time_struct time_st;
17
+
18
+ time_st.hour = NUM2INT(hour);
19
+ time_st.min = NUM2INT(min);
20
+ time_st.sec = NUM2INT(sec);
21
+ time_st.micros = NUM2INT(micros);
22
+
23
+ return duckdb_to_time(time_st);
24
+ }
25
+
26
+ duckdb_timestamp to_duckdb_timestamp_from_value(VALUE year, VALUE month, VALUE day, VALUE hour, VALUE min, VALUE sec, VALUE micros) {
27
+ duckdb_timestamp_struct timestamp_st;
28
+
29
+ timestamp_st.date.year = NUM2INT(year);
30
+ timestamp_st.date.month = NUM2INT(month);
31
+ timestamp_st.date.day = NUM2INT(day);
32
+ timestamp_st.time.hour = NUM2INT(hour);
33
+ timestamp_st.time.min = NUM2INT(min);
34
+ timestamp_st.time.sec = NUM2INT(sec);
35
+ timestamp_st.time.micros = NUM2INT(micros);
36
+
37
+ return duckdb_to_timestamp(timestamp_st);
38
+ }
39
+
40
+ void to_duckdb_interval_from_value(duckdb_interval* interval, VALUE months, VALUE days, VALUE micros) {
41
+ interval->months = NUM2INT(months);
42
+ interval->days = NUM2INT(days);
43
+ interval->micros = NUM2LL(micros);
44
+ }
45
+ #endif
data/ext/duckdb/util.h ADDED
@@ -0,0 +1,13 @@
1
+ #ifndef RUBY_DUCKDB_UTIL_H
2
+ #define RUBY_DUCKDB_UTIL_H
3
+
4
+ #ifdef HAVE_DUCKDB_APPEND_DATE
5
+
6
+ duckdb_date to_duckdb_date_from_value(VALUE year, VALUE month, VALUE day);
7
+ duckdb_time to_duckdb_time_from_value(VALUE hour, VALUE min, VALUE sec, VALUE micros);
8
+ duckdb_timestamp to_duckdb_timestamp_from_value(VALUE year, VALUE month, VALUE day, VALUE hour, VALUE min, VALUE sec, VALUE micros);
9
+ void to_duckdb_interval_from_value(duckdb_interval* interval, VALUE months, VALUE days, VALUE micros);
10
+
11
+ #endif
12
+
13
+ #endif
@@ -1,5 +1,6 @@
1
1
  require 'date'
2
2
  require 'time'
3
+ require_relative './converter'
3
4
 
4
5
  module DuckDB
5
6
  if defined?(DuckDB::Appender)
@@ -13,6 +14,8 @@ module DuckDB
13
14
  # appender.append_row(1, 'Alice')
14
15
  #
15
16
  class Appender
17
+ include DuckDB::Converter
18
+
16
19
  RANGE_INT16 = -32_768..32_767
17
20
  RANGE_INT32 = -2_147_483_648..2_147_483_647
18
21
  RANGE_INT64 = -9_223_372_036_854_775_808..9_223_372_036_854_775_807
@@ -197,11 +200,7 @@ module DuckDB
197
200
  append_hugeint(value)
198
201
  end
199
202
  when String
200
- if defined?(DuckDB::Blob)
201
- blob?(value) ? append_blob(value) : append_varchar(value)
202
- else
203
- append_varchar(value)
204
- end
203
+ blob?(value) ? append_blob(value) : append_varchar(value)
205
204
  when TrueClass, FalseClass
206
205
  append_bool(value)
207
206
  when Time
@@ -246,53 +245,6 @@ module DuckDB
246
245
  def blob?(value)
247
246
  value.instance_of?(DuckDB::Blob) || value.encoding == Encoding::BINARY
248
247
  end
249
-
250
- def iso8601_interval_to_hash(value)
251
- digit = ''
252
- time = false
253
- hash = {}
254
- hash.default = 0
255
-
256
- value.each_char do |c|
257
- if '-0123456789.'.include?(c)
258
- digit += c
259
- elsif c == 'T'
260
- time = true
261
- digit = ''
262
- elsif c == 'M'
263
- m_interval_to_hash(hash, digit, time)
264
- digit = ''
265
- elsif c == 'S'
266
- s_interval_to_hash(hash, digit)
267
- digit = ''
268
- elsif 'YDH'.include?(c)
269
- hash[c] = digit.to_i
270
- digit = ''
271
- elsif c != 'P'
272
- raise ArgumentError, "The argument `#{value}` can't be parse."
273
- end
274
- end
275
- hash
276
- end
277
-
278
- def m_interval_to_hash(hash, digit, time)
279
- key = time ? 'TM' : 'M'
280
- hash[key] = digit.to_i
281
- end
282
-
283
- def s_interval_to_hash(hash, digit)
284
- sec, msec = digit.split('.')
285
- hash['S'] = sec.to_i
286
- hash['MS'] = "#{msec}000000"[0, 6].to_i
287
- hash['MS'] *= -1 if hash['S'].negative?
288
- end
289
-
290
- def hash_to__append_interval_args(hash)
291
- months = hash['Y'] * 12 + hash['M']
292
- days = hash['D']
293
- micros = (hash['H'] * 3600 + hash['TM'] * 60 + hash['S']) * 1_000_000 + hash['MS']
294
- [months, days, micros]
295
- end
296
248
  end
297
249
  end
298
250
  end
data/lib/duckdb/config.rb CHANGED
@@ -34,10 +34,7 @@ module DuckDB
34
34
  # configs['default_order'] # => "The order type used when none is specified ([ASC] or DESC)"
35
35
  #
36
36
  def key_descriptions
37
- return @key_descriptions if @key_descriptions
38
-
39
- n = size
40
- @key_descriptions = (0...n).each_with_object({}) do |i, hash|
37
+ @key_descriptions ||= (0...size).each_with_object({}) do |i, hash|
41
38
  key, description = key_description(i)
42
39
  hash[key] = description
43
40
  end
@@ -0,0 +1,52 @@
1
+ module DuckDB
2
+ module Converter
3
+ private
4
+
5
+ def iso8601_interval_to_hash(value)
6
+ digit = ''
7
+ time = false
8
+ hash = {}
9
+ hash.default = 0
10
+
11
+ value.each_char do |c|
12
+ if '-0123456789.'.include?(c)
13
+ digit += c
14
+ elsif c == 'T'
15
+ time = true
16
+ digit = ''
17
+ elsif c == 'M'
18
+ m_interval_to_hash(hash, digit, time)
19
+ digit = ''
20
+ elsif c == 'S'
21
+ s_interval_to_hash(hash, digit)
22
+ digit = ''
23
+ elsif 'YDH'.include?(c)
24
+ hash[c] = digit.to_i
25
+ digit = ''
26
+ elsif c != 'P'
27
+ raise ArgumentError, "The argument `#{value}` can't be parse."
28
+ end
29
+ end
30
+ hash
31
+ end
32
+
33
+ def m_interval_to_hash(hash, digit, time)
34
+ key = time ? 'TM' : 'M'
35
+ hash[key] = digit.to_i
36
+ end
37
+
38
+ def s_interval_to_hash(hash, digit)
39
+ sec, msec = digit.split('.')
40
+ hash['S'] = sec.to_i
41
+ hash['MS'] = "#{msec}000000"[0, 6].to_i
42
+ hash['MS'] *= -1 if hash['S'].negative?
43
+ end
44
+
45
+ def hash_to__append_interval_args(hash)
46
+ months = hash['Y'] * 12 + hash['M']
47
+ days = hash['D']
48
+ micros = (hash['H'] * 3600 + hash['TM'] * 60 + hash['S']) * 1_000_000 + hash['MS']
49
+ [months, days, micros]
50
+ end
51
+ end
52
+ end
@@ -1,4 +1,5 @@
1
1
  require 'date'
2
+ require_relative './converter'
2
3
 
3
4
  module DuckDB
4
5
  # The DuckDB::PreparedStatement encapsulates connection with DuckDB prepared
@@ -12,6 +13,7 @@ module DuckDB
12
13
  # stmt.bind(1, 'email@example.com')
13
14
  # stmt.execute
14
15
  class PreparedStatement
16
+ include DuckDB::Converter
15
17
 
16
18
  RANGE_INT16 = -32768..32767
17
19
  RANGE_INT32 = -2147483648..2147483647
@@ -27,8 +29,114 @@ module DuckDB
27
29
  end
28
30
 
29
31
  # binds i-th parameter with SQL prepared statement.
30
- # The first argument is index of parameter. The index of first parameter is
31
- # 1 not 0.
32
+ # The first argument is index of parameter.
33
+ # The index of first parameter is 1 not 0.
34
+ # The second argument value is to expected date.
35
+ #
36
+ # require 'duckdb'
37
+ # db = DuckDB::Database.open('duckdb_database')
38
+ # con = db.connect
39
+ # sql ='SELECT name FROM users WHERE birth_day = ?'
40
+ # stmt = PreparedStatement.new(con, sql)
41
+ # stmt.bind(1, Date.today)
42
+ # # or you can specify date string.
43
+ # # stmt.bind(1, '2021-02-23')
44
+ def bind_date(i, value)
45
+ case value
46
+ when Date, Time
47
+ date = value
48
+ else
49
+ begin
50
+ date = Date.parse(value)
51
+ rescue => e
52
+ raise(ArgumentError, "Cannot parse argument value to date. #{e.message}")
53
+ end
54
+ end
55
+
56
+ _bind_date(i, date.year, date.month, date.day)
57
+ end
58
+
59
+ # binds i-th parameter with SQL prepared statement.
60
+ # The first argument is index of parameter.
61
+ # The index of first parameter is 1 not 0.
62
+ # The second argument value is to expected time value.
63
+ #
64
+ # require 'duckdb'
65
+ # db = DuckDB::Database.open('duckdb_database')
66
+ # con = db.connect
67
+ # sql ='SELECT name FROM users WHERE birth_time = ?'
68
+ # stmt = PreparedStatement.new(con, sql)
69
+ # stmt.bind(1, Time.now)
70
+ # # or you can specify time string.
71
+ # # stmt.bind(1, '07:39:45')
72
+ def bind_time(i, value)
73
+ case value
74
+ when Time
75
+ time = value
76
+ else
77
+ begin
78
+ time = Time.parse(value)
79
+ rescue => e
80
+ raise(ArgumentError, "Cannot parse argument value to time. #{e.message}")
81
+ end
82
+ end
83
+
84
+ _bind_time(i, time.hour, time.min, time.sec, time.usec)
85
+ end
86
+
87
+ # binds i-th parameter with SQL prepared statement.
88
+ # The first argument is index of parameter.
89
+ # The index of first parameter is 1 not 0.
90
+ # The second argument value is to expected time value.
91
+ #
92
+ # require 'duckdb'
93
+ # db = DuckDB::Database.open('duckdb_database')
94
+ # con = db.connect
95
+ # sql ='SELECT name FROM users WHERE created_at = ?'
96
+ # stmt = PreparedStatement.new(con, sql)
97
+ # stmt.bind(1, Time.now)
98
+ # # or you can specify timestamp string.
99
+ # # stmt.bind(1, '2022-02-23 07:39:45')
100
+ def bind_timestamp(i, value)
101
+ case value
102
+ when Time
103
+ time = value
104
+ else
105
+ begin
106
+ time = Time.parse(value)
107
+ rescue => e
108
+ raise(ArgumentError, "Cannot parse argument value to time. #{e.message}")
109
+ end
110
+ end
111
+
112
+ _bind_timestamp(i, time.year, time.month, time.day, time.hour, time.min, time.sec, time.usec)
113
+ end
114
+
115
+ # binds i-th parameter with SQL prepared statement.
116
+ # The first argument is index of parameter.
117
+ # The index of first parameter is 1 not 0.
118
+ # The second argument value is to expected ISO8601 time interval string.
119
+ #
120
+ # require 'duckdb'
121
+ # db = DuckDB::Database.open('duckdb_database')
122
+ # con = db.connect
123
+ # sql ='SELECT value FROM intervals WHERE interval = ?'
124
+ # stmt = PreparedStatement.new(con, sql)
125
+ # stmt.bind(1, 'P1Y2D')
126
+ def bind_interval(i, value)
127
+ raise(DuckDB::Error, 'bind_interval is not available with your duckdb version. please install duckdb latest version at first') unless respond_to?(:_bind_interval, true)
128
+ raise ArgumentError, "Argument `#{value}` must be a string." unless value.is_a?(String)
129
+
130
+ hash = iso8601_interval_to_hash(value)
131
+
132
+ months, days, micros = hash_to__append_interval_args(hash)
133
+
134
+ _bind_interval(i, months, days, micros)
135
+ end
136
+
137
+ # binds i-th parameter with SQL prepared statement.
138
+ # The first argument is index of parameter.
139
+ # The index of first parameter is 1 not 0.
32
140
  # The second argument value is the value of prepared statement parameter.
33
141
  #
34
142
  # require 'duckdb'
@@ -40,7 +148,7 @@ module DuckDB
40
148
  def bind(i, value)
41
149
  case value
42
150
  when NilClass
43
- respond_to?(:bind_null) ? bind_null(i) : raise(DuckDB::Error, 'This bind method does not support nil value. Re-compile ruby-duckdb with DuckDB version >= 0.1.1')
151
+ bind_null(i)
44
152
  when Float
45
153
  bind_double(i, value)
46
154
  when Integer
@@ -51,11 +159,7 @@ module DuckDB
51
159
  bind_varchar(i, value.to_s)
52
160
  end
53
161
  when String
54
- if defined?(DuckDB::Blob)
55
- blob?(value) ? bind_blob(i, value) : bind_varchar(i, value)
56
- else
57
- bind_varchar(i, value)
58
- end
162
+ blob?(value) ? bind_blob(i, value) : bind_varchar(i, value)
59
163
  when TrueClass, FalseClass
60
164
  bind_bool(i, value)
61
165
  when Time
@@ -1,5 +1,5 @@
1
1
  module DuckDB
2
2
  # The version string of ruby-duckdb.
3
3
  # Currently, ruby-duckdb is NOT semantic versioning.
4
- VERSION = '0.3.1.0'.freeze
4
+ VERSION = '0.3.2.0'.freeze
5
5
  end
data/lib/duckdb.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'duckdb/duckdb_native'
2
2
  require 'duckdb/version'
3
+ require 'duckdb/converter'
3
4
  require 'duckdb/database'
4
5
  require 'duckdb/connection'
5
6
  require 'duckdb/result'
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.3.1.0
4
+ version: 0.3.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masaki Suketa
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-20 00:00:00.000000000 Z
11
+ date: 2022-02-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -108,10 +108,13 @@ files:
108
108
  - ext/duckdb/result.c
109
109
  - ext/duckdb/result.h
110
110
  - ext/duckdb/ruby-duckdb.h
111
+ - ext/duckdb/util.c
112
+ - ext/duckdb/util.h
111
113
  - lib/duckdb.rb
112
114
  - lib/duckdb/appender.rb
113
115
  - lib/duckdb/config.rb
114
116
  - lib/duckdb/connection.rb
117
+ - lib/duckdb/converter.rb
115
118
  - lib/duckdb/database.rb
116
119
  - lib/duckdb/prepared_statement.rb
117
120
  - lib/duckdb/result.rb
@@ -138,7 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
138
141
  - !ruby/object:Gem::Version
139
142
  version: '0'
140
143
  requirements: []
141
- rubygems_version: 3.2.22
144
+ rubygems_version: 3.3.7
142
145
  signing_key:
143
146
  specification_version: 4
144
147
  summary: This module is Ruby binding for DuckDB database engine.