duckdb 0.0.5 → 0.0.6

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: 599ebecd3f693be06ff46fec535485d6ac6019cd889405a502d21a2f801c9ba8
4
- data.tar.gz: '0811911b5f0c3404f8c7ff9c2351d97668013dd576d4f5a98775e9af45df5e52'
3
+ metadata.gz: 74313dca99b11539431ecfe95cdd3f6392e0993776f292487991cf02e654f78f
4
+ data.tar.gz: 151e355bd98be14256b1e78e02eeb7c60dff12e1f2a7ef875e3e9604b7bfb2b3
5
5
  SHA512:
6
- metadata.gz: b4ca8e956de0edbb9aa9ceed9273a48f3cf847e5ff79732b849465c59fa2030af5cd81c62344e953e96990e11c48ff1b2dd8bd3cd87f3bc8271079aeb69a31bd
7
- data.tar.gz: 3501865c8c0aa7c70761705e06026aadd95e112d34fd9eed1152ae269407fddc7cdbe6a84f6f3f8cda917022bda45fb0d349b51400b939f43b74ae64bb8e43bf
6
+ metadata.gz: 6da56e491796d920c3c330d5dd2941b6b23f119ebb0bfed4f8e5ae25e2d2f1a83445cd06cd9d0dfab55a19184b9ed6302f04d2f61c038c8352fec8c0ebc60372
7
+ data.tar.gz: 8e6f30d324473da40e4e65c7ec8d6a96625eefa835647d8412cc8a8755b5cc29246100ddb2f48f42cc60f006927af4d8b1373b2c1c3e2e6c98f2f891d83fa8e4
@@ -0,0 +1,66 @@
1
+ name: Ubuntu
2
+
3
+ on: [push]
4
+
5
+ jobs:
6
+ build:
7
+
8
+ runs-on: ubuntu-latest
9
+ strategy:
10
+ matrix:
11
+ ruby: ['2.5.x', '2.6.x']
12
+ duckdb: ['0.1.2', '0.1.3']
13
+
14
+ steps:
15
+ - uses: actions/checkout@v1
16
+
17
+ - name: Set up Ruby
18
+ uses: actions/setup-ruby@v1
19
+ with:
20
+ ruby-version: ${{ matrix.ruby }}
21
+
22
+ - name: duckdb 0.1.2 cache
23
+ id: duckdb-cache-v0_1_2
24
+ uses: actions/cache@v1.1.0
25
+ with:
26
+ path: duckdb-v0.1.2
27
+ key: ${{ runner.os }}-duckdb-v0_1_2_007
28
+ restore-keys: |
29
+ ${{ runner.os }}-duckdb-v0_1_2
30
+
31
+ - name: Build duckdb 0.1.2
32
+ if: steps.duckdb-cache-v0_1_2.outputs.cache-hit != 'true'
33
+ run: |
34
+ git clone -b v0.1.2 https://github.com/cwida/duckdb.git duckdb-tmp-v0.1.2
35
+ cd duckdb-tmp-v0.1.2 && make && cd ..
36
+ rm -rf duckdb-v0.1.2
37
+ mkdir -p duckdb-v0.1.2/build/release/src duckdb-v0.1.2/src
38
+ cp -rip duckdb-tmp-v0.1.2/build/release/src/*.so duckdb-v0.1.2/build/release/src
39
+ cp -rip duckdb-tmp-v0.1.2/src/include duckdb-v0.1.2/src/
40
+
41
+ - name: duckdb 0.1.3 cache
42
+ id: duckdb-cache-v0_1_3
43
+ uses: actions/cache@v1.1.0
44
+ with:
45
+ path: duckdb-v0.1.3
46
+ key: ${{ runner.os }}-duckdb-v0_1_3_001
47
+ restore-keys: |
48
+ ${{ runner.os }}-duckdb-v0_1_3
49
+
50
+ - name: Build duckdb 0.1.3
51
+ if: steps.duckdb-cache-v0_1_3.outputs.cache-hit != 'true'
52
+ run: |
53
+ git clone -b v0.1.3 https://github.com/cwida/duckdb.git duckdb-tmp-v0.1.3
54
+ cd duckdb-tmp-v0.1.3 && make && cd ..
55
+ rm -rf duckdb-v0.1.3
56
+ mkdir -p duckdb-v0.1.3/build/release/src duckdb-v0.1.3/src
57
+ cp -rip duckdb-tmp-v0.1.3/build/release/src/*.so duckdb-v0.1.3/build/release/src
58
+ cp -rip duckdb-tmp-v0.1.3/src/include duckdb-v0.1.3/src/
59
+
60
+ - name: Build and test with Rake with Ruby ${{ matrix.ruby }}
61
+ env:
62
+ DUCKDB_VERSION: ${{ matrix.duckdb }}
63
+ run: |
64
+ gem install bundler
65
+ bundle install --jobs 4 --retry 3
66
+ bundle exec rake -- --with-duckdb-include=${GITHUB_WORKSPACE}/duckdb-v${DUCKDB_VERSION}/src/include --with-duckdb-lib=${GITHUB_WORKSPACE}/duckdb-v${DUCKDB_VERSION}/build/release/src/
data/.travis.yml ADDED
@@ -0,0 +1,20 @@
1
+ language: ruby
2
+ cache:
3
+ bundler: true
4
+ directories:
5
+ - ${HOME}/duckdb-v0.1.2
6
+ - ${HOME}/duckdb-v0.1.3
7
+ before_install:
8
+ - yes | gem update --system
9
+ - if [[ ! -d ${HOME}/duckdb-v0.1.2/build ]]; then cd ${HOME} && git clone -b v0.1.2 https://github.com/cwida/duckdb.git duckdb-v0.1.2 && cd duckdb-v0.1.2 && make && cd ${TRAVIS_BUILD_DIR}; fi
10
+ - if [[ ! -d ${HOME}/duckdb-v0.1.3/build ]]; then cd ${HOME} && git clone -b v0.1.3 https://github.com/cwida/duckdb.git duckdb-v0.1.3 && cd duckdb-v0.1.3 && make && cd ${TRAVIS_BUILD_DIR}; fi
11
+
12
+ env:
13
+ - DUCKDB_VERSION=0.1.2
14
+ - DUCKDB_VERSION=0.1.3
15
+ rvm:
16
+ - 2.5.7
17
+ - 2.6.5
18
+ - 2.7.0
19
+ - ruby-head
20
+ script: bundle exec rake -- --with-duckdb-include=${HOME}/duckdb-v${DUCKDB_VERSION}/src/include --with-duckdb-lib=${HOME}/duckdb-v${DUCKDB_VERSION}/build/release/src/
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # ChangeLog
2
2
 
3
+ ## 0.0.6
4
+
5
+ - add alias `execute` of `DuckDB::Connection#query`
6
+ - support `duckdb version 0.1.3`
7
+ - add `DuckDB:PreparedStatement`
8
+ - create CI (GitHub Actions / Travis-CI)
9
+ - create database only once in result_test.rb
10
+
3
11
  ## 0.0.5
4
12
 
5
13
  - add `DuckDB::Error`
data/Gemfile.lock CHANGED
@@ -1,14 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- duckdb (0.0.5)
4
+ duckdb (0.0.6)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
9
  minitest (5.13.0)
10
- rake (10.5.0)
11
- rake-compiler (1.0.8)
10
+ rake (13.0.1)
11
+ rake-compiler (1.1.0)
12
12
  rake
13
13
 
14
14
  PLATFORMS
@@ -18,8 +18,8 @@ DEPENDENCIES
18
18
  bundler (~> 2.0)
19
19
  duckdb!
20
20
  minitest (~> 5.0)
21
- rake (~> 10.0)
21
+ rake (~> 13.0)
22
22
  rake-compiler
23
23
 
24
24
  BUNDLED WITH
25
- 2.0.2
25
+ 2.1.4
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # ruby-duckdb
2
2
 
3
+ [![Build Status](https://travis-ci.com/suketa/ruby-duckdb.svg?branch=master)](https://travis-ci.com/suketa/ruby-duckdb)
4
+ [![](https://github.com/suketa/ruby-duckdb/workflows/Ubuntu/badge.svg)](https://github.com/suketa/ruby-duckdb/actions?query=workflow%3AUbuntu)
3
5
 
4
6
  ## Description
5
7
 
data/duckdb.gemspec CHANGED
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
26
26
  spec.extensions = ["ext/duckdb/extconf.rb"]
27
27
 
28
28
  spec.add_development_dependency "bundler", "~> 2.0"
29
- spec.add_development_dependency "rake", "~> 10.0"
29
+ spec.add_development_dependency "rake", "~> 13.0"
30
30
  spec.add_development_dependency "rake-compiler"
31
31
  spec.add_development_dependency "minitest", "~> 5.0"
32
32
  end
@@ -1,7 +1,5 @@
1
1
  #include "ruby-duckdb.h"
2
2
 
3
- static VALUE cDuckDBConnection;
4
-
5
3
  static void deallocate(void *ctx)
6
4
  {
7
5
  rubyDuckDBConnection *p = (rubyDuckDBConnection *)ctx;
@@ -16,7 +14,8 @@ static VALUE allocate(VALUE klass)
16
14
  return Data_Wrap_Struct(klass, NULL, deallocate, ctx);
17
15
  }
18
16
 
19
- VALUE create_connection(VALUE oDuckDBDatabase) {
17
+ VALUE create_connection(VALUE oDuckDBDatabase)
18
+ {
20
19
  rubyDuckDB *ctxdb;
21
20
  rubyDuckDBConnection *ctxcon;
22
21
  VALUE obj;
@@ -34,8 +33,8 @@ VALUE create_connection(VALUE oDuckDBDatabase) {
34
33
  return obj;
35
34
  }
36
35
 
37
- static VALUE duckdb_connection_query(VALUE self, VALUE str) {
38
-
36
+ static VALUE duckdb_connection_query_sql(VALUE self, VALUE str)
37
+ {
39
38
  rubyDuckDBConnection *ctx;
40
39
  rubyDuckDBResult *ctxr;
41
40
 
@@ -55,5 +54,5 @@ void init_duckdb_connection(void)
55
54
  cDuckDBConnection = rb_define_class_under(mDuckDB, "Connection", rb_cObject);
56
55
  rb_define_alloc_func(cDuckDBConnection, allocate);
57
56
 
58
- rb_define_method(cDuckDBConnection, "query", duckdb_connection_query, 1);
57
+ rb_define_private_method(cDuckDBConnection, "query_sql", duckdb_connection_query_sql, 1);
59
58
  }
@@ -7,6 +7,8 @@ struct _rubyDuckDBConnection {
7
7
 
8
8
  typedef struct _rubyDuckDBConnection rubyDuckDBConnection;
9
9
 
10
+ VALUE cDuckDBConnection;
11
+
10
12
  void init_duckdb_connection(void);
11
13
  VALUE create_connection(VALUE oDuckDBDatabase);
12
14
 
@@ -36,11 +36,13 @@ static VALUE duckdb_database_s_open(int argc, VALUE *argv, VALUE cDuckDBDatabase
36
36
  return obj;
37
37
  }
38
38
 
39
- static VALUE duckdb_database_connect(VALUE self) {
39
+ static VALUE duckdb_database_connect(VALUE self)
40
+ {
40
41
  return create_connection(self);
41
42
  }
42
43
 
43
- void init_duckdb_database(void) {
44
+ void init_duckdb_database(void)
45
+ {
44
46
  VALUE cDuckDBDatabase = rb_define_class_under(mDuckDB, "Database", rb_cObject);
45
47
  rb_define_alloc_func(cDuckDBDatabase, allocate);
46
48
  rb_define_singleton_method(cDuckDBDatabase, "open", duckdb_database_s_open, -1);
data/ext/duckdb/duckdb.c CHANGED
@@ -3,11 +3,13 @@
3
3
  VALUE mDuckDB;
4
4
 
5
5
  void
6
- Init_duckdb_native(void) {
6
+ Init_duckdb_native(void)
7
+ {
7
8
  mDuckDB = rb_define_module("DuckDB");
8
9
 
9
10
  init_duckdb_error();
10
11
  init_duckdb_database();
11
12
  init_duckdb_connection();
12
13
  init_duckdb_result();
14
+ init_duckdb_prepared_statement();
13
15
  }
data/ext/duckdb/error.c CHANGED
@@ -1,5 +1,6 @@
1
1
  #include "ruby-duckdb.h"
2
2
 
3
- void init_duckdb_error(void) {
3
+ void init_duckdb_error(void)
4
+ {
4
5
  eDuckDBError = rb_define_class_under(mDuckDB, "Error", rb_eStandardError);
5
6
  }
@@ -1,5 +1,7 @@
1
1
  require 'mkmf'
2
2
 
3
3
  dir_config('duckdb')
4
- have_library('duckdb')
5
- create_makefile('duckdb/duckdb_native')
4
+ if have_library('duckdb')
5
+ have_func('duckdb_bind_null', 'duckdb.h')
6
+ create_makefile('duckdb/duckdb_native')
7
+ end
@@ -0,0 +1,205 @@
1
+ #include "ruby-duckdb.h"
2
+
3
+ static VALUE cDuckDBPreparedStatement;
4
+
5
+ static void deallocate(void *ctx)
6
+ {
7
+ rubyDuckDBPreparedStatement *p = (rubyDuckDBPreparedStatement *)ctx;
8
+
9
+ duckdb_destroy_prepare(&(p->prepared_statement));
10
+ xfree(p);
11
+ }
12
+
13
+ static VALUE allocate(VALUE klass)
14
+ {
15
+ rubyDuckDBPreparedStatement *ctx = xcalloc((size_t)1, sizeof(rubyDuckDBPreparedStatement));
16
+ return Data_Wrap_Struct(klass, NULL, deallocate, ctx);
17
+ }
18
+
19
+ static VALUE duckdb_prepared_statement_initialize(VALUE self, VALUE con, VALUE query)
20
+ {
21
+ rubyDuckDBConnection *ctxcon;
22
+ rubyDuckDBPreparedStatement *ctx;
23
+
24
+ if (!rb_obj_is_kind_of(con, cDuckDBConnection)) {
25
+ rb_raise(rb_eTypeError, "1st argument should be instance of DackDB::Connection");
26
+ }
27
+
28
+ Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
29
+ Data_Get_Struct(con, rubyDuckDBConnection, ctxcon);
30
+
31
+ if (duckdb_prepare(ctxcon->con, StringValuePtr(query), &(ctx->prepared_statement)) == DuckDBError) {
32
+ /* TODO: include query parameter information in error message. */
33
+ rb_raise(eDuckDBError, "failed to prepare statement");
34
+ }
35
+ return self;
36
+ }
37
+
38
+ static VALUE duckdb_prepared_statement_nparams(VALUE self)
39
+ {
40
+ rubyDuckDBPreparedStatement *ctx;
41
+ Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
42
+
43
+ if (duckdb_nparams(ctx->prepared_statement, &(ctx->nparams)) == DuckDBError) {
44
+ rb_raise(eDuckDBError, "failed to get number of parameters");
45
+ }
46
+ return rb_int2big(ctx->nparams);
47
+ }
48
+
49
+
50
+ static VALUE duckdb_prepared_statement_execute(VALUE self)
51
+ {
52
+ rubyDuckDBPreparedStatement *ctx;
53
+ rubyDuckDBResult *ctxr;
54
+ VALUE result = create_result();
55
+
56
+ Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
57
+ Data_Get_Struct(result, rubyDuckDBResult, ctxr);
58
+ if (duckdb_execute_prepared(ctx->prepared_statement, &(ctxr->result)) == DuckDBError) {
59
+ rb_raise(eDuckDBError, "%s", ctxr->result.error_message);
60
+ }
61
+ return result;
62
+ }
63
+
64
+ static index_t check_index(VALUE vidx)
65
+ {
66
+ index_t idx = FIX2INT(vidx);
67
+ if (idx <= 0) {
68
+ rb_raise(rb_eArgError, "index of parameter must be greater than 0");
69
+ }
70
+ return idx;
71
+ }
72
+
73
+ static VALUE duckdb_prepared_statement_bind_boolean(VALUE self, VALUE vidx, VALUE val)
74
+ {
75
+ rubyDuckDBPreparedStatement *ctx;
76
+ index_t idx = check_index(vidx);
77
+
78
+ Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
79
+ if (val != Qtrue && val != Qfalse) {
80
+ rb_raise(rb_eArgError, "binding value must be boolean");
81
+ }
82
+
83
+ if (duckdb_bind_boolean(ctx->prepared_statement, idx, (val == Qtrue)) == DuckDBError) {
84
+ rb_raise(eDuckDBError, "fail to bind %ld parameter", idx);
85
+ }
86
+ return self;
87
+ }
88
+
89
+ static VALUE duckdb_prepared_statement_bind_int16(VALUE self, VALUE vidx, VALUE val)
90
+ {
91
+ rubyDuckDBPreparedStatement *ctx;
92
+ index_t idx = check_index(vidx);
93
+ int16_t i16val = NUM2INT(val);
94
+
95
+ Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
96
+
97
+ if (duckdb_bind_int16(ctx->prepared_statement, idx, i16val) == DuckDBError) {
98
+ rb_raise(eDuckDBError, "fail to bind %ld parameter", idx);
99
+ }
100
+ return self;
101
+ }
102
+
103
+ static VALUE duckdb_prepared_statement_bind_int32(VALUE self, VALUE vidx, VALUE val)
104
+ {
105
+ rubyDuckDBPreparedStatement *ctx;
106
+ index_t idx = check_index(vidx);
107
+ int32_t i32val = NUM2LONG(val);
108
+
109
+ Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
110
+
111
+ if (duckdb_bind_int32(ctx->prepared_statement, idx, i32val) == DuckDBError) {
112
+ rb_raise(eDuckDBError, "fail to bind %ld parameter", idx);
113
+ }
114
+ return self;
115
+ }
116
+
117
+ static VALUE duckdb_prepared_statement_bind_int64(VALUE self, VALUE vidx, VALUE val)
118
+ {
119
+ rubyDuckDBPreparedStatement *ctx;
120
+ index_t idx = check_index(vidx);
121
+ int64_t i64val = NUM2LL(val);
122
+
123
+ Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
124
+
125
+ if (duckdb_bind_int64(ctx->prepared_statement, idx, i64val) == DuckDBError) {
126
+ rb_raise(eDuckDBError, "fail to bind %ld parameter", idx);
127
+ }
128
+ return self;
129
+ }
130
+
131
+ static VALUE duckdb_prepared_statement_bind_float(VALUE self, VALUE vidx, VALUE val)
132
+ {
133
+ rubyDuckDBPreparedStatement *ctx;
134
+ index_t idx = check_index(vidx);
135
+ double dbl = NUM2DBL(val);
136
+
137
+ Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
138
+
139
+ if (duckdb_bind_float(ctx->prepared_statement, idx, (float)dbl) == DuckDBError) {
140
+ rb_raise(eDuckDBError, "fail to bind %ld parameter", idx);
141
+ }
142
+ return self;
143
+ }
144
+
145
+ static VALUE duckdb_prepared_statement_bind_double(VALUE self, VALUE vidx, VALUE val)
146
+ {
147
+ rubyDuckDBPreparedStatement *ctx;
148
+ index_t idx = check_index(vidx);
149
+ double dbl = NUM2DBL(val);
150
+
151
+ Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
152
+
153
+ if (duckdb_bind_double(ctx->prepared_statement, idx, dbl) == DuckDBError) {
154
+ rb_raise(eDuckDBError, "fail to bind %ld parameter", idx);
155
+ }
156
+ return self;
157
+ }
158
+
159
+ static VALUE duckdb_prepared_statement_bind_varchar(VALUE self, VALUE vidx, VALUE str)
160
+ {
161
+ rubyDuckDBPreparedStatement *ctx;
162
+ index_t idx = check_index(vidx);
163
+
164
+ Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
165
+ if (duckdb_bind_varchar(ctx->prepared_statement, idx, StringValuePtr(str)) == DuckDBError) {
166
+ rb_raise(eDuckDBError, "fail to bind %ld parameter", idx);
167
+ }
168
+ return self;
169
+ }
170
+
171
+ #ifdef HAVE_DUCKDB_BIND_NULL
172
+ static VALUE duckdb_prepared_statement_bind_null(VALUE self, VALUE vidx)
173
+ {
174
+ rubyDuckDBPreparedStatement *ctx;
175
+ index_t idx = check_index(vidx);
176
+
177
+ Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
178
+ if (duckdb_bind_null(ctx->prepared_statement, idx) == DuckDBError) {
179
+ rb_raise(eDuckDBError, "fail to bind %ld parameter", idx);
180
+ }
181
+ return self;
182
+ }
183
+ #endif
184
+
185
+ void init_duckdb_prepared_statement(void)
186
+ {
187
+ cDuckDBPreparedStatement = rb_define_class_under(mDuckDB, "PreparedStatement", rb_cObject);
188
+
189
+ rb_define_alloc_func(cDuckDBPreparedStatement, allocate);
190
+
191
+ rb_define_method(cDuckDBPreparedStatement, "initialize", duckdb_prepared_statement_initialize, 2);
192
+ rb_define_method(cDuckDBPreparedStatement, "execute", duckdb_prepared_statement_execute, 0);
193
+ rb_define_method(cDuckDBPreparedStatement, "nparams", duckdb_prepared_statement_nparams, 0);
194
+ rb_define_method(cDuckDBPreparedStatement, "bind_boolean", duckdb_prepared_statement_bind_boolean, 2);
195
+ rb_define_method(cDuckDBPreparedStatement, "bind_int16", duckdb_prepared_statement_bind_int16, 2);
196
+ rb_define_method(cDuckDBPreparedStatement, "bind_int32", duckdb_prepared_statement_bind_int32, 2);
197
+ rb_define_method(cDuckDBPreparedStatement, "bind_int64", duckdb_prepared_statement_bind_int64, 2);
198
+ rb_define_method(cDuckDBPreparedStatement, "bind_float", duckdb_prepared_statement_bind_float, 2);
199
+ rb_define_method(cDuckDBPreparedStatement, "bind_double", duckdb_prepared_statement_bind_double, 2);
200
+ rb_define_method(cDuckDBPreparedStatement, "bind_varchar", duckdb_prepared_statement_bind_varchar, 2);
201
+ #ifdef HAVE_DUCKDB_BIND_NULL
202
+ /* duckdb version > 0.1.1 */
203
+ rb_define_method(cDuckDBPreparedStatement, "bind_null", duckdb_prepared_statement_bind_null, 1);
204
+ #endif
205
+ }
@@ -0,0 +1,13 @@
1
+ #ifndef RUBY_DUCKDB_PREPARED_STATEMENT_H
2
+ #define RUBY_DUCKDB_PREPARED_STATEMENT_H
3
+
4
+ struct _rubyDuckDBPreparedStatement {
5
+ duckdb_prepared_statement prepared_statement;
6
+ index_t nparams;
7
+ };
8
+
9
+ typedef struct _rubyDuckDBPreparedStatement rubyDuckDBPreparedStatement;
10
+
11
+ void init_duckdb_prepared_statement(void);
12
+
13
+ #endif
data/ext/duckdb/result.c CHANGED
@@ -16,37 +16,44 @@ static VALUE allocate(VALUE klass)
16
16
  return Data_Wrap_Struct(klass, NULL, deallocate, ctx);
