tiny_tds 0.6.2-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,114 @@
1
+ # encoding: UTF-8
2
+ require 'rake'
3
+ require 'rake/clean'
4
+ require 'rbconfig'
5
+ require 'rake/testtask'
6
+ require 'rake/extensiontask'
7
+ require 'rubygems/package_task'
8
+
9
+ def test_libs
10
+ ['lib','test']
11
+ end
12
+
13
+ def test_files
14
+ Dir.glob("test/**/*_test.rb").sort
15
+ end
16
+
17
+ gemspec = Gem::Specification::load(File.expand_path('../tiny_tds.gemspec', __FILE__))
18
+
19
+ Rake::TestTask.new do |t|
20
+ t.libs = test_libs
21
+ t.test_files = test_files
22
+ t.verbose = true
23
+ end
24
+
25
+ Gem::PackageTask.new(gemspec) do |pkg|
26
+ pkg.need_tar = false
27
+ pkg.need_zip = false
28
+ end
29
+
30
+ task :compile => ["ports:freetds"] unless ENV['TINYTDS_SKIP_PORTS']
31
+
32
+ task :build => [:clean, :compile]
33
+
34
+ task :default => [:build, :test]
35
+
36
+ Dir["tasks/*.rake"].sort.each { |f| load f }
37
+
38
+ Rake::ExtensionTask.new('tiny_tds', gemspec) do |ext|
39
+ ext.lib_dir = 'lib/tiny_tds'
40
+ if RUBY_PLATFORM =~ /mswin|mingw/ then
41
+ # Define target for extension (supporting fat binaries).
42
+ RUBY_VERSION =~ /(\d+\.\d+)/
43
+ ext.lib_dir = "lib/tiny_tds/#{$1}"
44
+ else
45
+ ext.cross_compile = true
46
+ ext.cross_platform = []
47
+ ext.cross_config_options << "--disable-lookup"
48
+ config_opts = {}
49
+
50
+ platform_host_map = {
51
+ 'x86-mingw32' => 'i586-mingw32msvc',
52
+ 'x64-mingw32' => 'x86_64-w64-mingw32'
53
+ }
54
+
55
+ # This section ensures we setup up rake dependencies and that libiconv
56
+ # and freetds are compiled using the cross-compiler and then passed to
57
+ # extconf.rb in such a way that library detection works.
58
+ platform_host_map.each do |plat, host|
59
+ ext.cross_platform << plat
60
+
61
+ libiconv = define_libiconv_recipe(plat, host)
62
+ freetds = define_freetds_recipe(plat, host, libiconv)
63
+ task "native:#{plat}" => ["ports:freetds:#{plat}"] unless ENV['TINYTDS_SKIP_PORTS']
64
+
65
+ # For some reason --with-freetds-dir and --with-iconv-dir would not work.
66
+ # It seems the default params that extconf.rb constructs include
67
+ # --without-freetds-include, --without-freetds-lib, --without-iconv-lib
68
+ # and --without-iconv-include. Thus we must explicitly override them.
69
+ config_opts[plat] = " --with-freetds-include=#{freetds.path}/include"
70
+ config_opts[plat] += " --with-freetds-lib=#{freetds.path}/lib"
71
+ config_opts[plat] += " --with-iconv-include=#{libiconv.path}/include"
72
+ config_opts[plat] += " --with-iconv-lib=#{libiconv.path}/lib"
73
+ end
74
+
75
+ ext.cross_config_options << config_opts
76
+ end
77
+ end
78
+
79
+ desc "Checks out rake-compiler-dev-box and sets up the cross-compiling box. This can take a long time."
80
+ task 'cross-compile:setup' do
81
+ # Make sure we have the command-line programs we need
82
+ sh 'git', '--version'
83
+ sh 'vagrant', '-v'
84
+
85
+ if Dir.exists? 'rake-compiler-dev-box'
86
+ Dir.chdir 'rake-compiler-dev-box'
87
+ else
88
+ sh 'git', 'clone', 'https://github.com/tjschuck/rake-compiler-dev-box.git'
89
+ Dir.chdir 'rake-compiler-dev-box'
90
+ sh 'patch -p1 < ../compile/rake-compiler-dev-box.patch'
91
+ end
92
+
93
+ sh 'vagrant', 'up'
94
+ end
95
+
96
+ desc "Invokes the cross-compiler to generate gems for windows"
97
+ task 'cross-compile' do
98
+ build_dir = './rake-compiler-dev-box/tiny_tds/'
99
+ if not Dir.exists?(build_dir)
100
+ Dir.mkdir build_dir
101
+ end
102
+ # Copy the current version of tiny_tds into the box directory
103
+ Dir.entries('./').each do |entry|
104
+ next if ['.', '..', 'rake-compiler-dev-box'].include?(entry)
105
+ cp_r entry, build_dir, :remove_destination => true
106
+ end
107
+ Dir.chdir './rake-compiler-dev-box'
108
+ sh 'vagrant ssh -c "package_win32_fat_binary tiny_tds"'
109
+ end
110
+
111
+ desc "Cleans up all of the compiled ports, gems and tmp files from cross-compile"
112
+ task 'cross-compile:clean' do
113
+ rm_r './rake-compiler-dev-box/tiny_tds'
114
+ end
@@ -0,0 +1,31 @@
1
+ diff --git a/bin/package_win32_fat_binary b/bin/package_win32_fat_binary
2
+ index b336eb7..8ef4f98 100755
3
+ --- a/bin/package_win32_fat_binary
4
+ +++ b/bin/package_win32_fat_binary
5
+ @@ -12,9 +12,8 @@ cd '/vagrant'
6
+ # passed in path of gem to be cross-compiled
7
+ cd $1
8
+
9
+ -# need to use 1.8.7 for fat-binaries (1.9.3 can't cross-build 1.8.7)
10
+ -rvm use 1.8.7
11
+ +rvm use 1.9.3
12
+ bundle install
13
+
14
+ bundle exec rake clean
15
+ -bundle exec rake cross native gem RUBY_CC_VERSION=1.8.7:1.9.3:2.0.0
16
+ +bundle exec rake cross native gem RUBY_CC_VERSION=1.9.3:2.0.0:2.1.1
17
+ diff --git a/bin/prepare_xrubies b/bin/prepare_xrubies
18
+ index 0e2043c..bd1d3c8 100755
19
+ --- a/bin/prepare_xrubies
20
+ +++ b/bin/prepare_xrubies
21
+ @@ -18,10 +18,6 @@ rvm all do gem install rake-compiler -v "~> 0.9.2"
22
+ # Use just one CPU for building 1.8.7 and 1.9.3
23
+ export MAKE="make"
24
+
25
+ -# Build 1.8.7 with mingw32 compiler (GCC 4.2)
26
+ -rvm use 1.8.7
27
+ -rake-compiler cross-ruby VERSION=1.8.7-p374 HOST=i586-mingw32msvc
28
+ -
29
+ # Build 1.9.3 using 1.9.3 as base
30
+ rvm use 1.9.3
31
+ rake-compiler cross-ruby VERSION=1.9.3-p545 HOST=i586-mingw32msvc
@@ -0,0 +1,29 @@
1
+ --- a/Makefile.in 2011-08-17 18:57:36.000000000 -0700
2
+ +++ b/Makefile.in 2014-05-02 10:27:01.275813000 -0700
3
+ @@ -772,13 +772,6 @@
4
+
5
+
6
+ install-data-local:
7
+ - $(mkinstalldirs) $(ETC)
8
+ - if test ! -f $(ETC)/freetds.conf; then \
9
+ - $(INSTALL_DATA) $(srcdir)/freetds.conf $(ETC)/freetds.conf; \
10
+ - fi
11
+ - if test ! -f $(ETC)/locales.conf; then \
12
+ - $(INSTALL_DATA) $(srcdir)/locales.conf $(ETC)/locales.conf; \
13
+ - fi
14
+
15
+ clean-local:
16
+ find . \( -name \*.test_output -o -name \*.bb -o -name \*.bbg -o -name \*.da -o -name \*.gc\* \) -exec rm -f {} \;
17
+ --- a/src/pool/Makefile.in 2011-08-17 18:57:36.000000000 -0700
18
+ +++ b/src/pool/Makefile.in 2014-05-02 10:32:39.628347600 -0700
19
+ @@ -574,10 +574,6 @@
20
+
21
+
22
+ install-data-local:
23
+ - $(mkinstalldirs) $(ETC)
24
+ - if test ! -f $(ETC)/pool.conf; then \
25
+ - $(INSTALL_DATA) $(srcdir)/pool.conf $(ETC)/pool.conf; \
26
+ - fi
27
+
28
+ # Tell versions [3.59,3.63) of GNU make to not export all variables.
29
+ # Otherwise a system limit (for SysV at least) may be exceeded.
@@ -0,0 +1,11 @@
1
+ --- a/src/dblib/dblib.c
2
+ +++ b/src/dblib/dblib.c
3
+ @@ -765,7 +765,7 @@ dbsetlname(LOGINREC * login, const char *value, int which)
4
+ return FAIL;
5
+ }
6
+
7
+ - if (TDS_MAX_LOGIN_STR_SZ < strlen(value)) {
8
+ + if (login->tds_login->tds_version < 0x700 && TDS_MAX_LOGIN_STR_SZ < strlen(value)) {
9
+ dbperror(NULL, SYBENTLL, 0);
10
+ return FAIL;
11
+ }
@@ -0,0 +1,42 @@
1
+ --- a/src/tds/sspi.c
2
+ +++ b/src/tds/sspi.c
3
+ @@ -172,8 +172,19 @@ tds_sspi_handle_next(TDSSOCKET * tds, struct tds_authentication * tds_auth, size
4
+
5
+ free(auth_buf);
6
+
7
+ - if (status != SEC_E_OK)
8
+ + switch (status) {
9
+ + case SEC_I_COMPLETE_AND_CONTINUE:
10
+ + sec_fn->CompleteAuthToken(&auth->cred_ctx, &out_desc);
11
+ + break;
12
+ +
13
+ + case SEC_I_CONTINUE_NEEDED:
14
+ + case SEC_E_OK:
15
+ + break;
16
+ +
17
+ + default:
18
+ return TDS_FAIL;
19
+ + }
20
+ +
21
+ if (out_buf.cbBuffer == 0)
22
+ return TDS_SUCCEED;
23
+
24
+ @@ -275,9 +286,16 @@ tds_sspi_get_auth(TDSSOCKET * tds)
25
+ &auth->cred_ctx, &desc,
26
+ &attrs, &ts);
27
+
28
+ - if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
29
+ + switch (status) {
30
+ + case SEC_I_COMPLETE_AND_CONTINUE:
31
+ sec_fn->CompleteAuthToken(&auth->cred_ctx, &desc);
32
+ - } else if(status != SEC_E_OK) {
33
+ + break;
34
+ +
35
+ + case SEC_I_CONTINUE_NEEDED:
36
+ + case SEC_E_OK:
37
+ + break;
38
+ +
39
+ + default:
40
+ free(auth->sname);
41
+ free(auth->tds_auth.packet);
42
+ sec_fn->FreeCredentialsHandle(&auth->cred);
@@ -0,0 +1,408 @@
1
+ #include <tiny_tds_ext.h>
2
+ #include <errno.h>
3
+
4
+ VALUE cTinyTdsClient;
5
+ extern VALUE mTinyTds, cTinyTdsError;
6
+ static ID sym_username, sym_password, sym_dataserver, sym_database, sym_appname, sym_tds_version, sym_login_timeout, sym_timeout, sym_encoding, sym_azure;
7
+ static ID intern_source_eql, intern_severity_eql, intern_db_error_number_eql, intern_os_error_number_eql;
8
+ static ID intern_new, intern_dup, intern_transpose_iconv_encoding, intern_local_offset, intern_gsub;
9
+ VALUE opt_escape_regex, opt_escape_dblquote;
10
+
11
+
12
+ // Lib Macros
13
+
14
+ #define GET_CLIENT_WRAPPER(self) \
15
+ tinytds_client_wrapper *cwrap; \
16
+ Data_Get_Struct(self, tinytds_client_wrapper, cwrap)
17
+
18
+ #define REQUIRE_OPEN_CLIENT(cwrap) \
19
+ if (cwrap->closed || cwrap->userdata->closed) { \
20
+ rb_raise(cTinyTdsError, "closed connection"); \
21
+ return Qnil; \
22
+ }
23
+
24
+
25
+ // Lib Backend (Helpers)
26
+
27
+ VALUE rb_tinytds_raise_error(DBPROCESS *dbproc, int cancel, char *error, char *source, int severity, int dberr, int oserr) {
28
+ GET_CLIENT_USERDATA(dbproc);
29
+ if (cancel && !dbdead(dbproc) && userdata && !userdata->closed) {
30
+ userdata->dbsqlok_sent = 1;
31
+ dbsqlok(dbproc);
32
+ userdata->dbcancel_sent = 1;
33
+ dbcancel(dbproc);
34
+ }
35
+ VALUE e = rb_exc_new2(cTinyTdsError, error);
36
+ rb_funcall(e, intern_source_eql, 1, rb_str_new2(source));
37
+ if (severity)
38
+ rb_funcall(e, intern_severity_eql, 1, INT2FIX(severity));
39
+ if (dberr)
40
+ rb_funcall(e, intern_db_error_number_eql, 1, INT2FIX(dberr));
41
+ if (oserr)
42
+ rb_funcall(e, intern_os_error_number_eql, 1, INT2FIX(oserr));
43
+ rb_exc_raise(e);
44
+ return Qnil;
45
+ }
46
+
47
+
48
+ // Lib Backend (Memory Management & Handlers)
49
+
50
+ 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
+
54
+ /* Everything should cancel by default */
55
+ int return_value = INT_CANCEL;
56
+ int cancel = 0;
57
+
58
+ /* These error codes are documented in include/sybdb.h in FreeTDS */
59
+ switch(dberr) {
60
+
61
+ /* We don't want to raise these as a ruby exception for various reasons */
62
+ case 100: /* SYBEVERDOWN, indicating the connection can only be v7.1 */
63
+ case SYBESEOF: /* Usually accompanied by another more useful error */
64
+ case SYBESMSG: /* Generic "check messages from server" error */
65
+ case SYBEICONVI: /* Just return ?s to the client, as explained in readme */
66
+ return return_value;
67
+
68
+ case SYBEICONVO:
69
+ dbfreebuf(dbproc);
70
+ break;
71
+
72
+ case SYBETIME:
73
+ /*
74
+ SYBETIME is the only error that can send INT_TIMEOUT or INT_CONTINUE,
75
+ but we don't ever want to automatically retry. Instead have the app
76
+ decide what to do. We would use INT_TIMEOUT, however it seems tdserror()
77
+ in tds/util.c converts INT_TIMEOUT to INT_CONTINUE.
78
+ */
79
+ cancel = 1;
80
+ break;
81
+
82
+ case SYBEWRIT:
83
+ /* Write errors may happen after we abort a statement */
84
+ if (userdata && (userdata->dbsqlok_sent || userdata->dbcancel_sent)) {
85
+ return return_value;
86
+ }
87
+ cancel = 1;
88
+ break;
89
+ }
90
+
91
+ /*
92
+ When in non-blocking mode we need to store the exception data to throw it
93
+ once the blocking call returns, otherwise we will segfault ruby since part
94
+ of the contract of the ruby non-blocking indicator is that you do not call
95
+ any of the ruby C API.
96
+ */
97
+ if (userdata && userdata->nonblocking) {
98
+ if (cancel && !dbdead(dbproc) && !userdata->closed) {
99
+ dbcancel(dbproc);
100
+ userdata->dbcancel_sent = 1;
101
+ }
102
+
103
+ /*
104
+ If we've already captured an error message, don't overwrite it. This is
105
+ here because FreeTDS sends a generic "General SQL Server error" message
106
+ that will overwrite the real message. This is not normally a problem
107
+ because a ruby exception is normally thrown and we bail before the
108
+ generic message can be sent.
109
+ */
110
+ if (!userdata->nonblocking_error.is_set) {
111
+ userdata->nonblocking_error.cancel = cancel;
112
+ strcpy(userdata->nonblocking_error.error, dberrstr);
113
+ strcpy(userdata->nonblocking_error.source, source);
114
+ userdata->nonblocking_error.severity = severity;
115
+ userdata->nonblocking_error.dberr = dberr;
116
+ userdata->nonblocking_error.oserr = oserr;
117
+ userdata->nonblocking_error.is_set = 1;
118
+ }
119
+
120
+ } else {
121
+ rb_tinytds_raise_error(dbproc, cancel, dberrstr, source, severity, dberr, oserr);
122
+ }
123
+
124
+ return return_value;
125
+ }
126
+
127
+ 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
+ GET_CLIENT_USERDATA(dbproc);
130
+ if (severity > 10) {
131
+ // See tinytds_err_handler() for info about why we do this
132
+ if (userdata && userdata->nonblocking) {
133
+ if (!userdata->nonblocking_error.is_set) {
134
+ userdata->nonblocking_error.cancel = 1;
135
+ strcpy(userdata->nonblocking_error.error, msgtext);
136
+ strcpy(userdata->nonblocking_error.source, source);
137
+ userdata->nonblocking_error.severity = severity;
138
+ userdata->nonblocking_error.dberr = msgno;
139
+ userdata->nonblocking_error.oserr = msgstate;
140
+ userdata->nonblocking_error.is_set = 1;
141
+ }
142
+ if (!dbdead(dbproc) && !userdata->closed) {
143
+ dbcancel(dbproc);
144
+ userdata->dbcancel_sent = 1;
145
+ }
146
+ } else {
147
+ rb_tinytds_raise_error(dbproc, 1, msgtext, source, severity, msgno, msgstate);
148
+ }
149
+ }
150
+ return 0;
151
+ }
152
+
153
+ static void rb_tinytds_client_reset_userdata(tinytds_client_userdata *userdata) {
154
+ userdata->timing_out = 0;
155
+ userdata->dbsql_sent = 0;
156
+ userdata->dbsqlok_sent = 0;
157
+ userdata->dbcancel_sent = 0;
158
+ userdata->nonblocking = 0;
159
+ userdata->nonblocking_error.is_set = 0;
160
+ }
161
+
162
+ static void rb_tinytds_client_mark(void *ptr) {
163
+ tinytds_client_wrapper *cwrap = (tinytds_client_wrapper *)ptr;
164
+ if (cwrap) {
165
+ rb_gc_mark(cwrap->charset);
166
+ }
167
+ }
168
+
169
+ static void rb_tinytds_client_free(void *ptr) {
170
+ tinytds_client_wrapper *cwrap = (tinytds_client_wrapper *)ptr;
171
+ if (cwrap->login)
172
+ dbloginfree(cwrap->login);
173
+ if (cwrap->client && !cwrap->closed) {
174
+ dbclose(cwrap->client);
175
+ cwrap->closed = 1;
176
+ cwrap->userdata->closed = 1;
177
+ }
178
+ xfree(cwrap->userdata);
179
+ xfree(ptr);
180
+ }
181
+
182
+ static VALUE allocate(VALUE klass) {
183
+ VALUE obj;
184
+ tinytds_client_wrapper *cwrap;
185
+ obj = Data_Make_Struct(klass, tinytds_client_wrapper, rb_tinytds_client_mark, rb_tinytds_client_free, cwrap);
186
+ cwrap->closed = 1;
187
+ cwrap->charset = Qnil;
188
+ cwrap->userdata = malloc(sizeof(tinytds_client_userdata));
189
+ cwrap->userdata->closed = 1;
190
+ rb_tinytds_client_reset_userdata(cwrap->userdata);
191
+ return obj;
192
+ }
193
+
194
+
195
+ // TinyTds::Client (public)
196
+
197
+ static VALUE rb_tinytds_tds_version(VALUE self) {
198
+ GET_CLIENT_WRAPPER(self);
199
+ return INT2FIX(dbtds(cwrap->client));
200
+ }
201
+
202
+ static VALUE rb_tinytds_close(VALUE self) {
203
+ GET_CLIENT_WRAPPER(self);
204
+ if (cwrap->client && !cwrap->closed) {
205
+ dbclose(cwrap->client);
206
+ cwrap->closed = 1;
207
+ cwrap->userdata->closed = 1;
208
+ }
209
+ return Qtrue;
210
+ }
211
+
212
+ static VALUE rb_tinytds_dead(VALUE self) {
213
+ GET_CLIENT_WRAPPER(self);
214
+ return dbdead(cwrap->client) ? Qtrue : Qfalse;
215
+ }
216
+
217
+ static VALUE rb_tinytds_closed(VALUE self) {
218
+ GET_CLIENT_WRAPPER(self);
219
+ return (cwrap->closed || cwrap->userdata->closed) ? Qtrue : Qfalse;
220
+ }
221
+
222
+ static VALUE rb_tinytds_canceled(VALUE self) {
223
+ GET_CLIENT_WRAPPER(self);
224
+ return cwrap->userdata->dbcancel_sent ? Qtrue : Qfalse;
225
+ }
226
+
227
+ static VALUE rb_tinytds_sqlsent(VALUE self) {
228
+ GET_CLIENT_WRAPPER(self);
229
+ return cwrap->userdata->dbsql_sent ? Qtrue : Qfalse;
230
+ }
231
+
232
+ static VALUE rb_tinytds_execute(VALUE self, VALUE sql) {
233
+ GET_CLIENT_WRAPPER(self);
234
+ rb_tinytds_client_reset_userdata(cwrap->userdata);
235
+ REQUIRE_OPEN_CLIENT(cwrap);
236
+ dbcmd(cwrap->client, StringValuePtr(sql));
237
+ if (dbsqlsend(cwrap->client) == FAIL) {
238
+ rb_warn("TinyTds: dbsqlsend() returned FAIL.\n");
239
+ return Qfalse;
240
+ }
241
+ cwrap->userdata->dbsql_sent = 1;
242
+ VALUE result = rb_tinytds_new_result_obj(cwrap);
243
+ 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;
248
+ }
249
+
250
+ static VALUE rb_tinytds_charset(VALUE self) {
251
+ GET_CLIENT_WRAPPER(self);
252
+ return cwrap->charset;
253
+ }
254
+
255
+ static VALUE rb_tinytds_encoding(VALUE self) {
256
+ GET_CLIENT_WRAPPER(self);
257
+ return rb_enc_from_encoding(cwrap->encoding);
258
+ }
259
+
260
+ static VALUE rb_tinytds_escape(VALUE self, VALUE string) {
261
+ Check_Type(string, T_STRING);
262
+ GET_CLIENT_WRAPPER(self);
263
+ VALUE new_string = rb_funcall(string, intern_gsub, 2, opt_escape_regex, opt_escape_dblquote);
264
+ rb_enc_associate(new_string, cwrap->encoding);
265
+ return new_string;
266
+ }
267
+
268
+ /* Duplicated in result.c */
269
+ static VALUE rb_tinytds_return_code(VALUE self) {
270
+ GET_CLIENT_WRAPPER(self);
271
+ if (cwrap->client && dbhasretstat(cwrap->client)) {
272
+ return LONG2NUM((long)dbretstatus(cwrap->client));
273
+ } else {
274
+ return Qnil;
275
+ }
276
+ }
277
+
278
+ static VALUE rb_tinytds_identity_sql(VALUE self) {
279
+ GET_CLIENT_WRAPPER(self);
280
+ return rb_str_new2(cwrap->identity_insert_sql);
281
+ }
282
+
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
+
291
+
292
+ // TinyTds::Client (protected)
293
+
294
+ static VALUE rb_tinytds_connect(VALUE self, VALUE opts) {
295
+ /* Parsing options hash to local vars. */
296
+ VALUE user, pass, dataserver, database, app, version, ltimeout, timeout, charset, azure;
297
+ user = rb_hash_aref(opts, sym_username);
298
+ pass = rb_hash_aref(opts, sym_password);
299
+ dataserver = rb_hash_aref(opts, sym_dataserver);
300
+ database = rb_hash_aref(opts, sym_database);
301
+ app = rb_hash_aref(opts, sym_appname);
302
+ version = rb_hash_aref(opts, sym_tds_version);
303
+ ltimeout = rb_hash_aref(opts, sym_login_timeout);
304
+ timeout = rb_hash_aref(opts, sym_timeout);
305
+ charset = rb_hash_aref(opts, sym_encoding);
306
+ azure = rb_hash_aref(opts, sym_azure);
307
+ /* Dealing with options. */
308
+ if (dbinit() == FAIL) {
309
+ rb_raise(cTinyTdsError, "failed dbinit() function");
310
+ return self;
311
+ }
312
+ dberrhandle(tinytds_err_handler);
313
+ dbmsghandle(tinytds_msg_handler);
314
+ GET_CLIENT_WRAPPER(self);
315
+ cwrap->login = dblogin();
316
+ if (!NIL_P(version))
317
+ dbsetlversion(cwrap->login, NUM2INT(version));
318
+ if (!NIL_P(user))
319
+ dbsetluser(cwrap->login, StringValuePtr(user));
320
+ if (!NIL_P(pass))
321
+ dbsetlpwd(cwrap->login, StringValuePtr(pass));
322
+ if (!NIL_P(app))
323
+ dbsetlapp(cwrap->login, StringValuePtr(app));
324
+ if (!NIL_P(ltimeout))
325
+ dbsetlogintime(NUM2INT(ltimeout));
326
+ if (!NIL_P(timeout))
327
+ dbsettime(NUM2INT(timeout));
328
+ if (!NIL_P(charset))
329
+ DBSETLCHARSET(cwrap->login, StringValuePtr(charset));
330
+ if (!NIL_P(database) && (azure == Qtrue)) {
331
+ #ifdef DBSETLDBNAME
332
+ DBSETLDBNAME(cwrap->login, StringValuePtr(database));
333
+ #else
334
+ rb_warn("TinyTds: Azure connections not supported in this version of FreeTDS.\n");
335
+ #endif
336
+ }
337
+ cwrap->client = dbopen(cwrap->login, StringValuePtr(dataserver));
338
+ if (cwrap->client) {
339
+ cwrap->closed = 0;
340
+ cwrap->charset = charset;
341
+ if (!NIL_P(version))
342
+ dbsetversion(NUM2INT(version));
343
+ dbsetuserdata(cwrap->client, (BYTE*)cwrap->userdata);
344
+ cwrap->userdata->closed = 0;
345
+ if (!NIL_P(database) && (azure != Qtrue)) {
346
+ dbuse(cwrap->client, StringValuePtr(database));
347
+ }
348
+ VALUE transposed_encoding = rb_funcall(cTinyTdsClient, intern_transpose_iconv_encoding, 1, charset);
349
+ cwrap->encoding = rb_enc_find(StringValuePtr(transposed_encoding));
350
+ if (dbtds(cwrap->client) <= 7) {
351
+ cwrap->identity_insert_sql = "SELECT CAST(@@IDENTITY AS bigint) AS Ident";
352
+ } else {
353
+ cwrap->identity_insert_sql = "SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident";
354
+ }
355
+ }
356
+ return self;
357
+ }
358
+
359
+
360
+ // Lib Init
361
+
362
+ void init_tinytds_client() {
363
+ cTinyTdsClient = rb_define_class_under(mTinyTds, "Client", rb_cObject);
364
+ rb_define_alloc_func(cTinyTdsClient, allocate);
365
+ /* Define TinyTds::Client Public Methods */
366
+ rb_define_method(cTinyTdsClient, "tds_version", rb_tinytds_tds_version, 0);
367
+ rb_define_method(cTinyTdsClient, "close", rb_tinytds_close, 0);
368
+ rb_define_method(cTinyTdsClient, "closed?", rb_tinytds_closed, 0);
369
+ rb_define_method(cTinyTdsClient, "canceled?", rb_tinytds_canceled, 0);
370
+ rb_define_method(cTinyTdsClient, "dead?", rb_tinytds_dead, 0);
371
+ rb_define_method(cTinyTdsClient, "sqlsent?", rb_tinytds_sqlsent, 0);
372
+ rb_define_method(cTinyTdsClient, "execute", rb_tinytds_execute, 1);
373
+ rb_define_method(cTinyTdsClient, "charset", rb_tinytds_charset, 0);
374
+ rb_define_method(cTinyTdsClient, "encoding", rb_tinytds_encoding, 0);
375
+ rb_define_method(cTinyTdsClient, "escape", rb_tinytds_escape, 1);
376
+ rb_define_method(cTinyTdsClient, "return_code", rb_tinytds_return_code, 0);
377
+ 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
+ /* Define TinyTds::Client Protected Methods */
380
+ rb_define_protected_method(cTinyTdsClient, "connect", rb_tinytds_connect, 1);
381
+ /* Symbols For Connect */
382
+ sym_username = ID2SYM(rb_intern("username"));
383
+ sym_password = ID2SYM(rb_intern("password"));
384
+ sym_dataserver = ID2SYM(rb_intern("dataserver"));
385
+ sym_database = ID2SYM(rb_intern("database"));
386
+ sym_appname = ID2SYM(rb_intern("appname"));
387
+ sym_tds_version = ID2SYM(rb_intern("tds_version"));
388
+ sym_login_timeout = ID2SYM(rb_intern("login_timeout"));
389
+ sym_timeout = ID2SYM(rb_intern("timeout"));
390
+ sym_encoding = ID2SYM(rb_intern("encoding"));
391
+ sym_azure = ID2SYM(rb_intern("azure"));
392
+ /* Intern TinyTds::Error Accessors */
393
+ intern_source_eql = rb_intern("source=");
394
+ intern_severity_eql = rb_intern("severity=");
395
+ intern_db_error_number_eql = rb_intern("db_error_number=");
396
+ intern_os_error_number_eql = rb_intern("os_error_number=");
397
+ /* Intern Misc */
398
+ intern_new = rb_intern("new");
399
+ intern_dup = rb_intern("dup");
400
+ intern_transpose_iconv_encoding = rb_intern("transpose_iconv_encoding");
401
+ intern_local_offset = rb_intern("local_offset");
402
+ intern_gsub = rb_intern("gsub");
403
+ /* Escape Regexp Global */
404
+ opt_escape_regex = rb_funcall(rb_cRegexp, intern_new, 1, rb_str_new2("\\\'"));
405
+ opt_escape_dblquote = rb_str_new2("''");
406
+ rb_global_variable(&opt_escape_regex);
407
+ rb_global_variable(&opt_escape_dblquote);
408
+ }