tiny_tds 2.1.2 → 2.1.7

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.
data/Rakefile CHANGED
@@ -6,19 +6,33 @@ require 'rake/extensiontask'
6
6
  require_relative './ext/tiny_tds/extconsts'
7
7
 
8
8
  SPEC = Gem::Specification.load(File.expand_path('../tiny_tds.gemspec', __FILE__))
9
+
10
+ ruby_cc_ucrt_versions = "3.3.0:3.2.0:3.1.0".freeze
11
+ ruby_cc_mingw32_versions = "3.0.0:2.7.0:2.6.0:2.5.0:2.4.0".freeze
12
+
9
13
  GEM_PLATFORM_HOSTS = {
10
- 'x86-mingw32' => 'i686-w64-mingw32',
11
- 'x64-mingw32' => 'x86_64-w64-mingw32'
14
+ 'x86-mingw32' => {
15
+ host: 'i686-w64-mingw32',
16
+ ruby_versions: ruby_cc_mingw32_versions
17
+ },
18
+ 'x64-mingw32' => {
19
+ host: 'x86_64-w64-mingw32',
20
+ ruby_versions: ruby_cc_mingw32_versions
21
+ },
22
+ 'x64-mingw-ucrt' => {
23
+ host: 'x86_64-w64-mingw32',
24
+ ruby_versions: ruby_cc_ucrt_versions
25
+ },
12
26
  }
13
27
 
14
28
  # Add our project specific files to clean for a rebuild
15
29
  CLEAN.include FileList["{ext,lib}/**/*.{so,#{RbConfig::CONFIG['DLEXT']},o}"],
16
- FileList["exe/*"]
30
+ FileList["exe/*"]
17
31
 
18
32
  # Clobber all our temp files and ports files including .install files
19
33
  # and archives
20
34
  CLOBBER.include FileList["tmp/**/*"],
21
- FileList["ports/**/*"].exclude(%r{^ports/archives})
35
+ FileList["ports/**/*"].exclude(%r{^ports/archives})
22
36
 
23
37
  Dir['tasks/*.rake'].sort.each { |f| load f }
24
38
 
@@ -32,15 +46,11 @@ Rake::ExtensionTask.new('tiny_tds', SPEC) do |ext|
32
46
  # The fat binary gem doesn't depend on the freetds package, since it bundles the library.
33
47
  spec.metadata.delete('msys2_mingw_dependencies')
34
48
 
35
- platform_host_map = GEM_PLATFORM_HOSTS
36
- gemplat = spec.platform.to_s
37
- host = platform_host_map[gemplat]
38
-
39
49
  # We don't need the sources in a fat binary gem
40
50
  spec.files = spec.files.reject { |f| f =~ %r{^ports\/archives/} }
41
51
 
42
52
  # Make sure to include the ports binaries and libraries
43
- spec.files += FileList["ports/#{host}/**/**/{bin,lib}/*"].exclude do |f|
53
+ spec.files += FileList["ports/#{spec.platform.to_s}/**/**/{bin,lib}/*"].exclude do |f|
44
54
  File.directory? f
45
55
  end
46
56
 
@@ -50,4 +60,3 @@ end
50
60
 
51
61
  task build: [:clean, :compile]
52
62
  task default: [:build, :test]
53
-
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.1.2
1
+ 2.1.7
@@ -0,0 +1,34 @@
1
+ version: '3'
2
+
3
+ networks:
4
+ main-network:
5
+
6
+ services:
7
+ mssql:
8
+ image: metaskills/mssql-server-linux-tinytds:2017-GA
9
+ container_name: sqlserver
10
+ environment:
11
+ ACCEPT_EULA: Y
12
+ SA_PASSWORD: super01S3cUr3
13
+ ports:
14
+ - "1433:1433"
15
+ network_mode: "host"
16
+
17
+ toxiproxy:
18
+ image: shopify/toxiproxy
19
+ container_name: toxiproxy
20
+ command: '/toxiproxy -host=127.0.0.1'
21
+ network_mode: "host"
22
+
23
+ cimgruby:
24
+ image: "cimg/ruby:${RUBY_VERSION:-2.7}"
25
+ container_name: cimg_ruby
26
+ environment:
27
+ TESTOPTS: '-v'
28
+ TINYTDS_UNIT_HOST: '127.0.0.1'
29
+ SA_PASSWORD: super01S3cUr3
30
+ TOXIPROXY_HOST: '127.0.0.1'
31
+ command: tail -F anything
32
+ volumes:
33
+ - .:/home/circleci/project
34
+ network_mode: "host"
@@ -24,25 +24,25 @@ VALUE opt_escape_regex, opt_escape_dblquote;
24
24
 