17
17
  }
18
18
 
19
- static VALUE to_ruby_obj_boolean(duckdb_result *result, size_t col_idx, size_t row_idx) {
19
+ static VALUE to_ruby_obj_boolean(duckdb_result *result, index_t col_idx, index_t row_idx)
20
+ {
20
21
  bool bval = duckdb_value_boolean(result, col_idx, row_idx);
21
22
  return bval ? Qtrue : Qnil;
22
23
  }
23
24
 
24
- static VALUE to_ruby_obj_smallint(duckdb_result *result, size_t col_idx, size_t row_idx) {
25
+ static VALUE to_ruby_obj_smallint(duckdb_result *result, index_t col_idx, index_t row_idx)
26
+ {
25
27
  int16_t i16val = duckdb_value_int16(result, col_idx, row_idx);
26
28
  return INT2FIX(i16val);
27
29
  }
28
30
 
29
- static VALUE to_ruby_obj_integer(duckdb_result *result, size_t col_idx, size_t row_idx) {
31
+ static VALUE to_ruby_obj_integer(duckdb_result *result, index_t col_idx, index_t row_idx)
32
+ {
30
33
  int32_t i32val = duckdb_value_int32(result, col_idx, row_idx);
31
34
  return INT2NUM(i32val);
32
35
  }
33
36
 
34
- static VALUE to_ruby_obj_bigint(duckdb_result *result, size_t col_idx, size_t row_idx) {
37
+ static VALUE to_ruby_obj_bigint(duckdb_result *result, index_t col_idx, index_t row_idx)
38
+ {
35
39
  int64_t i64val = duckdb_value_int64(result, col_idx, row_idx);
36
40
  return rb_int2big(i64val);
37
41
  }
38
42
 
39
- static VALUE to_ruby_obj_float(duckdb_result *result, size_t col_idx, size_t row_idx) {
43
+ static VALUE to_ruby_obj_float(duckdb_result *result, index_t col_idx, index_t row_idx)
44
+ {
40
45
  float fval = duckdb_value_float(result, col_idx, row_idx);
41
46
  return DBL2NUM(fval);
42
47
  }
43
48
 
44
- static VALUE to_ruby_obj_double(duckdb_result *result, size_t col_idx, size_t row_idx) {
49
+ static VALUE to_ruby_obj_double(duckdb_result *result, index_t col_idx, index_t row_idx)
50
+ {
45
51
  double dval = duckdb_value_double(result, col_idx, row_idx);
46
52
  return DBL2NUM(dval);
47
53
  }
48
54
 
49
- static VALUE to_ruby_obj(duckdb_result *result, size_t col_idx, size_t row_idx) {
55
+ static VALUE to_ruby_obj(duckdb_result *result, index_t col_idx, index_t row_idx)
56
+ {
50
57
  char *p;
51
58
  VALUE obj = Qnil;
52
59
  if (result->columns[col_idx].nullmask[row_idx]) {
@@ -73,8 +80,9 @@ static VALUE to_ruby_obj(duckdb_result *result, size_t col_idx, size_t row_idx)
73
80
  return obj;
74
81
  }
75
82
 
76
- static VALUE row_array(rubyDuckDBResult *ctx, size_t row_idx) {
77
- size_t col_idx;
83
+ static VALUE row_array(rubyDuckDBResult *ctx, index_t row_idx)
84
+ {
85
+ index_t col_idx;
78
86
  VALUE ary = rb_ary_new2(ctx->result.column_count);
79
87
  for(col_idx = 0; col_idx < ctx->result.column_count; col_idx++) {
80
88
  rb_ary_store(ary, col_idx, to_ruby_obj(&(ctx->result), col_idx, row_idx));
@@ -82,16 +90,18 @@ static VALUE row_array(rubyDuckDBResult *ctx, size_t row_idx) {
82
90
  return ary;
83
91
  }
84
92
 
85
- static VALUE duckdb_result_row_size(VALUE oDuckDBResult, VALUE args, VALUE obj) {
93
+ static VALUE duckdb_result_row_size(VALUE oDuckDBResult, VALUE args, VALUE obj)
94
+ {
86
95
  rubyDuckDBResult *ctx;
87
96
  Data_Get_Struct(oDuckDBResult, rubyDuckDBResult, ctx);
88
97
 
89
98
  return LONG2FIX(ctx->result.row_count);
90
99
  }
91
100
 
92
- static VALUE duckdb_result_each(VALUE oDuckDBResult) {
101
+ static VALUE duckdb_result_each(VALUE oDuckDBResult)
102
+ {
93
103
  rubyDuckDBResult *ctx;
94
- size_t row_idx = 0;
104
+ index_t row_idx = 0;
95
105
 
96
106
  RETURN_SIZED_ENUMERATOR(oDuckDBResult, 0, 0, duckdb_result_row_size);
97
107
 
@@ -102,7 +112,8 @@ static VALUE duckdb_result_each(VALUE oDuckDBResult) {
102
112
  return oDuckDBResult;
103
113
  }
104
114
 
105
- VALUE create_result(void) {
115
+ VALUE create_result(void)
116
+ {
106
117
  return allocate(cDuckDBResult);
107
118
  }
108
119
 
@@ -7,6 +7,7 @@
7
7
  #include "./database.h"
8
8
  #include "./connection.h"
9
9
  #include "./result.h"
10
+ #include "./prepared_statement.h"
10
11
 
11
12
  extern VALUE mDuckDB;
12
13
 
data/lib/duckdb.rb CHANGED
@@ -1,6 +1,10 @@
1
1
  require 'duckdb/version'
2
+ require 'duckdb/database'
3
+ require 'duckdb/connection'
2
4
  require 'duckdb/duckdb_native'
3
5
  require 'duckdb/result'
6
+ require 'duckdb/prepared_statement'
4
7
 
8
+ # DuckDB provides Ruby interface of DuckDB.
5
9
  module DuckDB
6
10
  end
@@ -0,0 +1,34 @@
1
+ module DuckDB
2
+ # The DuckDB::Connection encapsulates connection with DuckDB database.
3
+ #
4
+ # require 'duckdb'
5
+ # db = DuckDB::Database.open
6
+ # con = db.connect
7
+ # con.query(sql)
8
+ class Connection
9
+ #
10
+ # executes sql with args.
11
+ # The first argument sql must be SQL string.
12
+ # The rest arguments are parameters of SQL string.
13
+ # The parameters must be '?' in SQL statement.
14
+ #
15
+ # require 'duckdb'
16
+ # db = DuckDB::Database.open('duckdb_file')
17
+ # con = db.connect
18
+ # users = con.query('SELECT * FROM users')
19
+ # sql = 'SELECT * FROM users WHERE name = ? AND email = ?'
20
+ # dave = con.query(sql, 'Dave', 'dave@example.com')
21
+ #
22
+ def query(sql, *args)
23
+ return query_sql(sql) if args.empty?
24
+
25
+ stmt = PreparedStatement.new(self, sql)
26
+ args.each_with_index do |arg, i|
27
+ stmt.bind(i + 1, arg)
28
+ end
29
+ stmt.execute
30
+ end
31
+
32
+ alias execute query
33
+ end
34
+ end
@@ -0,0 +1,24 @@
1
+ module DuckDB
2
+ # The Database class encapsulates a DuckDB database.
3
+ #
4
+ # The usage is as follows:
5
+ #
6
+ # require 'duckdb'
7
+ #
8
+ # db = DuckDB::Database.open # database in memory
9
+ # con = db.connect
10
+ #
11
+ # con.query('CREATE TABLE users (id INTEGER, name VARCHAR(30))')
12
+ #
13
+ # con.query("INSERT into users VALUES(1, 'Alice')")
14
+ # con.query("INSERT into users VALUES(2, 'Bob')")
15
+ # con.query("INSERT into users VALUES(3, 'Cathy')")
16
+ #
17
+ # result = con.query('SELECT * from users')
18
+ # result.each do |row|
19
+ # p row
20
+ # end
21
+ #
22
+ class Database
23
+ end
24
+ end
@@ -0,0 +1,48 @@
1
+ require 'date'
2
+
3
+ module DuckDB
4
+ # The DuckDB::PreparedStatement encapsulates connection with DuckDB prepared
5
+ # statement.
6
+ #
7
+ # require 'duckdb'
8
+ # db = DuckDB::Database.open('duckdb_database')
9
+ # con = db.connect
10
+ # sql ='SELECT name, email FROM users WHERE email = ?'
11
+ # stmt = PreparedStatement.new(con, sql)
12
+ # stmt.bind(1, 'email@example.com')
13
+ # stmt.execute
14
+ class PreparedStatement
15
+
16
+ # binds i-th parameter with SQL prepared statement.
17
+ # The first argument is index of parameter. The index of first parameter is
18
+ # 1 not 0.
19
+ # The second argument value is the value of prepared statement parameter.
20
+ #
21
+ # require 'duckdb'
22
+ # db = DuckDB::Database.open('duckdb_database')
23
+ # con = db.connect
24
+ # sql ='SELECT name, email FROM users WHERE email = ?'
25
+ # stmt = PreparedStatement.new(con, sql)
26
+ # stmt.bind(1, 'email@example.com')
27
+ def bind(i, value)
28
+ case value
29
+ when NilClass
30
+ respond_to?(:bind_null) ? bind_null(i) : rb_raise(DuckDB::Error, 'This bind method does not support nil value. Re-compile ruby-duckdb with DuckDB version >= 0.1.1')
31
+ when Float
32
+ bind_double(i, value)
33
+ when Integer
34
+ bind_int64(i, value)
35
+ when String
36
+ bind_varchar(i, value)
37
+ when TrueClass, FalseClass
38
+ bind_boolean(i, value)
39
+ when Time
40
+ bind_varchar(i, value.strftime('%Y-%m-%d %H:%M:%S.%N'))
41
+ when Date
42
+ bind_varchar(i, value.strftime('%Y-%m-%d'))
43
+ else
44
+ rb_raise(DuckDB::Error, "not supported type #{value} (value.class)")
45
+ end
46
+ end
47
+ end
48
+ end
data/lib/duckdb/result.rb CHANGED
@@ -1,4 +1,23 @@
1
1
  module DuckDB
2
+ # The Result class encapsulates a execute result of DuckDB database.
3
+ #
4
+ # The usage is as follows:
5
+ #
6
+ # require 'duckdb'
7
+ #
8
+ # db = DuckDB::Database.open # database in memory
9
+ # con = db.connect
10
+ #
11
+ # con.execute('CREATE TABLE users (id INTEGER, name VARCHAR(30))')
12
+ #
13
+ # con.execute("INSERT into users VALUES(1, 'Alice')")
14
+ # con.execute("INSERT into users VALUES(2, 'Bob')")
15
+ # con.execute("INSERT into users VALUES(3, 'Cathy')")
16
+ #
17
+ # result = con.execute('SELECT * from users')
18
+ # result.each do |row|
19
+ # p row
20
+ # end
2
21
  class Result
3
22
  include Enumerable
4
23
  end
@@ -1,3 +1,5 @@
1
1
  module DuckDB
2
- VERSION = '0.0.5'.freeze
2
+ # The version string of ruby-duckdb.
3
+ # Currently, ruby-duckdb is NOT semantic versioning.
4
+ VERSION = '0.0.6'.freeze
3
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: duckdb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masaki Suketa
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-11-04 00:00:00.000000000 Z
11
+ date: 2020-02-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '13.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '13.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake-compiler
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -75,14 +75,15 @@ extensions:
75
75
  - ext/duckdb/extconf.rb
76
76
  extra_rdoc_files: []
77
77
  files:
78
+ - ".github/workflows/test_by_github.yml"
78
79
  - ".gitignore"
80
+ - ".travis.yml"
79
81
  - CHANGELOG.md
80
82
  - Gemfile
81
83
  - Gemfile.lock
82
84
  - LICENSE
83
85
  - README.md
84
86
  - Rakefile
85
- - TODO
86
87
  - bin/console
87
88
  - bin/setup
88
89
  - duckdb.gemspec
@@ -94,10 +95,15 @@ files:
94
95
  - ext/duckdb/error.c
95
96
  - ext/duckdb/error.h
96
97
  - ext/duckdb/extconf.rb
98
+ - ext/duckdb/prepared_statement.c
99
+ - ext/duckdb/prepared_statement.h
97
100
  - ext/duckdb/result.c
98
101
  - ext/duckdb/result.h
99
102
  - ext/duckdb/ruby-duckdb.h
100
103
  - lib/duckdb.rb
104
+ - lib/duckdb/connection.rb
105
+ - lib/duckdb/database.rb
106
+ - lib/duckdb/prepared_statement.rb
101
107
  - lib/duckdb/result.rb
102
108
  - lib/duckdb/version.rb
103
109
  homepage: https://github.com/suketa/ruby-duckdb
@@ -122,7 +128,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
122
128
  - !ruby/object:Gem::Version
123
129
  version: '0'
124
130
  requirements: []
125
- rubygems_version: 3.0.3
131
+ rubygems_version: 3.1.2
126
132
  signing_key:
127
133
  specification_version: 4
128
134
  summary: This module is Ruby binding for DuckDB database engine.
data/TODO DELETED
@@ -1,2 +0,0 @@
1
- - add test
2
- - support prepared statement