tiny_tds 0.7.0 → 0.9.5.beta.1

Sign up to get free protection for your applications and to get access to all the features.
File without changes
@@ -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
- VALUE e = rb_exc_new2(cTinyTdsError, error);
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
- break;
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
- VALUE result = rb_tinytds_new_result_obj(cwrap);
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
- GET_RESULT_WRAPPER(result);
245
- rwrap->local_offset = rb_funcall(cTinyTdsClient, intern_local_offset, 0);
246
- rwrap->encoding = cwrap->encoding;
247
- return result;
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
- Check_Type(string, T_STRING);
266
+ VALUE new_string;
262
267
  GET_CLIENT_WRAPPER(self);
263
- VALUE new_string = rb_funcall(string, intern_gsub, 2, opt_escape_regex, opt_escape_dblquote);
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
- VALUE transposed_encoding = rb_funcall(cTinyTdsClient, intern_transpose_iconv_encoding, 1, charset);
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 */
@@ -36,6 +36,7 @@ typedef struct {
36
36
  rb_encoding *encoding;
37
37
  } tinytds_client_wrapper;
38
38
 
39
+ VALUE rb_tinytds_raise_error(DBPROCESS *dbproc, int cancel, const char *error, const char *source, int severity, int dberr, int oserr);
39
40
 
40
41
  // Lib Macros
41
42
 
@@ -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
- # If your using 0.82, you may have to make a conf file to get it to work. For example:
10
- # $ export FREETDSCONF='/opt/local/etc/freetds/freetds.conf'
11
- ICONV_VERSION = ENV['TINYTDS_ICONV_VERSION'] || "1.14"
12
- ICONV_SOURCE_URI = "http://ftp.gnu.org/pub/gnu/libiconv/libiconv-#{ICONV_VERSION}.tar.gz"
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
- # Prefer host_alias over host in order to use i586-mingw32msvc as
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
- # For ruby-1.9.3 we use newer mingw-w64 (i686-w64-mingw32) to build the shared libraries
101
- # and mingw32 (i586-mingw32msvc) to build the extension.
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
- .tap do |recipe|
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
- recipe.configure_options << "--with-openssl=#{libssl.path}" if libssl
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 << "\"CFLAGS=-I#{libiconv.path}/include\""
221
- recipe.configure_options << "\"LDFLAGS=-L#{libiconv.path}/lib -liconv\""
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]
@@ -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, intern_Rational;
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
- (rb_blocking_function_t*)_dbfunction, _client, \
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
- &userdata->nonblocking_error.error,
98
- &userdata->nonblocking_error.source,
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
- VALUE row = as_array ? rb_ary_new2(rwrap->number_of_fields) : rb_hash_new();
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, "%lld", money_value);
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 date_rec;
274
- dbdatecrack(rwrap->client, &date_rec, (DBDATETIME *)data);
275
- int year = date_rec.dateyear,
276
- month = date_rec.datemonth+1,
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
- RETCODE dbsqlok_rc = rb_tinytds_result_ok_helper(rwrap->client);
319
- RETCODE dbresults_rc = rb_tinytds_result_dbresults_retcode(self);
320
- VALUE fields_processed = rb_ary_entry(rwrap->fields_processed, rwrap->number_of_results);
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
- RETCODE dbsqlok_rc = rb_tinytds_result_ok_helper(rwrap->client);
390
- RETCODE dbresults_rc = rb_tinytds_result_dbresults_retcode(self);
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
- GET_CLIENT_USERDATA(rwrap->client);
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");