25
25
  // Lib Backend (Helpers)
26
26
 
27
- VALUE rb_tinytds_raise_error(DBPROCESS *dbproc, int is_message, int cancel, const char *error, const char *source, int severity, int dberr, int oserr) {
27
+ VALUE rb_tinytds_raise_error(DBPROCESS *dbproc, tinytds_errordata error) {
28
28
  VALUE e;
29
29
  GET_CLIENT_USERDATA(dbproc);
30
- if (cancel && !dbdead(dbproc) && userdata && !userdata->closed) {
30
+ if (error.cancel && !dbdead(dbproc) && userdata && !userdata->closed) {
31
31
  userdata->dbsqlok_sent = 1;
32
32
  dbsqlok(dbproc);
33
33
  userdata->dbcancel_sent = 1;
34
34
  dbcancel(dbproc);
35
35
  }
36
- e = rb_exc_new2(cTinyTdsError, error);
37
- rb_funcall(e, intern_source_eql, 1, rb_str_new2(source));
38
- if (severity)
39
- rb_funcall(e, intern_severity_eql, 1, INT2FIX(severity));
40
- if (dberr)
41
- rb_funcall(e, intern_db_error_number_eql, 1, INT2FIX(dberr));
42
- if (oserr)
43
- rb_funcall(e, intern_os_error_number_eql, 1, INT2FIX(oserr));
44
-
45
- if (severity <= 10 && is_message) {
36
+ e = rb_exc_new2(cTinyTdsError, error.error);
37
+ rb_funcall(e, intern_source_eql, 1, rb_str_new2(error.source));
38
+ if (error.severity)
39
+ rb_funcall(e, intern_severity_eql, 1, INT2FIX(error.severity));
40
+ if (error.dberr)
41
+ rb_funcall(e, intern_db_error_number_eql, 1, INT2FIX(error.dberr));
42
+ if (error.oserr)
43
+ rb_funcall(e, intern_os_error_number_eql, 1, INT2FIX(error.oserr));
44
+
45
+ if (error.severity <= 10 && error.is_message) {
46
46
  VALUE message_handler = userdata && userdata->message_handler ? userdata->message_handler : Qnil;
47
47
  if (message_handler && message_handler != Qnil && rb_respond_to(message_handler, intern_call) != 0) {
48
48
  rb_funcall(message_handler, intern_call, 1, e);
@@ -57,6 +57,16 @@ VALUE rb_tinytds_raise_error(DBPROCESS *dbproc, int is_message, int cancel, cons
57
57
 
58
58
 
59
59
  // Lib Backend (Memory Management & Handlers)
60
+ static void push_userdata_error(tinytds_client_userdata *userdata, tinytds_errordata error) {
61
+ // reallocate memory for the array as needed
62
+ if (userdata->nonblocking_errors_size == userdata->nonblocking_errors_length) {
63
+ userdata->nonblocking_errors_size *= 2;
64
+ userdata->nonblocking_errors = realloc(userdata->nonblocking_errors, userdata->nonblocking_errors_size * sizeof(tinytds_errordata));
65
+ }
66
+
67
+ userdata->nonblocking_errors[userdata->nonblocking_errors_length] = error;
68
+ userdata->nonblocking_errors_length++;
69
+ }
60
70
 
61
71
  int tinytds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr) {
62
72
  static const char *source = "error";
@@ -86,6 +96,13 @@ int tinytds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, c
86
96
  but we don't ever want to automatically retry. Instead have the app
87
97
  decide what to do.
88
98
  */
99
+ if (userdata && userdata->timing_out) {
100
+ return INT_CANCEL;
101
+ }
102
+ // userdata will not be set if hitting timeout during login so check for it first
103
+ if (userdata) {
104
+ userdata->timing_out = 1;
105
+ }
89
106
  return_value = INT_TIMEOUT;
90
107
  cancel = 1;
91
108
  break;
@@ -99,6 +116,16 @@ int tinytds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, c
99
116
  break;
100
117
  }
101
118
 
119
+ tinytds_errordata error_data = {
120
+ .is_message = 0,
121
+ .cancel = cancel,
122
+ .severity = severity,
123
+ .dberr = dberr,
124
+ .oserr = oserr
125
+ };
126
+ strncpy(error_data.error, dberrstr, ERROR_MSG_SIZE);
127
+ strncpy(error_data.source, source, ERROR_MSG_SIZE);
128
+
102
129
  /*
103
130
  When in non-blocking mode we need to store the exception data to throw it
104
131
  once the blocking call returns, otherwise we will segfault ruby since part
@@ -110,27 +137,9 @@ int tinytds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, c
110
137
  dbcancel(dbproc);
111
138
  userdata->dbcancel_sent = 1;
112
139
  }
113
-
114
- /*
115
- If we've already captured an error message, don't overwrite it. This is
116
- here because FreeTDS sends a generic "General SQL Server error" message
117
- that will overwrite the real message. This is not normally a problem
118
- because a ruby exception is normally thrown and we bail before the
119
- generic message can be sent.
120
- */
121
- if (!userdata->nonblocking_error.is_set) {
122
- userdata->nonblocking_error.is_message = 0;
123
- userdata->nonblocking_error.cancel = cancel;
124
- strncpy(userdata->nonblocking_error.error, dberrstr, ERROR_MSG_SIZE);
125
- strncpy(userdata->nonblocking_error.source, source, ERROR_MSG_SIZE);
126
- userdata->nonblocking_error.severity = severity;
127
- userdata->nonblocking_error.dberr = dberr;
128
- userdata->nonblocking_error.oserr = oserr;
129
- userdata->nonblocking_error.is_set = 1;
130
- }
131
-
140
+ push_userdata_error(userdata, error_data);
132
141
  } else {
133
- rb_tinytds_raise_error(dbproc, 0, cancel, dberrstr, source, severity, dberr, oserr);
142
+ rb_tinytds_raise_error(dbproc, error_data);
134
143
  }
135
144
 
136
145
  return return_value;
@@ -142,36 +151,72 @@ int tinytds_msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severi
142
151
 
143
152
  int is_message_an_error = severity > 10 ? 1 : 0;
144
153
 
154
+ tinytds_errordata error_data = {
155
+ .is_message = !is_message_an_error,
156
+ .cancel = is_message_an_error,
157
+ .severity = severity,
158
+ .dberr = msgno,
159
+ .oserr = msgstate
160
+ };
161
+ strncpy(error_data.error, msgtext, ERROR_MSG_SIZE);
162
+ strncpy(error_data.source, source, ERROR_MSG_SIZE);
163
+
145
164
  // See tinytds_err_handler() for info about why we do this
146
165
  if (userdata && userdata->nonblocking) {
147
- if (!userdata->nonblocking_error.is_set) {
148
- userdata->nonblocking_error.is_message = !is_message_an_error;
149
- userdata->nonblocking_error.cancel = is_message_an_error;
150
- strncpy(userdata->nonblocking_error.error, msgtext, ERROR_MSG_SIZE);
151
- strncpy(userdata->nonblocking_error.source, source, ERROR_MSG_SIZE);
152
- userdata->nonblocking_error.severity = severity;
153
- userdata->nonblocking_error.dberr = msgno;
154
- userdata->nonblocking_error.oserr = msgstate;
155
- userdata->nonblocking_error.is_set = 1;
156
- }
166
+ /*
167
+ In the case of non-blocking command batch execution we can receive multiple messages
168
+ (including errors). We keep track of those here so they can be processed once the
169
+ non-blocking call returns.
170
+ */
171
+ push_userdata_error(userdata, error_data);
157
172
 
158
173
  if (is_message_an_error && !dbdead(dbproc) && !userdata->closed) {
159
174
  dbcancel(dbproc);
160
175
  userdata->dbcancel_sent = 1;
161
176
  }
162
177
  } else {
163
- rb_tinytds_raise_error(dbproc, !is_message_an_error, is_message_an_error, msgtext, source, severity, msgno, msgstate);
178
+ rb_tinytds_raise_error(dbproc, error_data);
164
179
  }
165
180
  return 0;
166
181
  }
167
182
 
183
+ /*
184
+ Used by dbsetinterrupt -
185
+ This gets called periodically while waiting on a read from the server
186
+ Right now, we only care about cases where a read from the server is
187
+ taking longer than the specified timeout and dbcancel is not working.
188
+ In these cases we decide that we actually want to handle the interrupt
189
+ */
190
+ static int check_interrupt(void *ptr) {
191
+ GET_CLIENT_USERDATA((DBPROCESS *)ptr);
192
+ return userdata->timing_out;
193
+ }
194
+
195
+ /*
196
+ Used by dbsetinterrupt -
197
+ This gets called if check_interrupt returns TRUE.
198
+ Right now, this is only used in cases where a read from the server is
199
+ taking longer than the specified timeout and dbcancel is not working.
200
+ Return INT_CANCEL to abort the current command batch.
201
+ */
202
+ static int handle_interrupt(void *ptr) {
203
+ GET_CLIENT_USERDATA((DBPROCESS *)ptr);
204
+ if (userdata->timing_out) {
205
+ return INT_CANCEL;
206
+ }
207
+ return INT_CONTINUE;
208
+ }
209
+
168
210
  static void rb_tinytds_client_reset_userdata(tinytds_client_userdata *userdata) {
169
211
  userdata->timing_out = 0;
170
212
  userdata->dbsql_sent = 0;
171
213
  userdata->dbsqlok_sent = 0;
172
214
  userdata->dbcancel_sent = 0;
173
215
  userdata->nonblocking = 0;
174
- userdata->nonblocking_error.is_set = 0;
216
+ // the following is mainly done for consistency since the values are reset accordingly in nogvl_setup/cleanup.
217
+ // the nonblocking_errors array does not need to be freed here. That is done as part of nogvl_cleanup.
218
+ userdata->nonblocking_errors_length = 0;
219
+ userdata->nonblocking_errors_size = 0;
175
220
  }
176
221
 
177
222
  static void rb_tinytds_client_mark(void *ptr) {
@@ -187,6 +232,7 @@ static void rb_tinytds_client_free(void *ptr) {
187
232
  dbloginfree(cwrap->login);
188
233
  if (cwrap->client && !cwrap->closed) {
189
234
  dbclose(cwrap->client);
235
+ cwrap->client = NULL;
190
236
  cwrap->closed = 1;
191
237
  cwrap->userdata->closed = 1;
192
238
  }
@@ -218,6 +264,7 @@ static VALUE rb_tinytds_close(VALUE self) {
218
264
  GET_CLIENT_WRAPPER(self);
219
265
  if (cwrap->client && !cwrap->closed) {
220
266
  dbclose(cwrap->client);
267
+ cwrap->client = NULL;
221
268
  cwrap->closed = 1;
222
269
  cwrap->userdata->closed = 1;
223
270
  }
@@ -381,6 +428,7 @@ static VALUE rb_tinytds_connect(VALUE self, VALUE opts) {
381
428
  }
382
429
  }
383
430
  dbsetuserdata(cwrap->client, (BYTE*)cwrap->userdata);
431
+ dbsetinterrupt(cwrap->client, check_interrupt, handle_interrupt);
384
432
  cwrap->userdata->closed = 0;
385
433
  if (!NIL_P(database) && (azure != Qtrue)) {
386
434
  dbuse(cwrap->client, StringValueCStr(database));
@@ -5,9 +5,9 @@
5
5
  void init_tinytds_client();
6
6
 
7
7
  #define ERROR_MSG_SIZE 1024
8
+ #define ERRORS_STACK_INIT_SIZE 2
8
9
 
9
10
  typedef struct {
10
- short int is_set;
11
11
  int is_message;
12
12
  int cancel;
13
13
  char error[ERROR_MSG_SIZE];
@@ -25,7 +25,9 @@ typedef struct {
25
25
  RETCODE dbsqlok_retcode;
26
26
  short int dbcancel_sent;
27
27
  short int nonblocking;
28
- tinytds_errordata nonblocking_error;
28
+ short int nonblocking_errors_length;
29
+ short int nonblocking_errors_size;
30
+ tinytds_errordata *nonblocking_errors;
29
31
  VALUE message_handler;
30
32
  } tinytds_client_userdata;
31
33
 
@@ -40,7 +42,7 @@ typedef struct {
40
42
  rb_encoding *encoding;
41
43
  } tinytds_client_wrapper;
42
44
 
43
- VALUE rb_tinytds_raise_error(DBPROCESS *dbproc, int is_message, int cancel, const char *error, const char *source, int severity, int dberr, int oserr);
45
+ VALUE rb_tinytds_raise_error(DBPROCESS *dbproc, tinytds_errordata error);
44
46
 
45
47
  // Lib Macros
46
48
 
@@ -21,36 +21,59 @@ end
21
21
  do_help if arg_config('--help')
22
22
 
23
23
  # Make sure to check the ports path for the configured host
24
- host = RbConfig::CONFIG['host']
25
- project_dir = File.join(['..']*4)
26
- freetds_ports_dir = File.join(project_dir, 'ports', host, 'freetds', FREETDS_VERSION)
24
+ architecture = RbConfig::CONFIG['arch']
25
+ architecture = "x86-mingw32" if architecture == "i386-mingw32"
26
+
27
+ project_dir = File.expand_path("../../..", __FILE__)
28
+ freetds_ports_dir = File.join(project_dir, 'ports', architecture, 'freetds', FREETDS_VERSION)
27
29
  freetds_ports_dir = File.expand_path(freetds_ports_dir)
28
30
 
29
31
  # Add all the special path searching from the original tiny_tds build
30
- # order is important here! First in, last searched.
32
+ # order is important here! First in, first searched.
31
33
  DIRS = %w(
32
- /usr/local
33
34
  /opt/local
35
+ /usr/local
34
36
  )
35
37
 
36
- # Grab freetds environment variable for use by people on services like
37
- # Heroku who they can't easily use bundler config to set directories
38
- DIRS.push(ENV['FREETDS_DIR']) if ENV.has_key?('FREETDS_DIR')
38
+ if RbConfig::CONFIG['host_os'] =~ /darwin/i
39
+ # Ruby below 2.7 seems to label the host CPU on Apple Silicon as aarch64
40
+ # 2.7 and above print is as ARM64
41
+ target_host_cpu = Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.7') ? 'aarch64' : 'arm64'
42
+
43
+ if RbConfig::CONFIG['host_cpu'] == target_host_cpu
44
+ # Homebrew on Apple Silicon installs into /opt/hombrew
45
+ # https://docs.brew.sh/Installation
46
+ # On Intel Macs, it is /usr/local, so no changes necessary to DIRS
47
+ DIRS.unshift("/opt/homebrew")
48
+ end
49
+ end
50
+
51
+ if ENV["RI_DEVKIT"] && ENV["MINGW_PREFIX"] # RubyInstaller Support
52
+ DIRS.unshift(File.join(ENV["RI_DEVKIT"], ENV["MINGW_PREFIX"]))
53
+ end
39
54
 
40
55
  # Add the ports directory if it exists for local developer builds
41
- DIRS.push(freetds_ports_dir) if File.directory?(freetds_ports_dir)
56
+ DIRS.unshift(freetds_ports_dir) if File.directory?(freetds_ports_dir)
57
+
58
+ # Grab freetds environment variable for use by people on services like
59
+ # Heroku who they can't easily use bundler config to set directories
60
+ DIRS.unshift(ENV['FREETDS_DIR']) if ENV.has_key?('FREETDS_DIR')
42
61
 
43
62
  # Add the search paths for freetds configured above
44
- DIRS.each do |path|
45
- idir = "#{path}/include"
63
+ ldirs = DIRS.flat_map do |path|
46
64
  ldir = "#{path}/lib"
65
+ [ldir, "#{ldir}/freetds"]
66
+ end
47
67
 
48
- dir_config('freetds',
49
- [idir, "#{idir}/freetds"],
50
- [ldir, "#{ldir}/freetds"]
51
- )
68
+ idirs = DIRS.flat_map do |path|
69
+ idir = "#{path}/include"
70
+ [idir, "#{idir}/freetds"]
52
71
  end
53
72
 
73
+ puts "looking for freetds headers in the following directories:\n#{idirs.map{|a| " - #{a}\n"}.join}"
74
+ puts "looking for freetds library in the following directories:\n#{ldirs.map{|a| " - #{a}\n"}.join}"
75
+ dir_config('freetds', idirs, ldirs)
76
+
54
77
  have_dependencies = [
55
78
  find_header('sybfront.h'),
56
79
  find_header('sybdb.h'),
@@ -2,10 +2,10 @@
2
2
  ICONV_VERSION = ENV['TINYTDS_ICONV_VERSION'] || "1.15"
3
3
  ICONV_SOURCE_URI = "http://ftp.gnu.org/pub/gnu/libiconv/libiconv-#{ICONV_VERSION}.tar.gz"
4
4
 
5
- OPENSSL_VERSION = ENV['TINYTDS_OPENSSL_VERSION'] || '1.1.0e'
5
+ OPENSSL_VERSION = ENV['TINYTDS_OPENSSL_VERSION'] || '1.1.1s'
6
6
  OPENSSL_SOURCE_URI = "https://www.openssl.org/source/openssl-#{OPENSSL_VERSION}.tar.gz"
7
7
 
8
- FREETDS_VERSION = ENV['TINYTDS_FREETDS_VERSION'] || "1.00.27"
8
+ FREETDS_VERSION = ENV['TINYTDS_FREETDS_VERSION'] || "1.1.24"
9
9
  FREETDS_VERSION_INFO = Hash.new { |h,k|
10
10
  h[k] = {files: "http://www.freetds.org/files/stable/freetds-#{k}.tar.bz2"}
11
11
  }
@@ -86,26 +86,40 @@ static void dbcancel_ubf(DBPROCESS *client) {
86
86
  static void nogvl_setup(DBPROCESS *client) {
87
87
  GET_CLIENT_USERDATA(client);
88
88
  userdata->nonblocking = 1;
89
+ userdata->nonblocking_errors_length = 0;
90
+ userdata->nonblocking_errors = malloc(ERRORS_STACK_INIT_SIZE * sizeof(tinytds_errordata));
91
+ userdata->nonblocking_errors_size = ERRORS_STACK_INIT_SIZE;
89
92
  }
90
93
 
91
94
  static void nogvl_cleanup(DBPROCESS *client) {
92
95
  GET_CLIENT_USERDATA(client);
93
96
  userdata->nonblocking = 0;
97
+ userdata->timing_out = 0;
94
98
  /*
95
99
  Now that the blocking operation is done, we can finally throw any
96
100
  exceptions based on errors from SQL Server.
97
101
  */
98
- if (userdata->nonblocking_error.is_set) {
99
- userdata->nonblocking_error.is_set = 0;
100
- rb_tinytds_raise_error(client,
101
- userdata->nonblocking_error.is_message,
102
- userdata->nonblocking_error.cancel,
103
- userdata->nonblocking_error.error,
104
- userdata->nonblocking_error.source,
105
- userdata->nonblocking_error.severity,
106
- userdata->nonblocking_error.dberr,
107
- userdata->nonblocking_error.oserr);
102
+ short int i;
103
+ for (i = 0; i < userdata->nonblocking_errors_length; i++) {
104
+ tinytds_errordata error = userdata->nonblocking_errors[i];
105
+
106
+ // lookahead to drain any info messages ahead of raising error
107
+ if (!error.is_message) {
108
+ short int j;
109
+ for (j = i; j < userdata->nonblocking_errors_length; j++) {
110
+ tinytds_errordata msg_error = userdata->nonblocking_errors[j];
111
+ if (msg_error.is_message) {
112
+ rb_tinytds_raise_error(client, msg_error);
113
+ }
114
+ }
115
+ }
116
+
117
+ rb_tinytds_raise_error(client, error);
108
118
  }
119
+
120
+ free(userdata->nonblocking_errors);
121
+ userdata->nonblocking_errors_length = 0;
122
+ userdata->nonblocking_errors_size = 0;
109
123
  }
110
124
 
111
125
  static RETCODE nogvl_dbsqlok(DBPROCESS *client) {
@@ -570,6 +584,7 @@ void init_tinytds_result() {
570
584
  cDate = rb_const_get(rb_cObject, rb_intern("Date"));
571
585
  /* Define TinyTds::Result */
572
586
  cTinyTdsResult = rb_define_class_under(mTinyTds, "Result", rb_cObject);
587
+ rb_undef_alloc_func(cTinyTdsResult);
573
588
  /* Define TinyTds::Result Public Methods */
574
589
  rb_define_method(cTinyTdsResult, "fields", rb_tinytds_result_fields, 0);
575
590
  rb_define_method(cTinyTdsResult, "each", rb_tinytds_result_each, -1);
data/lib/tiny_tds/gem.rb CHANGED
@@ -20,12 +20,7 @@ module TinyTds
20
20
  end
21
21
 
22
22
  def ports_host
23
- h = RbConfig::CONFIG['host']
24
-
25
- # Our fat binary builds with a i686-w64-mingw32 toolchain
26
- # but ruby for windows x32-mingw32 reports i686-pc-mingw32
27
- # so correct the host here
28
- h.gsub('i686-pc-mingw32', 'i686-w64-mingw32')
23
+ RbConfig::CONFIG["arch"]
29
24
  end
30
25
  end
31
26
  end
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -x
4
+ set -e
5
+
6
+ # this should mirror the steps outlined in the circleci yml
7
+ echo "Installing mssql-tools..."
8
+ sleep 5
9
+ sudo -E ./test/bin/install-mssqltools.sh
10
+
11
+ echo "Configurating tinytds test database..."
12
+ sleep 5
13
+ ./test/bin/setup_tinytds_db.sh
14
+
15
+ echo "Building openssl library..."
16
+ sleep 5
17
+ sudo -E ./test/bin/install-openssl.sh
18
+
19
+ echo "Building freetds library..."
20
+ sleep 5
21
+ sudo -E ./test/bin/install-freetds.sh
22
+
23
+ echo "Installing gems..."
24
+ sleep 5
25
+ bundle install
data/start_dev.sh ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -x
4
+ set -e
5
+
6
+ # set volume read/write permissions to work both outside and inside container
7
+ sudo ./test/bin/setup_volume_permissions.sh
8
+
9
+ docker-compose up -d
10
+ echo "Waiting for containers to start..."
11
+ sleep 10
12
+
13
+ # setup circleci ruby container for development
14
+ docker exec cimg_ruby bash -c './setup_cimgruby_dev.sh'
15
+
16
+ # enter container
17
+ set +x
18
+ echo "cimg/ruby container is ready for tiny_tds development.........."
19
+ echo "To enter container run: docker exec -it cimg_ruby /bin/bash"
20
+ echo "To build solution run: docker exec cimg_ruby bash -c 'bundle exec rake build'"
21
+ echo "To test solution run: docker exec cimg_ruby bash -c 'bundle exec rake test'"
@@ -1,14 +1,23 @@
1
1
  # encoding: UTF-8
2
2
 
3
- desc 'Build the windows binary gems per rake-compiler-dock'
4
- task 'gem:windows' => ['ports:cross'] do
3
+ desc 'Build the native binary gems using rake-compiler-dock'
4
+ task 'gem:native' => ['ports:cross'] do
5
5
  require 'rake_compiler_dock'
6
6
 
7
7
  # make sure to install our bundle
8
- build = ['bundle']
8
+ sh "bundle package --all" # Avoid repeated downloads of gems by using gem files from the host.
9
9
 
10
- # and finally build the native gem
11
- build << 'rake cross native gem RUBY_CC_VERSION=2.5.0:2.4.0:2.3.0:2.2.2:2.1.6:2.0.0 CFLAGS="-Wall" MAKE="make -j`nproc`"'
10
+ GEM_PLATFORM_HOSTS.each do |plat, meta|
11
+ RakeCompilerDock.sh "bundle --local && RUBY_CC_VERSION=#{meta[:ruby_versions]} rake native:#{plat} gem", platform: plat
12
+ end
13
+ end
14
+
15
+ # assumes you are in a container provided by Rake compiler
16
+ # if not, use the task above
17
+ task 'gem:for_platform', [:gem_platform] do |_task, args|
18
+ args.with_defaults(gem_platform: RbConfig::CONFIG["arch"])
12
19
 
13
- RakeCompilerDock.sh build.join(' && ')
20
+ sh "bundle install"
21
+ Rake::Task["ports:compile"].invoke(GEM_PLATFORM_HOSTS[args.gem_platform][:host], args.gem_platform)
22
+ sh "RUBY_CC_VERSION=#{GEM_PLATFORM_HOSTS[args.gem_platform][:ruby_versions]} rake native:#{args.gem_platform} gem"
14
23
  end
@@ -8,25 +8,8 @@ module Ports
8
8
  set_patches
9
9
  end
10
10
 
11
- def cook
12
- chdir_for_build do
13
- super
14
- end
15
- self
16
- end
17
-
18
11
  private
19
12
 
20
- # When using rake-compiler-dock on Windows, the underlying Virtualbox shared
21
- # folders don't support symlinks, but libiconv expects it for a build on
22
- # Linux. We work around this limitation by using the temp dir for cooking.
23
- def chdir_for_build
24
- build_dir = ENV['RCD_HOST_RUBY_PLATFORM'].to_s =~ /mingw|mswin|cygwin/ ? '/tmp' : '.'
25
- Dir.chdir(build_dir) do
26
- yield
27
- end
28
- end
29
-
30
13
  def configure_defaults
31
14
  [
32
15
  "--host=#{@host}",
@@ -27,27 +27,11 @@ module Ports
27
27
 
28
28
  private
29
29
 
30
- def execute(action, command, options={})
31
- # OpenSSL Requires Perl >= 5.10, while the Ruby devkit uses MSYS1 with Perl 5.8.8.
32
- # To overcome this, prepend Git's usr/bin to the PATH.
33
- # It has MSYS2 with a recent version of perl.
34
- prev_path = ENV['PATH']
35
- if host =~ /mingw/ && IO.popen(["perl", "-e", "print($])"], &:read).to_f < 5.010
36
- git_perl = 'C:/Program Files/Git/usr/bin'
37
- if File.directory?(git_perl)
38
- ENV['PATH'] = "#{git_perl}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
39
- ENV['PERL'] = 'perl'
40
- end
41
- end
42
-
43
- super
44
- ENV['PATH'] = prev_path
45
- end
46
-
47
30
  def configure_defaults
48
31
  opts = [
49
32
  'shared',
50
- target_arch
33
+ target_arch,
34
+ "--openssldir=#{path}",
51
35
  ]
52
36
 
53
37
  if cross_build?