tiny_tds 0.7.0-x86-mingw32 → 0.9.5.beta.1-x86-mingw32
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 +4 -4
- data/.gitignore +3 -1
- data/CHANGELOG +17 -46
- data/Gemfile +4 -0
- data/README.md +20 -14
- data/Rakefile +18 -13
- data/VERSION +1 -0
- data/appveyor.yml +17 -6
- data/bin/tsql +25 -0
- data/exe/.keep +0 -0
- data/ext/tiny_tds/client.c +26 -24
- data/ext/tiny_tds/client.h +1 -0
- data/ext/tiny_tds/extconf.rb +57 -36
- data/ext/tiny_tds/extconsts.rb +14 -0
- data/ext/tiny_tds/result.c +76 -36
- data/ext/tiny_tds/result.h +0 -4
- data/ext/tiny_tds/tiny_tds_ext.h +4 -2
- data/lib/tiny_tds.rb +3 -9
- data/lib/tiny_tds/client.rb +61 -34
- data/lib/tiny_tds/version.rb +1 -1
- data/ports/patches/freetds/0.91.112/Makefile.in.diff +29 -0
- data/ports/patches/freetds/0.91.112/dblib-30-char-username.diff +11 -0
- data/ports/patches/freetds/0.95.75/0001-mingw_missing_inet_pton.diff +34 -0
- data/test/client_test.rb +32 -12
- data/test/result_test.rb +13 -13
- data/test/schema/sqlserver_2000.sql +13 -13
- data/test/schema/sqlserver_2005.sql +13 -13
- data/test/schema/sqlserver_2008.sql +13 -13
- data/test/schema/sqlserver_2014.sql +9 -9
- data/test/schema/sqlserver_azure.sql +13 -13
- data/test/schema/sybase_ase.sql +7 -7
- data/test/schema_test.rb +157 -33
- data/test/test_helper.rb +13 -8
- data/test/thread_test.rb +6 -4
- metadata +21 -16
data/exe/.keep
ADDED
File without changes
|
data/ext/tiny_tds/client.c
CHANGED
@@ -24,7 +24,8 @@ 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 cancel, char *error, char *source, int severity, int dberr, int oserr) {
|
27
|
+
VALUE rb_tinytds_raise_error(DBPROCESS *dbproc, int cancel, const char *error, const char *source, int severity, int dberr, int oserr) {
|
28
|
+
VALUE e;
|
28
29
|
GET_CLIENT_USERDATA(dbproc);
|
29
30
|
if (cancel && !dbdead(dbproc) && userdata && !userdata->closed) {
|
30
31
|
userdata->dbsqlok_sent = 1;
|
@@ -32,7 +33,7 @@ VALUE rb_tinytds_raise_error(DBPROCESS *dbproc, int cancel, char *error, char *s
|
|
32
33
|
userdata->dbcancel_sent = 1;
|
33
34
|
dbcancel(dbproc);
|
34
35
|
}
|
35
|
-
|
36
|
+
e = rb_exc_new2(cTinyTdsError, error);
|
36
37
|
rb_funcall(e, intern_source_eql, 1, rb_str_new2(source));
|
37
38
|
if (severity)
|
38
39
|
rb_funcall(e, intern_severity_eql, 1, INT2FIX(severity));
|
@@ -48,13 +49,13 @@ VALUE rb_tinytds_raise_error(DBPROCESS *dbproc, int cancel, char *error, char *s
|
|
48
49
|
// Lib Backend (Memory Management & Handlers)
|
49
50
|
|
50
51
|
int tinytds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr) {
|
51
|
-
static char *source = "error";
|
52
|
-
GET_CLIENT_USERDATA(dbproc);
|
53
|
-
|
52
|
+
static const char *source = "error";
|
54
53
|
/* Everything should cancel by default */
|
55
54
|
int return_value = INT_CANCEL;
|
56
55
|
int cancel = 0;
|
57
56
|
|
57
|
+
GET_CLIENT_USERDATA(dbproc);
|
58
|
+
|
58
59
|
/* These error codes are documented in include/sybdb.h in FreeTDS */
|
59
60
|
switch(dberr) {
|
60
61
|
|
@@ -67,7 +68,7 @@ int tinytds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, c
|
|
67
68
|
|
68
69
|
case SYBEICONVO:
|
69
70
|
dbfreebuf(dbproc);
|
70
|
-
|
71
|
+
return return_value;
|
71
72
|
|
72
73
|
case SYBETIME:
|
73
74
|
/*
|
@@ -125,7 +126,7 @@ int tinytds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, c
|
|
125
126
|
}
|
126
127
|
|
127
128
|
int tinytds_msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severity, char *msgtext, char *srvname, char *procname, int line) {
|
128
|
-
static char *source = "message";
|
129
|
+
static const char *source = "message";
|
129
130
|
GET_CLIENT_USERDATA(dbproc);
|
130
131
|
if (severity > 10) {
|
131
132
|
// See tinytds_err_handler() for info about why we do this
|
@@ -230,6 +231,8 @@ static VALUE rb_tinytds_sqlsent(VALUE self) {
|
|
230
231
|
}
|
231
232
|
|
232
233
|
static VALUE rb_tinytds_execute(VALUE self, VALUE sql) {
|
234
|
+
VALUE result;
|
235
|
+
|
233
236
|
GET_CLIENT_WRAPPER(self);
|
234
237
|
rb_tinytds_client_reset_userdata(cwrap->userdata);
|
235
238
|
REQUIRE_OPEN_CLIENT(cwrap);
|
@@ -239,12 +242,14 @@ static VALUE rb_tinytds_execute(VALUE self, VALUE sql) {
|
|
239
242
|
return Qfalse;
|
240
243
|
}
|
241
244
|
cwrap->userdata->dbsql_sent = 1;
|
242
|
-
|
245
|
+
result = rb_tinytds_new_result_obj(cwrap);
|
243
246
|
rb_iv_set(result, "@query_options", rb_funcall(rb_iv_get(self, "@query_options"), intern_dup, 0));
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
247
|
+
{
|
248
|
+
GET_RESULT_WRAPPER(result);
|
249
|
+
rwrap->local_offset = rb_funcall(cTinyTdsClient, intern_local_offset, 0);
|
250
|
+
rwrap->encoding = cwrap->encoding;
|
251
|
+
return result;
|
252
|
+
}
|
248
253
|
}
|
249
254
|
|
250
255
|
static VALUE rb_tinytds_charset(VALUE self) {
|
@@ -258,9 +263,11 @@ static VALUE rb_tinytds_encoding(VALUE self) {
|
|
258
263
|
}
|
259
264
|
|
260
265
|
static VALUE rb_tinytds_escape(VALUE self, VALUE string) {
|
261
|
-
|
266
|
+
VALUE new_string;
|
262
267
|
GET_CLIENT_WRAPPER(self);
|
263
|
-
|
268
|
+
|
269
|
+
Check_Type(string, T_STRING);
|
270
|
+
new_string = rb_funcall(string, intern_gsub, 2, opt_escape_regex, opt_escape_dblquote);
|
264
271
|
rb_enc_associate(new_string, cwrap->encoding);
|
265
272
|
return new_string;
|
266
273
|
}
|
@@ -280,13 +287,6 @@ static VALUE rb_tinytds_identity_sql(VALUE self) {
|
|
280
287
|
return rb_str_new2(cwrap->identity_insert_sql);
|
281
288
|
}
|
282
289
|
|
283
|
-
static VALUE rb_tinytds_freetds_nine_one_or_higher(VALUE self) {
|
284
|
-
#ifdef DBSETLDBNAME
|
285
|
-
return Qtrue;
|
286
|
-
#else
|
287
|
-
return Qfalse;
|
288
|
-
#endif
|
289
|
-
}
|
290
290
|
|
291
291
|
|
292
292
|
// TinyTds::Client (protected)
|
@@ -294,6 +294,8 @@ static VALUE rb_tinytds_freetds_nine_one_or_higher(VALUE self) {
|
|
294
294
|
static VALUE rb_tinytds_connect(VALUE self, VALUE opts) {
|
295
295
|
/* Parsing options hash to local vars. */
|
296
296
|
VALUE user, pass, dataserver, database, app, version, ltimeout, timeout, charset, azure;
|
297
|
+
GET_CLIENT_WRAPPER(self);
|
298
|
+
|
297
299
|
user = rb_hash_aref(opts, sym_username);
|
298
300
|
pass = rb_hash_aref(opts, sym_password);
|
299
301
|
dataserver = rb_hash_aref(opts, sym_dataserver);
|
@@ -311,7 +313,6 @@ static VALUE rb_tinytds_connect(VALUE self, VALUE opts) {
|
|
311
313
|
}
|
312
314
|
dberrhandle(tinytds_err_handler);
|
313
315
|
dbmsghandle(tinytds_msg_handler);
|
314
|
-
GET_CLIENT_WRAPPER(self);
|
315
316
|
cwrap->login = dblogin();
|
316
317
|
if (!NIL_P(version))
|
317
318
|
dbsetlversion(cwrap->login, NUM2INT(version));
|
@@ -336,6 +337,8 @@ static VALUE rb_tinytds_connect(VALUE self, VALUE opts) {
|
|
336
337
|
}
|
337
338
|
cwrap->client = dbopen(cwrap->login, StringValueCStr(dataserver));
|
338
339
|
if (cwrap->client) {
|
340
|
+
VALUE transposed_encoding;
|
341
|
+
|
339
342
|
cwrap->closed = 0;
|
340
343
|
cwrap->charset = charset;
|
341
344
|
if (!NIL_P(version))
|
@@ -345,7 +348,7 @@ static VALUE rb_tinytds_connect(VALUE self, VALUE opts) {
|
|
345
348
|
if (!NIL_P(database) && (azure != Qtrue)) {
|
346
349
|
dbuse(cwrap->client, StringValueCStr(database));
|
347
350
|
}
|
348
|
-
|
351
|
+
transposed_encoding = rb_funcall(cTinyTdsClient, intern_transpose_iconv_encoding, 1, charset);
|
349
352
|
cwrap->encoding = rb_enc_find(StringValueCStr(transposed_encoding));
|
350
353
|
if (dbtds(cwrap->client) <= 7) {
|
351
354
|
cwrap->identity_insert_sql = "SELECT CAST(@@IDENTITY AS bigint) AS Ident";
|
@@ -375,7 +378,6 @@ void init_tinytds_client() {
|
|
375
378
|
rb_define_method(cTinyTdsClient, "escape", rb_tinytds_escape, 1);
|
376
379
|
rb_define_method(cTinyTdsClient, "return_code", rb_tinytds_return_code, 0);
|
377
380
|
rb_define_method(cTinyTdsClient, "identity_sql", rb_tinytds_identity_sql, 0);
|
378
|
-
rb_define_method(cTinyTdsClient, "freetds_091_or_higer?", rb_tinytds_freetds_nine_one_or_higher, 0);
|
379
381
|
/* Define TinyTds::Client Protected Methods */
|
380
382
|
rb_define_protected_method(cTinyTdsClient, "connect", rb_tinytds_connect, 1);
|
381
383
|
/* Symbols For Connect */
|
data/ext/tiny_tds/client.h
CHANGED
data/ext/tiny_tds/extconf.rb
CHANGED
@@ -3,27 +3,13 @@ ENV['RC_ARCHS'] = '' if RUBY_PLATFORM =~ /darwin/
|
|
3
3
|
# :stopdoc:
|
4
4
|
|
5
5
|
require 'mkmf'
|
6
|
-
require 'mini_portile'
|
7
6
|
require 'fileutils'
|
8
7
|
|
9
|
-
#
|
10
|
-
#
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
OPENSSL_VERSION = ENV['TINYTDS_OPENSSL_VERSION'] || '1.0.2d'
|
15
|
-
OPENSSL_SOURCE_URI = "http://www.openssl.org/source/openssl-#{OPENSSL_VERSION}.tar.gz"
|
16
|
-
|
17
|
-
FREETDS_VERSION = ENV['TINYTDS_FREETDS_VERSION'] || "0.91"
|
18
|
-
FREETDS_VERSION_INFO = Hash.new { |h,k|
|
19
|
-
h[k] = {:files => "ftp://ftp.freetds.org/pub/freetds/stable/freetds-#{k}.tar.gz"}
|
20
|
-
}.merge({
|
21
|
-
"0.82" => {:files => "ftp://ftp.freetds.org/pub/freetds/old/0.82/freetds-0.82.tar.gz"},
|
22
|
-
"0.91" => {:files => "ftp://ftp.freetds.org/pub/freetds/stable/freetds-0.91.112.tar.gz"},
|
23
|
-
"0.92" => {:files => "ftp://ftp.freetds.org/pub/freetds/stable/freetds-0.92.405.tar.gz"},
|
24
|
-
"current" => {:files => "ftp://ftp.freetds.org/pub/freetds/current/freetds-current.tar.gz"}
|
25
|
-
})
|
26
|
-
FREETDS_SOURCE_URI = FREETDS_VERSION_INFO[FREETDS_VERSION][:files]
|
8
|
+
# The gem version constraint in the gemspec is not respected at install time.
|
9
|
+
# Keep this version in sync with the one in the gemspec !
|
10
|
+
gem 'mini_portile2', '~> 2.0'
|
11
|
+
require 'mini_portile2'
|
12
|
+
require_relative './extconsts'
|
27
13
|
|
28
14
|
# Shamelessly copied from nokogiri
|
29
15
|
#
|
@@ -44,6 +30,12 @@ usage: ruby #{$0} [options]
|
|
44
30
|
--enable-lookup
|
45
31
|
Search for freetds through all paths in the PATH environment variable.
|
46
32
|
|
33
|
+
--disable-openssl
|
34
|
+
Disable OpenSSL for freetds build. No effect on system-freetds.
|
35
|
+
|
36
|
+
--enable-gnutls
|
37
|
+
Use GnuTLS instead of OpenSSL for freetds build.
|
38
|
+
|
47
39
|
--enable-cross-build
|
48
40
|
Do cross-build.
|
49
41
|
HELP
|
@@ -90,17 +82,13 @@ class BuildRecipe < MiniPortile
|
|
90
82
|
super(name, version)
|
91
83
|
self.files = files
|
92
84
|
self.target = File.expand_path('../../../ports', __FILE__)
|
93
|
-
|
94
|
-
# correct compiler prefix for cross build, but use host if not set.
|
95
|
-
self.host = consolidated_host(RbConfig::CONFIG["host_alias"].empty? ? RbConfig::CONFIG["host"] : RbConfig::CONFIG["host_alias"])
|
85
|
+
self.host = consolidated_host(RbConfig::CONFIG["host"])
|
96
86
|
self.patch_files = Dir[File.join(self.target, "patches", self.name, self.version, "*.diff")].sort
|
97
87
|
end
|
98
88
|
|
99
89
|
def consolidated_host(name)
|
100
|
-
|
101
|
-
|
102
|
-
name.gsub('i586-mingw32msvc', 'i686-w64-mingw32').
|
103
|
-
gsub('i686-pc-mingw32', 'i686-w64-mingw32')
|
90
|
+
# Host name and prefix of build tools are different on Windows 32 bit.
|
91
|
+
name.gsub('i686-pc-mingw32', 'i686-w64-mingw32')
|
104
92
|
end
|
105
93
|
|
106
94
|
def configure_defaults
|
@@ -111,10 +99,16 @@ class BuildRecipe < MiniPortile
|
|
111
99
|
]
|
112
100
|
end
|
113
101
|
|
102
|
+
# Use the same path for all recipes, so that only one include/lib path is required.
|
114
103
|
def port_path
|
115
104
|
"#{target}/#{host}"
|
116
105
|
end
|
117
106
|
|
107
|
+
# We use the same port_path for all recipes. That breaks the standard installed? method.
|
108
|
+
def installed?
|
109
|
+
false
|
110
|
+
end
|
111
|
+
|
118
112
|
# When using rake-compiler-dock on Windows, the underlying Virtualbox shared
|
119
113
|
# folders don't support symlinks, but libiconv expects it for a build on
|
120
114
|
# Linux. We work around this limitation by using the temp dir for cooking.
|
@@ -195,21 +189,24 @@ def define_libssl_recipe(host)
|
|
195
189
|
end
|
196
190
|
|
197
191
|
def define_libiconv_recipe(host)
|
198
|
-
BuildRecipe.new("libiconv", ICONV_VERSION, [ICONV_SOURCE_URI])
|
199
|
-
.tap do |recipe|
|
192
|
+
BuildRecipe.new("libiconv", ICONV_VERSION, [ICONV_SOURCE_URI]).tap do |recipe|
|
200
193
|
# always produce position independent code
|
201
194
|
recipe.configure_options << "CFLAGS=-fPIC"
|
202
195
|
end
|
203
196
|
end
|
204
197
|
|
205
|
-
def define_freetds_recipe(host, libiconv, libssl)
|
206
|
-
BuildRecipe.new("freetds", FREETDS_VERSION, [FREETDS_SOURCE_URI])
|
207
|
-
|
208
|
-
with_tdsver = FREETDS_VERSION =~ /0\.8/ ? "--with-tdsver=8.0" : "--with-tdsver=7.1"
|
198
|
+
def define_freetds_recipe(host, libiconv, libssl, gnutls)
|
199
|
+
BuildRecipe.new("freetds", FREETDS_VERSION, [FREETDS_SOURCE_URI]).tap do |recipe|
|
200
|
+
with_tdsver = FREETDS_VERSION =~ /0\.91/ ? "--with-tdsver=7.1" : "--with-tdsver=7.3"
|
209
201
|
for_windows = recipe.host =~ /mswin|mingw/i
|
210
202
|
recipe.configure_options << '--with-pic'
|
211
203
|
recipe.configure_options << "--with-libiconv-prefix=#{libiconv.path}" if libiconv
|
212
|
-
|
204
|
+
if true == libssl
|
205
|
+
recipe.configure_options << "--with-openssl"
|
206
|
+
elsif libssl
|
207
|
+
recipe.configure_options << "--with-openssl=#{libssl.path}"
|
208
|
+
end
|
209
|
+
recipe.configure_options << "--with-gnutls" if gnutls
|
213
210
|
recipe.configure_options << '--sysconfdir=C:/Sites' if for_windows
|
214
211
|
recipe.configure_options << '--enable-sspi' if for_windows
|
215
212
|
recipe.configure_options << "--disable-odbc"
|
@@ -217,9 +214,31 @@ def define_freetds_recipe(host, libiconv, libssl)
|
|
217
214
|
if libiconv
|
218
215
|
# For some reason freetds doesn't honor --with-libiconv-prefix
|
219
216
|
# so we have do add it by hand:
|
220
|
-
recipe.configure_options << "
|
221
|
-
recipe.configure_options << "
|
217
|
+
recipe.configure_options << "CFLAGS=-I#{libiconv.path}/include"
|
218
|
+
recipe.configure_options << "LDFLAGS=-L#{libiconv.path}/lib -liconv"
|
219
|
+
end
|
220
|
+
|
221
|
+
class << recipe
|
222
|
+
|
223
|
+
def install
|
224
|
+
super_value = super
|
225
|
+
# Install binstub target binaries.
|
226
|
+
if super_value
|
227
|
+
bin_path = File.expand_path File.join(path, 'bin')
|
228
|
+
exe_path = File.expand_path File.join(target, '..', 'exe')
|
229
|
+
return unless File.directory?(bin_path)
|
230
|
+
ENV['PATH'] = "#{bin_path}#{File::PATH_SEPARATOR}#{ENV['PATH']}" unless ENV['PATH'].include?(bin_path)
|
231
|
+
['tsql'].each do |bin|
|
232
|
+
path = which(bin)
|
233
|
+
next unless path.include?(bin_path)
|
234
|
+
FileUtils.cp path, exe_path
|
235
|
+
end
|
236
|
+
end
|
237
|
+
super_value
|
238
|
+
end
|
239
|
+
|
222
240
|
end
|
241
|
+
|
223
242
|
end
|
224
243
|
end
|
225
244
|
|
@@ -285,11 +304,13 @@ system_freetds = enable_config('system-freetds', ENV['TINYTDS_SKIP_PORTS'] || fr
|
|
285
304
|
host = RbConfig::CONFIG["host"]
|
286
305
|
system_iconv = enable_config('system-iconv', host =~ /mingw|mswin/ ? false : true)
|
287
306
|
system_openssl = enable_config('system-openssl', host =~ /mingw|mswin/ ? false : true )
|
307
|
+
enable_gnutls = enable_config('gnutls', false )
|
308
|
+
enable_openssl = enable_config('openssl', !enable_gnutls )
|
288
309
|
|
289
310
|
unless system_freetds
|
290
311
|
libssl = define_libssl_recipe(host).cook_and_activate unless system_openssl
|
291
312
|
libiconv = define_libiconv_recipe(host).cook_and_activate unless system_iconv
|
292
|
-
freetds = define_freetds_recipe(host, libiconv, libssl).cook_and_activate
|
313
|
+
freetds = define_freetds_recipe(host, libiconv, libssl || enable_openssl, enable_gnutls).cook_and_activate
|
293
314
|
dir_config('freetds', freetds.path + "/include", freetds.path + "/lib")
|
294
315
|
end
|
295
316
|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
|
2
|
+
ICONV_VERSION = ENV['TINYTDS_ICONV_VERSION'] || "1.14"
|
3
|
+
ICONV_SOURCE_URI = "http://ftp.gnu.org/pub/gnu/libiconv/libiconv-#{ICONV_VERSION}.tar.gz"
|
4
|
+
|
5
|
+
OPENSSL_VERSION = ENV['TINYTDS_OPENSSL_VERSION'] || '1.0.2e'
|
6
|
+
OPENSSL_SOURCE_URI = "http://www.openssl.org/source/openssl-#{OPENSSL_VERSION}.tar.gz"
|
7
|
+
|
8
|
+
FREETDS_VERSION = ENV['TINYTDS_FREETDS_VERSION'] || "0.95.75"
|
9
|
+
FREETDS_VERSION_INFO = Hash.new { |h,k|
|
10
|
+
h[k] = {files: "ftp://ftp.freetds.org/pub/freetds/stable/freetds-#{k}.tar.bz2"}
|
11
|
+
}
|
12
|
+
FREETDS_VERSION_INFO['0.99'] = {files: 'ftp://ftp.freetds.org/pub/freetds/current/freetds-dev.0.99.479.tar.bz2'}
|
13
|
+
FREETDS_VERSION_INFO['current'] = {files: 'https://github.com/FreeTDS/freetds/archive/master.zip'}
|
14
|
+
FREETDS_SOURCE_URI = FREETDS_VERSION_INFO[FREETDS_VERSION][:files]
|
data/ext/tiny_tds/result.c
CHANGED
@@ -7,9 +7,9 @@
|
|
7
7
|
VALUE cTinyTdsResult;
|
8
8
|
extern VALUE mTinyTds, cTinyTdsClient, cTinyTdsError;
|
9
9
|
VALUE cBigDecimal, cDate;
|
10
|
-
VALUE opt_decimal_zero, opt_float_zero, opt_one, opt_zero, opt_four, opt_19hdr, opt_tenk, opt_onemil;
|
10
|
+
VALUE opt_decimal_zero, opt_float_zero, opt_one, opt_zero, opt_four, opt_19hdr, opt_onek, opt_tenk, opt_onemil, opt_onebil;
|
11
11
|
static ID intern_new, intern_utc, intern_local, intern_localtime, intern_merge,
|
12
|
-
intern_civil, intern_new_offset, intern_plus, intern_divide
|
12
|
+
intern_civil, intern_new_offset, intern_plus, intern_divide;
|
13
13
|
static ID sym_symbolize_keys, sym_as, sym_array, sym_cache_rows, sym_first, sym_timezone, sym_local, sym_utc, sym_empty_sets;
|
14
14
|
|
15
15
|
|
@@ -27,6 +27,12 @@ rb_encoding *binaryEncoding;
|
|
27
27
|
_val; \
|
28
28
|
})
|
29
29
|
|
30
|
+
#ifdef _WIN32
|
31
|
+
#define LONG_LONG_FORMAT "I64d"
|
32
|
+
#else
|
33
|
+
#define LONG_LONG_FORMAT "lld"
|
34
|
+
#endif
|
35
|
+
|
30
36
|
|
31
37
|
// Lib Backend (Memory Management)
|
32
38
|
|
@@ -42,7 +48,6 @@ static void rb_tinytds_result_mark(void *ptr) {
|
|
42
48
|
}
|
43
49
|
|
44
50
|
static void rb_tinytds_result_free(void *ptr) {
|
45
|
-
tinytds_result_wrapper *rwrap = (tinytds_result_wrapper *)ptr;
|
46
51
|
xfree(ptr);
|
47
52
|
}
|
48
53
|
|
@@ -67,8 +72,8 @@ VALUE rb_tinytds_new_result_obj(tinytds_client_wrapper *cwrap) {
|
|
67
72
|
// No GVL Helpers
|
68
73
|
|
69
74
|
#define NOGVL_DBCALL(_dbfunction, _client) ( \
|
70
|
-
(RETCODE)rb_thread_call_without_gvl( \
|
71
|
-
(
|
75
|
+
(RETCODE)(intptr_t)rb_thread_call_without_gvl( \
|
76
|
+
(void *(*)(void *))_dbfunction, _client, \
|
72
77
|
(rb_unblock_function_t*)dbcancel_ubf, _client ) \
|
73
78
|
)
|
74
79
|
|
@@ -94,8 +99,8 @@ static void nogvl_cleanup(DBPROCESS *client) {
|
|
94
99
|
userdata->nonblocking_error.is_set = 0;
|
95
100
|
rb_tinytds_raise_error(client,
|
96
101
|
userdata->nonblocking_error.cancel,
|
97
|
-
|
98
|
-
|
102
|
+
userdata->nonblocking_error.error,
|
103
|
+
userdata->nonblocking_error.source,
|
99
104
|
userdata->nonblocking_error.severity,
|
100
105
|
userdata->nonblocking_error.dberr,
|
101
106
|
userdata->nonblocking_error.oserr);
|
@@ -139,9 +144,9 @@ static RETCODE nogvl_dbnextrow(DBPROCESS * client) {
|
|
139
144
|
// Lib Backend (Helpers)
|
140
145
|
|
141
146
|
static RETCODE rb_tinytds_result_dbresults_retcode(VALUE self) {
|
142
|
-
GET_RESULT_WRAPPER(self);
|
143
147
|
VALUE ruby_rc;
|
144
148
|
RETCODE db_rc;
|
149
|
+
GET_RESULT_WRAPPER(self);
|
145
150
|
ruby_rc = rb_ary_entry(rwrap->dbresults_retcodes, rwrap->number_of_results);
|
146
151
|
if (NIL_P(ruby_rc)) {
|
147
152
|
db_rc = nogvl_dbresults(rwrap->client);
|
@@ -162,8 +167,8 @@ static RETCODE rb_tinytds_result_ok_helper(DBPROCESS *client) {
|
|
162
167
|
}
|
163
168
|
|
164
169
|
static void rb_tinytds_result_exec_helper(DBPROCESS *client) {
|
165
|
-
GET_CLIENT_USERDATA(client);
|
166
170
|
RETCODE dbsqlok_rc = rb_tinytds_result_ok_helper(client);
|
171
|
+
GET_CLIENT_USERDATA(client);
|
167
172
|
if (dbsqlok_rc == SUCCEED) {
|
168
173
|
/*
|
169
174
|
This is to just process each result set. Commands such as backup and
|
@@ -185,12 +190,13 @@ static void rb_tinytds_result_exec_helper(DBPROCESS *client) {
|
|
185
190
|
}
|
186
191
|
|
187
192
|
static VALUE rb_tinytds_result_fetch_row(VALUE self, ID timezone, int symbolize_keys, int as_array) {
|
193
|
+
VALUE row;
|
194
|
+
/* Storing Values */
|
195
|
+
unsigned int i;
|
188
196
|
/* Wrapper And Local Vars */
|
189
197
|
GET_RESULT_WRAPPER(self);
|
190
198
|
/* Create Empty Row */
|
191
|
-
|
192
|
-
/* Storing Values */
|
193
|
-
unsigned int i = 0;
|
199
|
+
row = as_array ? rb_ary_new2(rwrap->number_of_fields) : rb_hash_new();
|
194
200
|
for (i = 0; i < rwrap->number_of_fields; i++) {
|
195
201
|
VALUE val = Qnil;
|
196
202
|
int col = i+1;
|
@@ -238,7 +244,7 @@ static VALUE rb_tinytds_result_fetch_row(VALUE self, ID timezone, int symbolize_
|
|
238
244
|
DBMONEY *money = (DBMONEY *)data;
|
239
245
|
char converted_money[25];
|
240
246
|
long long money_value = ((long long)money->mnyhigh << 32) | money->mnylow;
|
241
|
-
sprintf(converted_money, "%
|
247
|
+
sprintf(converted_money, "%" LONG_LONG_FORMAT, money_value);
|
242
248
|
val = rb_funcall(cBigDecimal, intern_new, 2, rb_str_new2(converted_money), opt_four);
|
243
249
|
val = rb_funcall(val, intern_divide, 1, opt_tenk);
|
244
250
|
break;
|
@@ -270,22 +276,50 @@ static VALUE rb_tinytds_result_fetch_row(VALUE self, ID timezone, int symbolize_
|
|
270
276
|
data_len = sizeof(new_data);
|
271
277
|
}
|
272
278
|
case SYBDATETIME: {
|
273
|
-
DBDATEREC
|
274
|
-
dbdatecrack(rwrap->client, &
|
275
|
-
|
276
|
-
|
277
|
-
day = date_rec.datedmonth,
|
278
|
-
hour = date_rec.datehour,
|
279
|
-
min = date_rec.dateminute,
|
280
|
-
sec = date_rec.datesecond,
|
281
|
-
msec = date_rec.datemsecond;
|
282
|
-
if (year+month+day+hour+min+sec+msec != 0) {
|
283
|
-
VALUE offset = (timezone == intern_local) ? rwrap->local_offset : opt_zero;
|
284
|
-
uint64_t seconds = (year*31557600ULL) + (month*2592000ULL) + (day*86400ULL) + (hour*3600ULL) + (min*60ULL) + sec;
|
285
|
-
val = rb_funcall(rb_cTime, timezone, 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), INT2NUM(msec*1000));
|
279
|
+
DBDATEREC dr;
|
280
|
+
dbdatecrack(rwrap->client, &dr, (DBDATETIME *)data);
|
281
|
+
if (dr.year + dr.month + dr.day + dr.hour + dr.minute + dr.second + dr.millisecond != 0) {
|
282
|
+
val = rb_funcall(rb_cTime, timezone, 7, INT2NUM(dr.year), INT2NUM(dr.month), INT2NUM(dr.day), INT2NUM(dr.hour), INT2NUM(dr.minute), INT2NUM(dr.second), INT2NUM(dr.millisecond*1000));
|
286
283
|
}
|
287
284
|
break;
|
288
285
|
}
|
286
|
+
case 40: // SYBMSDATE
|
287
|
+
case 41: // SYBMSTIME
|
288
|
+
case 42: // SYBMSDATETIME2
|
289
|
+
case 43: { // SYBMSDATETIMEOFFSET
|
290
|
+
#ifdef DBVERSION_73
|
291
|
+
if (dbtds(rwrap->client) >= DBTDS_7_3) {
|
292
|
+
DBDATEREC2 dr2;
|
293
|
+
dbanydatecrack(rwrap->client, &dr2, coltype, data);
|
294
|
+
switch(coltype) {
|
295
|
+
case 40: { // SYBMSDATE
|
296
|
+
val = rb_funcall(cDate, intern_new, 3, INT2NUM(dr2.year), INT2NUM(dr2.month), INT2NUM(dr2.day));
|
297
|
+
break;
|
298
|
+
}
|
299
|
+
case 41: { // SYBMSTIME
|
300
|
+
VALUE rational_nsec = rb_Rational(INT2NUM(dr2.nanosecond), opt_onek);
|
301
|
+
val = rb_funcall(rb_cTime, timezone, 7, INT2NUM(1900), INT2NUM(1), INT2NUM(1), INT2NUM(dr2.hour), INT2NUM(dr2.minute), INT2NUM(dr2.second), rational_nsec);
|
302
|
+
break;
|
303
|
+
}
|
304
|
+
case 42: { // SYBMSDATETIME2
|
305
|
+
VALUE rational_nsec = rb_Rational(INT2NUM(dr2.nanosecond), opt_onek);
|
306
|
+
val = rb_funcall(rb_cTime, timezone, 7, INT2NUM(dr2.year), INT2NUM(dr2.month), INT2NUM(dr2.day), INT2NUM(dr2.hour), INT2NUM(dr2.minute), INT2NUM(dr2.second), rational_nsec);
|
307
|
+
break;
|
308
|
+
}
|
309
|
+
case 43: { // SYBMSDATETIMEOFFSET
|
310
|
+
VALUE rational_sec = rb_Rational(INT2NUM(dr2.nanosecond), opt_onebil);
|
311
|
+
val = rb_funcall(rb_cTime, intern_new, 7, INT2NUM(dr2.year), INT2NUM(dr2.month), INT2NUM(dr2.day), INT2NUM(dr2.hour), INT2NUM(dr2.minute), rational_sec, INT2NUM(dr2.tzone));
|
312
|
+
break;
|
313
|
+
}
|
314
|
+
}
|
315
|
+
} else {
|
316
|
+
val = ENCODED_STR_NEW(data, data_len);
|
317
|
+
}
|
318
|
+
#else
|
319
|
+
val = ENCODED_STR_NEW(data, data_len);
|
320
|
+
#endif
|
321
|
+
break;
|
322
|
+
}
|
289
323
|
case SYBCHAR:
|
290
324
|
case SYBTEXT:
|
291
325
|
val = ENCODED_STR_NEW(data, data_len);
|
@@ -314,10 +348,12 @@ static VALUE rb_tinytds_result_fetch_row(VALUE self, ID timezone, int symbolize_
|
|
314
348
|
// TinyTds::Client (public)
|
315
349
|
|
316
350
|
static VALUE rb_tinytds_result_fields(VALUE self) {
|
351
|
+
RETCODE dbsqlok_rc, dbresults_rc;
|
352
|
+
VALUE fields_processed;
|
317
353
|
GET_RESULT_WRAPPER(self);
|
318
|
-
|
319
|
-
|
320
|
-
|
354
|
+
dbsqlok_rc = rb_tinytds_result_ok_helper(rwrap->client);
|
355
|
+
dbresults_rc = rb_tinytds_result_dbresults_retcode(self);
|
356
|
+
fields_processed = rb_ary_entry(rwrap->fields_processed, rwrap->number_of_results);
|
321
357
|
if ((dbsqlok_rc == SUCCEED) && (dbresults_rc == SUCCEED) && (fields_processed == Qnil)) {
|
322
358
|
/* Default query options. */
|
323
359
|
int symbolize_keys = 0;
|
@@ -353,12 +389,13 @@ static VALUE rb_tinytds_result_fields(VALUE self) {
|
|
353
389
|
}
|
354
390
|
|
355
391
|
static VALUE rb_tinytds_result_each(int argc, VALUE * argv, VALUE self) {
|
356
|
-
GET_RESULT_WRAPPER(self);
|
357
|
-
GET_CLIENT_USERDATA(rwrap->client);
|
358
392
|
/* Local Vars */
|
359
393
|
VALUE qopts, opts, block;
|
360
394
|
ID timezone;
|
361
395
|
int symbolize_keys = 0, as_array = 0, cache_rows = 0, first = 0, empty_sets = 0;
|
396
|
+
tinytds_client_userdata *userdata;
|
397
|
+
GET_RESULT_WRAPPER(self);
|
398
|
+
userdata = (tinytds_client_userdata *)dbgetuserdata(rwrap->client);
|
362
399
|
/* Merge Options Hash To Query Options. Populate Opts & Block Var. */
|
363
400
|
qopts = rb_iv_get(self, "@query_options");
|
364
401
|
if (rb_scan_args(argc, argv, "01&", &opts, &block) == 1)
|
@@ -385,9 +422,10 @@ static VALUE rb_tinytds_result_each(int argc, VALUE * argv, VALUE self) {
|
|
385
422
|
empty_sets = 1;
|
386
423
|
/* Make The Results Or Yield Existing */
|
387
424
|
if (NIL_P(rwrap->results)) {
|
425
|
+
RETCODE dbsqlok_rc, dbresults_rc;
|
388
426
|
rwrap->results = rb_ary_new();
|
389
|
-
|
390
|
-
|
427
|
+
dbsqlok_rc = rb_tinytds_result_ok_helper(rwrap->client);
|
428
|
+
dbresults_rc = rb_tinytds_result_dbresults_retcode(self);
|
391
429
|
while ((dbsqlok_rc == SUCCEED) && (dbresults_rc == SUCCEED)) {
|
392
430
|
int has_rows = (DBROWS(rwrap->client) == SUCCEED) ? 1 : 0;
|
393
431
|
if (has_rows || empty_sets || (rwrap->number_of_results == 0))
|
@@ -447,8 +485,9 @@ static VALUE rb_tinytds_result_each(int argc, VALUE * argv, VALUE self) {
|
|
447
485
|
}
|
448
486
|
|
449
487
|
static VALUE rb_tinytds_result_cancel(VALUE self) {
|
488
|
+
tinytds_client_userdata *userdata;
|
450
489
|
GET_RESULT_WRAPPER(self);
|
451
|
-
|
490
|
+
userdata = (tinytds_client_userdata *)dbgetuserdata(rwrap->client);
|
452
491
|
if (rwrap->client && !userdata->dbcancel_sent) {
|
453
492
|
RETCODE dbsqlok_rc = rb_tinytds_result_ok_helper(rwrap->client);
|
454
493
|
dbcancel(rwrap->client);
|
@@ -490,8 +529,8 @@ static VALUE rb_tinytds_result_return_code(VALUE self) {
|
|
490
529
|
static VALUE rb_tinytds_result_insert(VALUE self) {
|
491
530
|
GET_RESULT_WRAPPER(self);
|
492
531
|
if (rwrap->client) {
|
493
|
-
rb_tinytds_result_exec_helper(rwrap->client);
|
494
532
|
VALUE identity = Qnil;
|
533
|
+
rb_tinytds_result_exec_helper(rwrap->client);
|
495
534
|
dbcmd(rwrap->client, rwrap->cwrap->identity_insert_sql);
|
496
535
|
if (nogvl_dbsqlexec(rwrap->client) != FAIL
|
497
536
|
&& nogvl_dbresults(rwrap->client) != FAIL
|
@@ -538,7 +577,6 @@ void init_tinytds_result() {
|
|
538
577
|
intern_new_offset = rb_intern("new_offset");
|
539
578
|
intern_plus = rb_intern("+");
|
540
579
|
intern_divide = rb_intern("/");
|
541
|
-
intern_Rational = rb_intern("Rational");
|
542
580
|
/* Symbol Helpers */
|
543
581
|
sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys"));
|
544
582
|
sym_as = ID2SYM(rb_intern("as"));
|
@@ -558,8 +596,10 @@ void init_tinytds_result() {
|
|
558
596
|
opt_zero = INT2NUM(0);
|
559
597
|
opt_four = INT2NUM(4);
|
560
598
|
opt_19hdr = INT2NUM(1900);
|
599
|
+
opt_onek = INT2NUM(1000);
|
561
600
|
opt_tenk = INT2NUM(10000);
|
562
601
|
opt_onemil = INT2NUM(1000000);
|
602
|
+
opt_onebil = INT2NUM(1000000000);
|
563
603
|
/* Encoding */
|
564
604
|
#ifdef HAVE_RUBY_ENCODING_H
|
565
605
|
binaryEncoding = rb_enc_find("binary");
|