tiny_tds_vagas 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/CHANGELOG +198 -0
  4. data/CODE_OF_CONDUCT.md +31 -0
  5. data/Gemfile +6 -0
  6. data/ISSUE_TEMPLATE.md +5 -0
  7. data/MIT-LICENSE +23 -0
  8. data/README.md +427 -0
  9. data/Rakefile +110 -0
  10. data/VERSION +1 -0
  11. data/appveyor.yml +52 -0
  12. data/bin/defncopy +3 -0
  13. data/bin/tsql +3 -0
  14. data/ext/tiny_tds/client.c +410 -0
  15. data/ext/tiny_tds/client.h +49 -0
  16. data/ext/tiny_tds/extconf.rb +329 -0
  17. data/ext/tiny_tds/extconsts.rb +15 -0
  18. data/ext/tiny_tds/result.c +608 -0
  19. data/ext/tiny_tds/result.h +32 -0
  20. data/ext/tiny_tds/tiny_tds_ext.c +12 -0
  21. data/ext/tiny_tds/tiny_tds_ext.h +17 -0
  22. data/lib/tiny_tds.rb +37 -0
  23. data/lib/tiny_tds/bin.rb +86 -0
  24. data/lib/tiny_tds/client.rb +124 -0
  25. data/lib/tiny_tds/error.rb +15 -0
  26. data/lib/tiny_tds/result.rb +8 -0
  27. data/lib/tiny_tds/version.rb +3 -0
  28. data/ports/patches/freetds/1.00/0001-mingw_missing_inet_pton.diff +34 -0
  29. data/test/appveyor/dbsetup.ps1 +27 -0
  30. data/test/appveyor/dbsetup.sql +9 -0
  31. data/test/benchmark/query.rb +77 -0
  32. data/test/benchmark/query_odbc.rb +106 -0
  33. data/test/benchmark/query_tinytds.rb +126 -0
  34. data/test/client_test.rb +217 -0
  35. data/test/result_test.rb +728 -0
  36. data/test/schema/1px.gif +0 -0
  37. data/test/schema/sqlserver_2000.sql +140 -0
  38. data/test/schema/sqlserver_2005.sql +140 -0
  39. data/test/schema/sqlserver_2008.sql +140 -0
  40. data/test/schema/sqlserver_2014.sql +140 -0
  41. data/test/schema/sqlserver_azure.sql +140 -0
  42. data/test/schema/sybase_ase.sql +138 -0
  43. data/test/schema_test.rb +443 -0
  44. data/test/test_helper.rb +213 -0
  45. data/test/thread_test.rb +98 -0
  46. data/tiny_tds.gemspec +28 -0
  47. metadata +201 -0
