duckdb 0.3.1.0 → 0.3.2.0

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