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.
- checksums.yaml +5 -5
- data/.circleci/config.yml +409 -0
- data/.gitignore +2 -0
- data/CHANGELOG.md +29 -1
- data/Gemfile +0 -7
- data/README.md +33 -22
- data/Rakefile +19 -10
- data/VERSION +1 -1
- data/docker-compose.yml +34 -0
- data/ext/tiny_tds/client.c +92 -44
- data/ext/tiny_tds/client.h +5 -3
- data/ext/tiny_tds/extconf.rb +38 -15
- data/ext/tiny_tds/extconsts.rb +2 -2
- data/ext/tiny_tds/result.c +25 -10
- data/lib/tiny_tds/gem.rb +1 -6
- data/setup_cimgruby_dev.sh +25 -0
- data/start_dev.sh +21 -0
- data/tasks/native_gem.rake +15 -6
- data/tasks/ports/libiconv.rb +0 -17
- data/tasks/ports/openssl.rb +2 -18
- data/tasks/ports/recipe.rb +16 -4
- data/tasks/ports.rake +61 -40
- data/test/bin/install-mssql.ps1 +31 -0
- data/test/bin/install-mssqltools.sh +9 -0
- data/test/bin/setup_tinytds_db.sh +7 -0
- data/test/bin/setup_volume_permissions.sh +10 -0
- data/test/client_test.rb +99 -54
- data/test/gem_test.rb +26 -28
- data/test/result_test.rb +83 -42
- data/test/schema_test.rb +12 -12
- data/test/sql/db-create.sql +18 -0
- data/test/sql/db-login.sql +38 -0
- data/test/test_helper.rb +67 -4
- data/test/thread_test.rb +1 -1
- data/tiny_tds.gemspec +8 -6
- metadata +54 -45
- data/.travis.yml +0 -24
- data/BACKERS.md +0 -32
- data/appveyor.yml +0 -51
- data/test/appveyor/dbsetup.ps1 +0 -27
- data/test/appveyor/dbsetup.sql +0 -9
- data/test/bin/setup.sh +0 -19
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' =>
|
11
|
-
|
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
|
-
|
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
|
-
|
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/#{
|
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.
|
1
|
+
2.1.7
|
data/docker-compose.yml
ADDED
@@ -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"
|
data/ext/tiny_tds/client.c
CHANGED
@@ -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,
|
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,
|
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
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
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,
|
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
|
-
|
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));
|
data/ext/tiny_tds/client.h
CHANGED
@@ -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
|
-
|
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,
|
45
|
+
VALUE rb_tinytds_raise_error(DBPROCESS *dbproc, tinytds_errordata error);
|
44
46
|
|
45
47
|
// Lib Macros
|
46
48
|
|
data/ext/tiny_tds/extconf.rb
CHANGED
@@ -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
|
-
|
25
|
-
|
26
|
-
|
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,
|
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
|
-
|
37
|
-
#
|
38
|
-
|
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.
|
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.
|
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
|
-
|
49
|
-
|
50
|
-
|
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'),
|
data/ext/tiny_tds/extconsts.rb
CHANGED
@@ -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.
|
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.
|
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
|
}
|
data/ext/tiny_tds/result.c
CHANGED
@@ -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
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
userdata->
|
106
|
-
|
107
|
-
|
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
|
-
|
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'"
|
data/tasks/native_gem.rake
CHANGED
@@ -1,14 +1,23 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
|
-
desc 'Build the
|
4
|
-
task 'gem:
|
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
|
-
|
8
|
+
sh "bundle package --all" # Avoid repeated downloads of gems by using gem files from the host.
|
9
9
|
|
10
|
-
|
11
|
-
|
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
|
-
|
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
|
data/tasks/ports/libiconv.rb
CHANGED
@@ -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}",
|
data/tasks/ports/openssl.rb
CHANGED
@@ -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?
|