@@ -0,0 +1,49 @@
1
+
2
+ #ifndef TINYTDS_CLIENT_H
3
+ #define TINYTDS_CLIENT_H
4
+
5
+ void init_tinytds_client();
6
+
7
+ #define ERROR_MSG_SIZE 1024
8
+
9
+ typedef struct {
10
+ short int is_set;
11
+ int cancel;
12
+ char error[ERROR_MSG_SIZE];
13
+ char source[ERROR_MSG_SIZE];
14
+ int severity;
15
+ int dberr;
16
+ int oserr;
17
+ } tinytds_errordata;
18
+
19
+ typedef struct {
20
+ short int closed;
21
+ short int timing_out;
22
+ short int dbsql_sent;
23
+ short int dbsqlok_sent;
24
+ RETCODE dbsqlok_retcode;
25
+ short int dbcancel_sent;
26
+ short int nonblocking;
27
+ tinytds_errordata nonblocking_error;
28
+ } tinytds_client_userdata;
29
+
30
+ typedef struct {
31
+ LOGINREC *login;
32
+ RETCODE return_code;
33
+ DBPROCESS *client;
34
+ short int closed;
35
+ VALUE charset;
36
+ tinytds_client_userdata *userdata;
37
+ const char *identity_insert_sql;
38
+ rb_encoding *encoding;
39
+ } tinytds_client_wrapper;
40
+
41
+ VALUE rb_tinytds_raise_error(DBPROCESS *dbproc, int cancel, const char *error, const char *source, int severity, int dberr, int oserr);
42
+
43
+ // Lib Macros
44
+
45
+ #define GET_CLIENT_USERDATA(dbproc) \
46
+ tinytds_client_userdata *userdata = (tinytds_client_userdata *)dbgetuserdata(dbproc);
47
+
48
+
49
+ #endif
@@ -0,0 +1,329 @@
1
+ ENV['RC_ARCHS'] = '' if RUBY_PLATFORM =~ /darwin/
2
+
3
+ # :stopdoc:
4
+
5
+ require 'mkmf'
6
+ require 'fileutils'
7
+
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'
13
+
14
+ OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
15
+
16
+ # Shamelessly copied from nokogiri
17
+ #
18
+
19
+ def do_help
20
+ print <<HELP
21
+ usage: ruby #{$0} [options]
22
+
23
+ --enable-system-freetds / --disable-system-freetds
24
+ --enable-system-iconv / --disable-system-iconv
25
+ --enable-system-openssl / --disable-system-openssl
26
+ Force use of system or builtin freetds/iconv/openssl library.
27
+ Default is to prefer system libraries and fallback to builtin.
28
+
29
+ --with-freetds-dir=DIR
30
+ Use the freetds library placed under DIR.
31
+
32
+ --enable-lookup
33
+ Search for freetds through all paths in the PATH environment variable.
34
+
35
+ --disable-openssl
36
+ Disable OpenSSL for freetds build. No effect on system-freetds.
37
+
38
+ --enable-gnutls
39
+ Use GnuTLS instead of OpenSSL for freetds build.
40
+
41
+ --enable-cross-build
42
+ Do cross-build.
43
+ HELP
44
+ exit! 0
45
+ end
46
+
47
+ do_help if arg_config('--help')
48
+
49
+ FREETDSDIR = ENV['FREETDS_DIR']
50
+
51
+ if FREETDSDIR.nil? || FREETDSDIR.empty?
52
+ LIBDIR = RbConfig::CONFIG['libdir']
53
+ INCLUDEDIR = RbConfig::CONFIG['includedir']
54
+ else
55
+ puts "Will use #{FREETDSDIR}"
56
+ LIBDIR = "#{FREETDSDIR}/lib"
57
+ INCLUDEDIR = "#{FREETDSDIR}/include"
58
+ end
59
+
60
+ $CFLAGS << " #{ENV["CFLAGS"]}"
61
+ $LDFLAGS << " #{ENV["LDFLAGS"]}"
62
+ $LIBS << " #{ENV["LIBS"]}"
63
+
64
+ SEARCHABLE_PATHS = begin
65
+ eop_regexp = /#{File::SEPARATOR}bin$/
66
+ paths = ENV['PATH']
67
+ paths = paths.gsub(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
68
+ paths = paths.split(File::PATH_SEPARATOR)
69
+ bin_paths = paths.select{ |p| p =~ eop_regexp }
70
+ bin_paths.map{ |p| p.sub(eop_regexp,'') }.compact.reject{ |p| p.empty? }.uniq
71
+ end
72
+
73
+ def searchable_paths_with_directories(*directories)
74
+ SEARCHABLE_PATHS.map do |path|
75
+ directories.map do |paths|
76
+ dir = File.join path, *paths
77
+ File.directory?(dir) ? dir : nil
78
+ end.flatten.compact
79
+ end.flatten.compact
80
+ end
81
+
82
+ class BuildRecipe < MiniPortile
83
+ def initialize(name, version, files)
84
+ super(name, version)
85
+ self.files = files
86
+ self.target = File.expand_path('../../../ports', __FILE__)
87
+ self.host = consolidated_host(RbConfig::CONFIG["host"])
88
+ self.patch_files = Dir[File.join(self.target, "patches", self.name, self.version, "*.diff")].sort
89
+ end
90
+
91
+ def consolidated_host(name)
92
+ # Host name and prefix of build tools are different on Windows 32 bit.
93
+ name.gsub('i686-pc-mingw32', 'i686-w64-mingw32')
94
+ end
95
+
96
+ def configure_defaults
97
+ [
98
+ "--host=#{host}", # build for specific target (host)
99
+ "--disable-static",
100
+ "--enable-shared",
101
+ ]
102
+ end
103
+
104
+ # Use the same path for all recipes, so that only one include/lib path is required.
105
+ def port_path
106
+ "#{target}/#{host}"
107
+ end
108
+
109
+ # We use the same port_path for all recipes. That breaks the standard installed? method.
110
+ def installed?
111
+ false
112
+ end
113
+
114
+ # When using rake-compiler-dock on Windows, the underlying Virtualbox shared
115
+ # folders don't support symlinks, but libiconv expects it for a build on
116
+ # Linux. We work around this limitation by using the temp dir for cooking.
117
+ def chdir_for_build
118
+ build_dir = ENV['RCD_HOST_RUBY_PLATFORM'].to_s =~ /mingw|mswin|cygwin/ ? '/tmp' : '.'
119
+ Dir.chdir(build_dir) do
120
+ yield
121
+ end
122
+ end
123
+
124
+ def cook_and_activate
125
+ checkpoint = File.join(self.target, "#{self.name}-#{self.version}-#{self.host}.installed")
126
+ unless File.exist?(checkpoint)
127
+ chdir_for_build do
128
+ self.cook
129
+ end
130
+ FileUtils.touch checkpoint
131
+ end
132
+ self.activate
133
+ self
134
+ end
135
+ end
136
+
137
+ def define_libssl_recipe(host)
138
+ BuildRecipe.new("openssl", OPENSSL_VERSION, [OPENSSL_SOURCE_URI]).tap do |recipe|
139
+ class << recipe
140
+ def extract_file(file, target)
141
+ filename = File.basename(file)
142
+ FileUtils.mkdir_p target
143
+
144
+ message "Extracting #{filename} into #{target}... "
145
+ result = `#{tar_exe} #{tar_compression_switch(filename)}xf "#{file}" -C "#{target}" 2>&1`
146
+ if $?.success?
147
+ output "OK"
148
+ else
149
+ # tar on windows returns error exit code, because it can not extract symlinks
150
+ output "ERROR (ignored)"
151
+ end
152
+ end
153
+
154
+ def configure
155
+ config = if host=~/mingw/
156
+ host=~/x86_64/ ? 'mingw64' : 'mingw'
157
+ end
158
+ args = [ "CFLAGS=-DDSO_WIN32",
159
+ "./Configure",
160
+ "no-shared",
161
+ configure_prefix,
162
+ config,
163
+ ]
164
+ args.unshift("CROSS_COMPILE=#{host}-") if enable_config("cross-build")
165
+
166
+ execute "configure", "sh -c \"#{args.join(" ")}\""
167
+ end
168
+
169
+ def compile
170
+ super
171
+ # OpenSSL DLLs are called "libeay32.dll" and "ssleay32.dll" per default,
172
+ # regardless to the version. This is best suited to meet the Windows DLL hell.
173
+ # To avoid any conflicts we do a static build and build DLLs afterwards,
174
+ # with our own naming scheme.
175
+ execute "mkdef-libeay32", "(perl util/mkdef.pl 32 libeay >libeay32.def)"
176
+ execute "mkdef-ssleay32", "(perl util/mkdef.pl 32 ssleay >ssleay32.def)"
177
+ dllwrap = consolidated_host(RbConfig::CONFIG["DLLWRAP"])
178
+ execute "dllwrap-libeay32", "#{dllwrap} --dllname libeay32-#{version}-#{host}.dll --output-lib libcrypto.dll.a --def libeay32.def libcrypto.a -lwsock32 -lgdi32 -lcrypt32"
179
+ execute "dllwrap-ssleay32", "#{dllwrap} --dllname ssleay32-#{version}-#{host}.dll --output-lib libssl.dll.a --def ssleay32.def libssl.a libcrypto.dll.a"
180
+ end
181
+
182
+ def install
183
+ super
184
+ FileUtils.cp "#{work_path}/libeay32-#{version}-#{host}.dll", "#{path}/bin/"
185
+ FileUtils.cp "#{work_path}/ssleay32-#{version}-#{host}.dll", "#{path}/bin/"
186
+ FileUtils.cp "#{work_path}/libcrypto.dll.a", "#{path}/lib/"
187
+ FileUtils.cp "#{work_path}/libssl.dll.a", "#{path}/lib/"
188
+ end
189
+ end
190
+ end
191
+ end
192
+
193
+ def define_libiconv_recipe(host)
194
+ BuildRecipe.new("libiconv", ICONV_VERSION, [ICONV_SOURCE_URI]).tap do |recipe|
195
+ # always produce position independent code
196
+ recipe.configure_options << "CFLAGS=-fPIC"
197
+ end
198
+ end
199
+
200
+ def define_freetds_recipe(host, libiconv, libssl, gnutls)
201
+ BuildRecipe.new("freetds", FREETDS_VERSION, [FREETDS_SOURCE_URI]).tap do |recipe|
202
+ with_tdsver = FREETDS_VERSION =~ /0\.91/ ? "--with-tdsver=7.1" : "--with-tdsver=7.3"
203
+ for_windows = recipe.host =~ /mswin|mingw/i
204
+ recipe.configure_options << '--with-pic'
205
+ recipe.configure_options << "--with-libiconv-prefix=#{libiconv.path}" if libiconv
206
+ if true == libssl
207
+ recipe.configure_options << "--with-openssl"
208
+ elsif libssl
209
+ recipe.configure_options << "--with-openssl=#{libssl.path}"
210
+ end
211
+ recipe.configure_options << "--with-gnutls" if gnutls
212
+ recipe.configure_options << '--sysconfdir=C:\Sites' if for_windows
213
+ recipe.configure_options << '--enable-sspi' if for_windows
214
+ recipe.configure_options << "--disable-odbc"
215
+ recipe.configure_options << with_tdsver
216
+ if libiconv
217
+ # For some reason freetds doesn't honor --with-libiconv-prefix
218
+ # so we have do add it by hand:
219
+ recipe.configure_options << "CFLAGS=-I#{libiconv.path}/include"
220
+ recipe.configure_options << "LDFLAGS=-L#{libiconv.path}/lib -liconv"
221
+ end
222
+
223
+ class << recipe
224
+
225
+ def install
226
+ super_value = super
227
+ # Install binstub target binaries.
228
+ if super_value
229
+ bin_path = File.expand_path File.join(path, 'bin')
230
+ exe_path = File.expand_path File.join(target, '..', 'exe')
231
+ return unless File.directory?(bin_path)
232
+ ['tsql', 'defncopy'].each do |bin|
233
+ ['.exe', ''].each do |ext|
234
+ exe = File.join bin_path, "#{bin}#{ext}"
235
+ next unless File.exists?(exe)
236
+ next unless File.executable?(exe)
237
+ FileUtils.cp exe, exe_path
238
+ end
239
+ end
240
+ end
241
+ super_value
242
+ end
243
+
244
+ end
245
+
246
+ end
247
+ end
248
+
249
+ if RbConfig::CONFIG['target_os'] =~ /mswin32|mingw32/
250
+ lib_prefix = 'lib' unless RbConfig::CONFIG['target_os'] =~ /mingw32/
251
+ # There's no default include/lib dir on Windows. Let's just add the Ruby ones
252
+ # and resort on the search path specified by INCLUDE and LIB environment
253
+ # variables
254
+ HEADER_DIRS = [INCLUDEDIR]
255
+ LIB_DIRS = [LIBDIR]
256
+ else
257
+ lib_prefix = ''
258
+ HEADER_DIRS = [
259
+ # First search /opt/local for macports
260
+ '/opt/local/include',
261
+ # Then search /usr/local for people that installed from source
262
+ '/usr/local/include',
263
+ # Check the ruby install locations
264
+ INCLUDEDIR,
265
+ # Finally fall back to /usr
266
+ '/usr/include'
267
+ ].reject{ |dir| !File.directory?(dir) }
268
+ LIB_DIRS = [
269
+ # First search /opt/local for macports
270
+ '/opt/local/lib',
271
+ # Then search /usr/local for people that installed from source
272
+ '/usr/local/lib',
273
+ # Check the ruby install locations
274
+ LIBDIR,
275
+ # Finally fall back to /usr
276
+ '/usr/lib',
277
+ ].reject{ |dir| !File.directory?(dir) }
278
+ end
279
+
280
+ FREETDS_HEADER_DIRS = (searchable_paths_with_directories(['include'],['include','freetds']) + HEADER_DIRS).uniq
281
+ FREETDS_LIB_DIRS = (searchable_paths_with_directories(['lib'],['lib','freetds']) + LIB_DIRS).uniq
282
+
283
+ # lookup over searchable paths is great for native compilation, however, when
284
+ # cross compiling we need to specify our own paths.
285
+ if enable_config("lookup", true)
286
+ dir_config('freetds', FREETDS_HEADER_DIRS, FREETDS_LIB_DIRS)
287
+ else
288
+ dir_config('freetds')
289
+
290
+ # remove LDFLAGS
291
+ $LDFLAGS = ENV.fetch("LDFLAGS", "")
292
+ end
293
+
294
+ def asplode(lib)
295
+ msg = "-----\n"
296
+ msg << "#{lib} is missing.\n"
297
+ msg << "Do you have FreeTDS 0.95.80 or higher installed?\n" if lib == 'freetds'
298
+ msg << "-----"
299
+ abort(msg)
300
+ end
301
+
302
+ def freetds_usable?(lib_prefix)
303
+ have_header('sybfront.h') && have_header('sybdb.h') &&
304
+ find_library("#{lib_prefix}sybdb", 'tdsdbopen') &&
305
+ find_library("#{lib_prefix}sybdb", 'dbanydatecrack')
306
+ end
307
+
308
+ # We use freetds, when available already, and fallback to compilation of ports
309
+ system_freetds = enable_config('system-freetds', ENV['TINYTDS_SKIP_PORTS'] || freetds_usable?(lib_prefix))
310
+
311
+ # We expect to have iconv and OpenSSL available on non-Windows systems
312
+ host = RbConfig::CONFIG["host"]
313
+ system_iconv = enable_config('system-iconv', host =~ /mingw|mswin/ ? false : true)
314
+ system_openssl = enable_config('system-openssl', host =~ /mingw|mswin/ ? false : true )
315
+ enable_gnutls = enable_config('gnutls', false )
316
+ enable_openssl = enable_config('openssl', !enable_gnutls )
317
+
318
+ unless system_freetds
319
+ libssl = define_libssl_recipe(host).cook_and_activate unless system_openssl
320
+ libiconv = define_libiconv_recipe(host).cook_and_activate unless system_iconv
321
+ freetds = define_freetds_recipe(host, libiconv, libssl || enable_openssl, enable_gnutls).cook_and_activate
322
+ dir_config('freetds', freetds.path + "/include", freetds.path + "/lib")
323
+ end
324
+
325
+ asplode 'freetds' unless freetds_usable?(lib_prefix)
326
+
327
+ create_makefile('tiny_tds/tiny_tds')
328
+
329
+ # :startdoc:
@@ -0,0 +1,15 @@
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.2g'
6
+ OPENSSL_SOURCE_URI = "https://www.openssl.org/source/openssl-#{OPENSSL_VERSION}.tar.gz"
7
+
8
+ FREETDS_VERSION = ENV['TINYTDS_FREETDS_VERSION'] || "1.00"
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['1.00'] = {files: 'ftp://ftp.freetds.org/pub/freetds/stable/freetds-1.00.tar.bz2'}
13
+ FREETDS_VERSION_INFO['0.99'] = {files: 'ftp://ftp.freetds.org/pub/freetds/current/freetds-dev.0.99.678.tar.gz'}
14
+ FREETDS_VERSION_INFO['0.95'] = {files: 'ftp://ftp.freetds.org/pub/freetds/stable/freetds-0.95.92.tar.gz'}
15
+ FREETDS_SOURCE_URI = FREETDS_VERSION_INFO[FREETDS_VERSION][:files]
@@ -0,0 +1,608 @@
1
+
2
+ #include <tiny_tds_ext.h>
3
+ #include <stdint.h>
4
+
5
+ // File Types/Vars
6
+
7
+ VALUE cTinyTdsResult;
8
+ extern VALUE mTinyTds, cTinyTdsClient, cTinyTdsError;
9
+ VALUE cBigDecimal, cDate;
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
+ static ID intern_new, intern_utc, intern_local, intern_localtime, intern_merge,
12
+ intern_civil, intern_new_offset, intern_plus, intern_divide;
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
+
15
+
16
+ // Lib Macros
17
+
18
+ rb_encoding *binaryEncoding;
19
+ #define ENCODED_STR_NEW(_data, _len) ({ \
20
+ VALUE _val = rb_str_new((char *)_data, (long)_len); \
21
+ rb_enc_associate(_val, rwrap->encoding); \
22
+ _val; \
23
+ })
24
+ #define ENCODED_STR_NEW2(_data2) ({ \
25
+ VALUE _val = rb_str_new2((char *)_data2); \
26
+ rb_enc_associate(_val, rwrap->encoding); \
27
+ _val; \
28
+ })
29
+
30
+ #ifdef _WIN32
31
+ #define LONG_LONG_FORMAT "I64d"
32
+ #else
33
+ #define LONG_LONG_FORMAT "lld"
34
+ #endif
35
+
36
+
37
+ // Lib Backend (Memory Management)
38
+
39
+ static void rb_tinytds_result_mark(void *ptr) {
40
+ tinytds_result_wrapper *rwrap = (tinytds_result_wrapper *)ptr;
41
+ if (rwrap) {
42
+ rb_gc_mark(rwrap->local_offset);
43
+ rb_gc_mark(rwrap->fields);
44
+ rb_gc_mark(rwrap->fields_processed);
45
+ rb_gc_mark(rwrap->results);
46
+ rb_gc_mark(rwrap->dbresults_retcodes);
47
+ }
48
+ }
49
+
50
+ static void rb_tinytds_result_free(void *ptr) {
51
+ xfree(ptr);
52
+ }
53
+
54
+ VALUE rb_tinytds_new_result_obj(tinytds_client_wrapper *cwrap) {
55
+ VALUE obj;
56
+ tinytds_result_wrapper *rwrap;
57
+ obj = Data_Make_Struct(cTinyTdsResult, tinytds_result_wrapper, rb_tinytds_result_mark, rb_tinytds_result_free, rwrap);
58
+ rwrap->cwrap = cwrap;
59
+ rwrap->client = cwrap->client;
60
+ rwrap->local_offset = Qnil;
61
+ rwrap->fields = rb_ary_new();
62
+ rwrap->fields_processed = rb_ary_new();
63
+ rwrap->results = Qnil;
64
+ rwrap->dbresults_retcodes = rb_ary_new();
65
+ rwrap->number_of_results = 0;
66
+ rwrap->number_of_fields = 0;
67
+ rwrap->number_of_rows = 0;
68
+ rb_obj_call_init(obj, 0, NULL);
69
+ return obj;
70
+ }
71
+
72
+ // No GVL Helpers
73
+
74
+ #define NOGVL_DBCALL(_dbfunction, _client) ( \
75
+ (RETCODE)(intptr_t)rb_thread_call_without_gvl( \
76
+ (void *(*)(void *))_dbfunction, _client, \
77
+ (rb_unblock_function_t*)dbcancel_ubf, _client ) \
78
+ )
79
+
80
+ static void dbcancel_ubf(DBPROCESS *client) {
81
+ GET_CLIENT_USERDATA(client);
82
+ dbcancel(client);
83
+ userdata->dbcancel_sent = 1;
84
+ }
85
+
86
+ static void nogvl_setup(DBPROCESS *client) {
87
+ GET_CLIENT_USERDATA(client);
88
+ userdata->nonblocking = 1;
89
+ }
90
+
91
+ static void nogvl_cleanup(DBPROCESS *client) {
92
+ GET_CLIENT_USERDATA(client);
93
+ userdata->nonblocking = 0;
94
+ /*
95
+ Now that the blocking operation is done, we can finally throw any
96
+ exceptions based on errors from SQL Server.
97
+ */
98
+ if (userdata->nonblocking_error.is_set) {
99
+ userdata->nonblocking_error.is_set = 0;
100
+ rb_tinytds_raise_error(client,
101
+ userdata->nonblocking_error.cancel,
102
+ userdata->nonblocking_error.error,
103
+ userdata->nonblocking_error.source,
104
+ userdata->nonblocking_error.severity,
105
+ userdata->nonblocking_error.dberr,
106
+ userdata->nonblocking_error.oserr);
107
+ }
108
+ }
109
+
110
+ static RETCODE nogvl_dbsqlok(DBPROCESS *client) {
111
+ int retcode = FAIL;
112
+ GET_CLIENT_USERDATA(client);
113
+ nogvl_setup(client);
114
+ retcode = NOGVL_DBCALL(dbsqlok, client);
115
+ nogvl_cleanup(client);
116
+ userdata->dbsqlok_sent = 1;
117
+ return retcode;
118
+ }
119
+
120
+ static RETCODE nogvl_dbsqlexec(DBPROCESS *client) {
121
+ int retcode = FAIL;
122
+ nogvl_setup(client);
123
+ retcode = NOGVL_DBCALL(dbsqlexec, client);
124
+ nogvl_cleanup(client);
125
+ return retcode;
126
+ }
127
+
128
+ static RETCODE nogvl_dbresults(DBPROCESS *client) {
129
+ int retcode = FAIL;
130
+ nogvl_setup(client);
131
+ retcode = NOGVL_DBCALL(dbresults, client);
132
+ nogvl_cleanup(client);
133
+ return retcode;
134
+ }
135
+
136
+ static RETCODE nogvl_dbnextrow(DBPROCESS * client) {
137
+ int retcode = FAIL;
138
+ nogvl_setup(client);
139
+ retcode = NOGVL_DBCALL(dbnextrow, client);
140
+ nogvl_cleanup(client);
141
+ return retcode;
142
+ }
143
+
144
+ // Lib Backend (Helpers)
145
+
146
+ static RETCODE rb_tinytds_result_dbresults_retcode(VALUE self) {
147
+ VALUE ruby_rc;
148
+ RETCODE db_rc;
149
+ GET_RESULT_WRAPPER(self);
150
+ ruby_rc = rb_ary_entry(rwrap->dbresults_retcodes, rwrap->number_of_results);
151
+ if (NIL_P(ruby_rc)) {
152
+ db_rc = nogvl_dbresults(rwrap->client);
153
+ ruby_rc = INT2FIX(db_rc);
154
+ rb_ary_store(rwrap->dbresults_retcodes, rwrap->number_of_results, ruby_rc);
155
+ } else {
156
+ db_rc = FIX2INT(ruby_rc);
157
+ }
158
+ return db_rc;
159
+ }
160
+
161
+ static RETCODE rb_tinytds_result_ok_helper(DBPROCESS *client) {
162
+ GET_CLIENT_USERDATA(client);
163
+ if (userdata->dbsqlok_sent == 0) {
164
+ userdata->dbsqlok_retcode = nogvl_dbsqlok(client);
165
+ }
166
+ return userdata->dbsqlok_retcode;
167
+ }
168
+
169
+ static void rb_tinytds_result_exec_helper(DBPROCESS *client) {
170
+ RETCODE dbsqlok_rc = rb_tinytds_result_ok_helper(client);
171
+ GET_CLIENT_USERDATA(client);
172
+ if (dbsqlok_rc == SUCCEED) {
173
+ /*
174
+ This is to just process each result set. Commands such as backup and
175
+ restore are not done when the first result set is returned, so we need to
176
+ exhaust the result sets before it is complete.
177
+ */
178
+ while (nogvl_dbresults(client) == SUCCEED) {
179
+ /*
180
+ If we don't loop through each row for calls to TinyTds::Result.do that
181
+ actually do return result sets, we will trigger error 20019 about trying
182
+ to execute a new command with pending results. Oh well.
183
+ */
184
+ while (dbnextrow(client) != NO_MORE_ROWS);
185
+ }
186
+ }
187
+ dbcancel(client);
188
+ userdata->dbcancel_sent = 1;
189
+ userdata->dbsql_sent = 0;
190
+ }
191
+
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;
196
+ /* Wrapper And Local Vars */
197
+ GET_RESULT_WRAPPER(self);
198
+ /* Create Empty Row */
199
+ row = as_array ? rb_ary_new2(rwrap->number_of_fields) : rb_hash_new();
200
+ for (i = 0; i < rwrap->number_of_fields; i++) {
201
+ VALUE val = Qnil;
202
+ int col = i+1;
203
+ int coltype = dbcoltype(rwrap->client, col);
204
+ BYTE *data = dbdata(rwrap->client, col);
205
+ DBINT data_len = dbdatlen(rwrap->client, col);
206
+ int null_val = ((data == NULL) && (data_len == 0));
207
+ if (!null_val) {
208
+ switch(coltype) {
209
+ case SYBINT1:
210
+ val = INT2FIX(*(DBTINYINT *)data);
211
+ break;
212
+ case SYBINT2:
213
+ val = INT2FIX(*(DBSMALLINT *)data);
214
+ break;
215
+ case SYBINT4:
216
+ val = INT2NUM(*(DBINT *)data);
217
+ break;
218
+ case SYBINT8:
219
+ val = LL2NUM(*(DBBIGINT *)data);
220
+ break;
221
+ case SYBBIT:
222
+ val = *(int *)data ? Qtrue : Qfalse;
223
+ break;
224
+ case SYBNUMERIC:
225
+ case SYBDECIMAL: {
226
+ DBTYPEINFO *data_info = dbcoltypeinfo(rwrap->client, col);
227
+ int data_slength = (int)data_info->precision + (int)data_info->scale + 1;
228
+ char converted_decimal[data_slength];
229
+ dbconvert(rwrap->client, coltype, data, data_len, SYBVARCHAR, (BYTE *)converted_decimal, -1);
230
+ val = rb_funcall(cBigDecimal, intern_new, 1, rb_str_new2((char *)converted_decimal));
231
+ break;
232
+ }
233
+ case SYBFLT8: {
234
+ double col_to_double = *(double *)data;
235
+ val = (col_to_double == 0.000000) ? opt_float_zero : rb_float_new(col_to_double);
236
+ break;
237
+ }
238
+ case SYBREAL: {
239
+ float col_to_float = *(float *)data;
240
+ val = (col_to_float == 0.0) ? opt_float_zero : rb_float_new(col_to_float);
241
+ break;
242
+ }
243
+ case SYBMONEY: {
244
+ DBMONEY *money = (DBMONEY *)data;
245
+ char converted_money[25];
246
+ long long money_value = ((long long)money->mnyhigh << 32) | money->mnylow;
247
+ sprintf(converted_money, "%" LONG_LONG_FORMAT, money_value);
248
+ val = rb_funcall(cBigDecimal, intern_new, 2, rb_str_new2(converted_money), opt_four);
249
+ val = rb_funcall(val, intern_divide, 1, opt_tenk);
250
+ break;
251
+ }
252
+ case SYBMONEY4: {
253
+ DBMONEY4 *money = (DBMONEY4 *)data;
254
+ char converted_money[20];
255
+ sprintf(converted_money, "%f", money->mny4 / 10000.0);
256
+ val = rb_funcall(cBigDecimal, intern_new, 1, rb_str_new2(converted_money));
257
+ break;
258
+ }
259
+ case SYBBINARY:
260
+ case SYBIMAGE:
261
+ val = rb_str_new((char *)data, (long)data_len);
262
+ #ifdef HAVE_RUBY_ENCODING_H
263
+ rb_enc_associate(val, binaryEncoding);
264
+ #endif
265
+ break;
266
+ case 36: { // SYBUNIQUE
267
+ char converted_unique[37];
268
+ dbconvert(rwrap->client, coltype, data, 37, SYBVARCHAR, (BYTE *)converted_unique, -1);
269
+ val = ENCODED_STR_NEW2(converted_unique);
270
+ break;
271
+ }
272
+ case SYBDATETIME4: {
273
+ DBDATETIME new_data;
274
+ dbconvert(rwrap->client, coltype, data, data_len, SYBDATETIME, (BYTE *)&new_data, sizeof(new_data));
275
+ data = (BYTE *)&new_data;
276
+ data_len = sizeof(new_data);
277
+ }
278
+ case SYBDATETIME: {
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));
283
+ }
284
+ break;
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
+ long long numerator = ((long)dr2.second * (long long)1000000000) + (long long)dr2.nanosecond;
311
+ VALUE rational_sec = rb_Rational(LL2NUM(numerator), opt_onebil);
312
+ 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*60));
313
+ break;
314
+ }
315
+ }
316
+ } else {
317
+ val = ENCODED_STR_NEW(data, data_len);
318
+ }
319
+ #else
320
+ val = ENCODED_STR_NEW(data, data_len);
321
+ #endif
322
+ break;
323
+ }
324
+ case SYBCHAR:
325
+ case SYBTEXT:
326
+ val = ENCODED_STR_NEW(data, data_len);
327
+ break;
328
+ default:
329
+ val = ENCODED_STR_NEW(data, data_len);
330
+ break;
331
+ }
332
+ }
333
+ if (as_array) {
334
+ rb_ary_store(row, i, val);
335
+ } else {
336
+ VALUE key;
337
+ if (rwrap->number_of_results == 0) {
338
+ key = rb_ary_entry(rwrap->fields, i);
339
+ } else {
340
+ key = rb_ary_entry(rb_ary_entry(rwrap->fields, rwrap->number_of_results), i);
341
+ }
342
+ rb_hash_aset(row, key, val);
343
+ }
344
+ }
345
+ return row;
346
+ }
347
+
348
+
349
+ // TinyTds::Client (public)
350
+
351
+ static VALUE rb_tinytds_result_fields(VALUE self) {
352
+ RETCODE dbsqlok_rc, dbresults_rc;
353
+ VALUE fields_processed;
354
+ GET_RESULT_WRAPPER(self);
355
+ dbsqlok_rc = rb_tinytds_result_ok_helper(rwrap->client);
356
+ dbresults_rc = rb_tinytds_result_dbresults_retcode(self);
357
+ fields_processed = rb_ary_entry(rwrap->fields_processed, rwrap->number_of_results);
358
+ if ((dbsqlok_rc == SUCCEED) && (dbresults_rc == SUCCEED) && (fields_processed == Qnil)) {
359
+ /* Default query options. */
360
+ int symbolize_keys = 0;
361
+ VALUE qopts = rb_iv_get(self, "@query_options");
362
+ if (rb_hash_aref(qopts, sym_symbolize_keys) == Qtrue)
363
+ symbolize_keys = 1;
364
+ /* Set number_of_fields count for this result set. */
365
+ rwrap->number_of_fields = dbnumcols(rwrap->client);
366
+ if (rwrap->number_of_fields > 0) {
367
+ /* Create fields for this result set. */
368
+ unsigned int fldi = 0;
369
+ VALUE fields = rb_ary_new2(rwrap->number_of_fields);
370
+ for (fldi = 0; fldi < rwrap->number_of_fields; fldi++) {
371
+ char *colname = dbcolname(rwrap->client, fldi+1);
372
+ VALUE field = symbolize_keys ? rb_str_intern(ENCODED_STR_NEW2(colname)) : rb_obj_freeze(ENCODED_STR_NEW2(colname));
373
+ rb_ary_store(fields, fldi, field);
374
+ }
375
+ /* Store the fields. */
376
+ if (rwrap->number_of_results == 0) {
377
+ rwrap->fields = fields;
378
+ } else if (rwrap->number_of_results == 1) {
379
+ VALUE multi_rs_fields = rb_ary_new();
380
+ rb_ary_store(multi_rs_fields, 0, rwrap->fields);
381
+ rb_ary_store(multi_rs_fields, 1, fields);
382
+ rwrap->fields = multi_rs_fields;
383
+ } else {
384
+ rb_ary_store(rwrap->fields, rwrap->number_of_results, fields);
385
+ }
386
+ }
387
+ rb_ary_store(rwrap->fields_processed, rwrap->number_of_results, Qtrue);
388
+ }
389
+ return rwrap->fields;
390
+ }
391
+
392
+ static VALUE rb_tinytds_result_each(int argc, VALUE * argv, VALUE self) {
393
+ /* Local Vars */
394
+ VALUE qopts, opts, block;
395
+ ID timezone;
396
+ int symbolize_keys = 0, as_array = 0, cache_rows = 0, first = 0, empty_sets = 0;
397
+ tinytds_client_userdata *userdata;
398
+ GET_RESULT_WRAPPER(self);
399
+ userdata = (tinytds_client_userdata *)dbgetuserdata(rwrap->client);
400
+ /* Merge Options Hash To Query Options. Populate Opts & Block Var. */
401
+ qopts = rb_iv_get(self, "@query_options");
402
+ if (rb_scan_args(argc, argv, "01&", &opts, &block) == 1)
403
+ qopts = rb_funcall(qopts, intern_merge, 1, opts);
404
+ rb_iv_set(self, "@query_options", qopts);
405
+ /* Locals From Options */
406
+ if (rb_hash_aref(qopts, sym_first) == Qtrue)
407
+ first = 1;
408
+ if (rb_hash_aref(qopts, sym_symbolize_keys) == Qtrue)
409
+ symbolize_keys = 1;
410
+ if (rb_hash_aref(qopts, sym_as) == sym_array)
411
+ as_array = 1;
412
+ if (rb_hash_aref(qopts, sym_cache_rows) == Qtrue)
413
+ cache_rows = 1;
414
+ if (rb_hash_aref(qopts, sym_timezone) == sym_local) {
415
+ timezone = intern_local;
416
+ } else if (rb_hash_aref(qopts, sym_timezone) == sym_utc) {
417
+ timezone = intern_utc;
418
+ } else {
419
+ rb_warn(":timezone option must be :utc or :local - defaulting to :local");
420
+ timezone = intern_local;
421
+ }
422
+ if (rb_hash_aref(qopts, sym_empty_sets) == Qtrue)
423
+ empty_sets = 1;
424
+ /* Make The Results Or Yield Existing */
425
+ if (NIL_P(rwrap->results)) {
426
+ RETCODE dbsqlok_rc, dbresults_rc;
427
+ rwrap->results = rb_ary_new();
428
+ dbsqlok_rc = rb_tinytds_result_ok_helper(rwrap->client);
429
+ dbresults_rc = rb_tinytds_result_dbresults_retcode(self);
430
+ while ((dbsqlok_rc == SUCCEED) && (dbresults_rc == SUCCEED)) {
431
+ int has_rows = (DBROWS(rwrap->client) == SUCCEED) ? 1 : 0;
432
+ if (has_rows || empty_sets || (rwrap->number_of_results == 0))
433
+ rb_tinytds_result_fields(self);
434
+ if ((has_rows || empty_sets) && rwrap->number_of_fields > 0) {
435
+ /* Create rows for this result set. */
436
+ unsigned long rowi = 0;
437
+ VALUE result = rb_ary_new();
438
+ while (nogvl_dbnextrow(rwrap->client) != NO_MORE_ROWS) {
439
+ VALUE row = rb_tinytds_result_fetch_row(self, timezone, symbolize_keys, as_array);
440
+ if (cache_rows)
441
+ rb_ary_store(result, rowi, row);
442
+ if (!NIL_P(block))
443
+ rb_yield(row);
444
+ if (first) {
445
+ dbcanquery(rwrap->client);
446
+ userdata->dbcancel_sent = 1;
447
+ }
448
+ rowi++;
449
+ }
450
+ rwrap->number_of_rows = rowi;
451
+ /* Store the result. */
452
+ if (cache_rows) {
453
+ if (rwrap->number_of_results == 0) {
454
+ rwrap->results = result;
455
+ } else if (rwrap->number_of_results == 1) {
456
+ VALUE multi_resultsets = rb_ary_new();
457
+ rb_ary_store(multi_resultsets, 0, rwrap->results);
458
+ rb_ary_store(multi_resultsets, 1, result);
459
+ rwrap->results = multi_resultsets;
460
+ } else {
461
+ rb_ary_store(rwrap->results, rwrap->number_of_results, result);
462
+ }
463
+ }
464
+ // If we find results increment the counter that helpers use and setup the next loop.
465
+ rwrap->number_of_results = rwrap->number_of_results + 1;
466
+ dbresults_rc = rb_tinytds_result_dbresults_retcode(self);
467
+ rb_ary_store(rwrap->fields_processed, rwrap->number_of_results, Qnil);
468
+ } else {
469
+ // If we do not find results, side step the rb_tinytds_result_dbresults_retcode helper and
470
+ // manually populate its memoized array while nullifing any memoized fields too before loop.
471
+ dbresults_rc = nogvl_dbresults(rwrap->client);
472
+ rb_ary_store(rwrap->dbresults_retcodes, rwrap->number_of_results, INT2FIX(dbresults_rc));
473
+ rb_ary_store(rwrap->fields_processed, rwrap->number_of_results, Qnil);
474
+ }
475
+ }
476
+ if (dbresults_rc == FAIL)
477
+ rb_warn("TinyTDS: Something in the dbresults() while loop set the return code to FAIL.\n");
478
+ userdata->dbsql_sent = 0;
479
+ } else if (!NIL_P(block)) {
480
+ unsigned long i;
481
+ for (i = 0; i < rwrap->number_of_rows; i++) {
482
+ rb_yield(rb_ary_entry(rwrap->results, i));
483
+ }
484
+ }
485
+ return rwrap->results;
486
+ }
487
+
488
+ static VALUE rb_tinytds_result_cancel(VALUE self) {
489
+ tinytds_client_userdata *userdata;
490
+ GET_RESULT_WRAPPER(self);
491
+ userdata = (tinytds_client_userdata *)dbgetuserdata(rwrap->client);
492
+ if (rwrap->client && !userdata->dbcancel_sent) {
493
+ rb_tinytds_result_ok_helper(rwrap->client);
494
+ dbcancel(rwrap->client);
495
+ userdata->dbcancel_sent = 1;
496
+ userdata->dbsql_sent = 0;
497
+ }
498
+ return Qtrue;
499
+ }
500
+
501
+ static VALUE rb_tinytds_result_do(VALUE self) {
502
+ GET_RESULT_WRAPPER(self);
503
+ if (rwrap->client) {
504
+ rb_tinytds_result_exec_helper(rwrap->client);
505
+ return LONG2NUM((long)dbcount(rwrap->client));
506
+ } else {
507
+ return Qnil;
508
+ }
509
+ }
510
+
511
+ static VALUE rb_tinytds_result_affected_rows(VALUE self) {
512
+ GET_RESULT_WRAPPER(self);
513
+ if (rwrap->client) {
514
+ return LONG2NUM((long)dbcount(rwrap->client));
515
+ } else {
516
+ return Qnil;
517
+ }
518
+ }
519
+
520
+ /* Duplicated in client.c */
521
+ static VALUE rb_tinytds_result_return_code(VALUE self) {
522
+ GET_RESULT_WRAPPER(self);
523
+ if (rwrap->client && dbhasretstat(rwrap->client)) {
524
+ return LONG2NUM((long)dbretstatus(rwrap->client));
525
+ } else {
526
+ return Qnil;
527
+ }
528
+ }
529
+
530
+ static VALUE rb_tinytds_result_insert(VALUE self) {
531
+ GET_RESULT_WRAPPER(self);
532
+ if (rwrap->client) {
533
+ VALUE identity = Qnil;
534
+ rb_tinytds_result_exec_helper(rwrap->client);
535
+ dbcmd(rwrap->client, rwrap->cwrap->identity_insert_sql);
536
+ if (nogvl_dbsqlexec(rwrap->client) != FAIL
537
+ && nogvl_dbresults(rwrap->client) != FAIL
538
+ && DBROWS(rwrap->client) != FAIL) {
539
+ while (nogvl_dbnextrow(rwrap->client) != NO_MORE_ROWS) {
540
+ int col = 1;
541
+ BYTE *data = dbdata(rwrap->client, col);
542
+ DBINT data_len = dbdatlen(rwrap->client, col);
543
+ int null_val = ((data == NULL) && (data_len == 0));
544
+ if (!null_val)
545
+ identity = LL2NUM(*(DBBIGINT *)data);
546
+ }
547
+ }
548
+ return identity;
549
+ } else {
550
+ return Qnil;
551
+ }
552
+ }
553
+
554
+
555
+ // Lib Init
556
+
557
+ void init_tinytds_result() {
558
+ /* Data Classes */
559
+ cBigDecimal = rb_const_get(rb_cObject, rb_intern("BigDecimal"));
560
+ cDate = rb_const_get(rb_cObject, rb_intern("Date"));
561
+ /* Define TinyTds::Result */
562
+ cTinyTdsResult = rb_define_class_under(mTinyTds, "Result", rb_cObject);
563
+ /* Define TinyTds::Result Public Methods */
564
+ rb_define_method(cTinyTdsResult, "fields", rb_tinytds_result_fields, 0);
565
+ rb_define_method(cTinyTdsResult, "each", rb_tinytds_result_each, -1);
566
+ rb_define_method(cTinyTdsResult, "cancel", rb_tinytds_result_cancel, 0);
567
+ rb_define_method(cTinyTdsResult, "do", rb_tinytds_result_do, 0);
568
+ rb_define_method(cTinyTdsResult, "affected_rows", rb_tinytds_result_affected_rows, 0);
569
+ rb_define_method(cTinyTdsResult, "return_code", rb_tinytds_result_return_code, 0);
570
+ rb_define_method(cTinyTdsResult, "insert", rb_tinytds_result_insert, 0);
571
+ /* Intern String Helpers */
572
+ intern_new = rb_intern("new");
573
+ intern_utc = rb_intern("utc");
574
+ intern_local = rb_intern("local");
575
+ intern_merge = rb_intern("merge");
576
+ intern_localtime = rb_intern("localtime");
577
+ intern_civil = rb_intern("civil");
578
+ intern_new_offset = rb_intern("new_offset");
579
+ intern_plus = rb_intern("+");
580
+ intern_divide = rb_intern("/");
581
+ /* Symbol Helpers */
582
+ sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys"));
583
+ sym_as = ID2SYM(rb_intern("as"));
584
+ sym_array = ID2SYM(rb_intern("array"));
585
+ sym_cache_rows = ID2SYM(rb_intern("cache_rows"));
586
+ sym_first = ID2SYM(rb_intern("first"));
587
+ sym_local = ID2SYM(intern_local);
588
+ sym_utc = ID2SYM(intern_utc);
589
+ sym_timezone = ID2SYM(rb_intern("timezone"));
590
+ sym_empty_sets = ID2SYM(rb_intern("empty_sets"));
591
+ /* Data Conversion Options */
592
+ opt_decimal_zero = rb_str_new2("0.0");
593
+ rb_global_variable(&opt_decimal_zero);
594
+ opt_float_zero = rb_float_new((double)0);
595
+ rb_global_variable(&opt_float_zero);
596
+ opt_one = INT2NUM(1);
597
+ opt_zero = INT2NUM(0);
598
+ opt_four = INT2NUM(4);
599
+ opt_19hdr = INT2NUM(1900);
600
+ opt_onek = INT2NUM(1000);
601
+ opt_tenk = INT2NUM(10000);
602
+ opt_onemil = INT2NUM(1000000);
603
+ opt_onebil = INT2NUM(1000000000);
604
+ /* Encoding */
605
+ #ifdef HAVE_RUBY_ENCODING_H
606
+ binaryEncoding = rb_enc_find("binary");
607
+ #endif
608
+ }