Skip to content

Commit ec25cc5

Browse files
authored
v4: Refactor #new and #connect (#596)
* `TinyTds::Client.new` now accepts keyword arguments instead of a hash * Separate `#new` and `#connect` * Rename `encoding` keyword argument to `charset` `encoding` denotes the actual `Encoding` then used to associate strings.
1 parent 654570a commit ec25cc5

File tree

7 files changed

+114
-158
lines changed

7 files changed

+114
-158
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
* `TinyTds::Result` is now a pure Ruby class
88
* `#execute`: Replaced `opts` hash with keyword arguments
99
* Removed `symbolize_keys` and `cache_rows` from `#default_query_options`
10+
* `TinyTds::Client.new` now accepts keyword arguments instead of a hash
11+
* Renamed `tds_version` and `tds_version_info` to `server_version` and `server_version_info`
12+
* Separate `#new` and `#connect`
13+
* Instead, before running `#do`, `#execute` or `#insert`, `tiny_tds` will check if the connection is active and re-connect if needed.
1014

1115
## 3.3.0
1216

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,15 @@ Connect to a database.
9898
client = TinyTds::Client.new username: 'sa', password: 'secret', host: 'mydb.host.net'
9999
```
100100

101-
Creating a new client takes a hash of options. For valid iconv encoding options, see the output of `iconv -l`. Only a few have been tested, and are highly recommended to leave blank for the UTF-8 default.
101+
Creating a new client takes keyword arguments. For valid iconv encoding options, see the output of `iconv -l`. Only a few have been tested, and are highly recommended to leave blank for the UTF-8 default.
102102

103103
* :username - The database server user.
104104
* :password - The user password.
105105
* :dataserver - Can be the name for your data server as defined in freetds.conf. Raw hostname or hostname:port will work here too. FreeTDS says that a named instance like 'localhost\SQLEXPRESS' will work too, but I highly suggest that you use the :host and :port options below. [Google how to find your host port if you are using named instances](http://bit.ly/xAf2jm) or [go here](http://msdn.microsoft.com/en-us/library/ms181087.aspx).
106106
* :host - Used if :dataserver blank. Can be an host name or IP.
107107
* :port - Defaults to 1433. Only used if :host is used.
108108
* :database - The default database to use.
109-
* :appname - Short string seen in SQL Servers process/activity window.
109+
* :app_name - Short string seen in SQL Servers process/activity window.
110110
* :tds_version - TDS version. Defaults to "7.3".
111111
* :login_timeout - Seconds to wait for login. Default to 60 seconds.
112112
* :timeout - Seconds to wait for a response to a SQL command. Default 5 seconds. Timeouts caused by network failure will raise a timeout error 1 second after the configured timeout limit is hit (see [#481](https://github.com/rails-sqlserver/tiny_tds/pull/481) for details).

ext/tiny_tds/client.c

Lines changed: 56 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@
44

55
VALUE cTinyTdsClient;
66
extern VALUE mTinyTds, cTinyTdsError;
7-
static ID sym_username, sym_password, sym_dataserver, sym_database, sym_appname, sym_tds_version, sym_login_timeout, sym_timeout, sym_encoding, sym_azure, sym_contained, sym_use_utf16, sym_message_handler;
87
static ID intern_source_eql, intern_severity_eql, intern_db_error_number_eql, intern_os_error_number_eql;
9-
static ID intern_new, intern_dup, intern_transpose_iconv_encoding, intern_local_offset, intern_gsub, intern_call;
8+
static ID intern_new, intern_dup, intern_local_offset, intern_gsub, intern_call, intern_active, intern_connect;
109
VALUE opt_escape_regex, opt_escape_dblquote;
1110

1211
static ID id_ivar_fields, id_ivar_rows, id_ivar_return_code, id_ivar_affected_rows, id_ivar_default_query_options, intern_bigd, intern_divide;
@@ -16,15 +15,6 @@ static VALUE cTinyTdsResult, cKernel, cDate;
1615
rb_encoding *binaryEncoding;
1716
VALUE opt_onek, opt_onebil, opt_float_zero, opt_four, opt_tenk;
1817

19-
static void rb_tinytds_client_mark(void *ptr)
20-
{
21-
tinytds_client_wrapper *cwrap = (tinytds_client_wrapper *)ptr;
22-
23-
if (cwrap) {
24-
rb_gc_mark(cwrap->charset);
25-
}
26-
}
27-
2818
static void rb_tinytds_client_free(void *ptr)
2919
{
3020
tinytds_client_wrapper *cwrap = (tinytds_client_wrapper *)ptr;
@@ -52,7 +42,7 @@ static size_t tinytds_client_wrapper_size(const void* data)
5242
static const rb_data_type_t tinytds_client_wrapper_type = {
5343
.wrap_struct_name = "tinytds_client_wrapper",
5444
.function = {
55-
.dmark = rb_tinytds_client_mark,
45+
.dmark = NULL,
5646
.dfree = rb_tinytds_client_free,
5747
.dsize = tinytds_client_wrapper_size,
5848
},
@@ -460,7 +450,6 @@ static VALUE allocate(VALUE klass)
460450
tinytds_client_wrapper *cwrap;
461451
obj = TypedData_Make_Struct(klass, tinytds_client_wrapper, &tinytds_client_wrapper_type, cwrap);
462452
cwrap->closed = 1;
463-
cwrap->charset = Qnil;
464453
cwrap->userdata = malloc(sizeof(tinytds_client_userdata));
465454
cwrap->userdata->closed = 1;
466455
rb_tinytds_client_reset_userdata(cwrap->userdata);
@@ -469,11 +458,15 @@ static VALUE allocate(VALUE klass)
469458

470459

471460
// TinyTds::Client (public)
472-
473-
static VALUE rb_tinytds_tds_version(VALUE self)
461+
static VALUE rb_tinytds_server_version(VALUE self)
474462
{
475463
GET_CLIENT_WRAPPER(self);
476-
return INT2FIX(dbtds(cwrap->client));
464+
465+
if (rb_funcall(self, intern_active, 0) == Qtrue) {
466+
return INT2FIX(dbtds(cwrap->client));
467+
} else {
468+
return Qnil;
469+
}
477470
}
478471

479472
static VALUE rb_tinytds_close(VALUE self)
@@ -746,6 +739,11 @@ static VALUE rb_tinytds_execute(int argc, VALUE *argv, VALUE self)
746739
}
747740

748741
GET_CLIENT_WRAPPER(self);
742+
743+
if (rb_funcall(self, intern_active, 0) == Qfalse) {
744+
rb_funcall(self, intern_connect, 0);
745+
}
746+
749747
rb_tinytds_send_sql_to_server(cwrap, sql);
750748

751749
VALUE result = rb_obj_alloc(cTinyTdsResult);
@@ -857,6 +855,11 @@ static VALUE rb_tiny_tds_insert(VALUE self, VALUE sql)
857855
{
858856
VALUE identity = Qnil;
859857
GET_CLIENT_WRAPPER(self);
858+
859+
if (rb_funcall(self, intern_active, 0) == Qfalse) {
860+
rb_funcall(self, intern_connect, 0);
861+
}
862+
860863
rb_tinytds_send_sql_to_server(cwrap, sql);
861864
rb_tinytds_result_exec_helper(cwrap->client);
862865

@@ -886,18 +889,17 @@ static VALUE rb_tiny_tds_insert(VALUE self, VALUE sql)
886889
static VALUE rb_tiny_tds_do(VALUE self, VALUE sql)
887890
{
888891
GET_CLIENT_WRAPPER(self);
892+
893+
if (rb_funcall(self, intern_active, 0) == Qfalse) {
894+
rb_funcall(self, intern_connect, 0);
895+
}
896+
889897
rb_tinytds_send_sql_to_server(cwrap, sql);
890898
rb_tinytds_result_exec_helper(cwrap->client);
891899

892900
return rb_tinytds_affected_rows(cwrap->client);
893901
}
894902

895-
static VALUE rb_tinytds_charset(VALUE self)
896-
{
897-
GET_CLIENT_WRAPPER(self);
898-
return cwrap->charset;
899-
}
900-
901903
static VALUE rb_tinytds_encoding(VALUE self)
902904
{
903905
GET_CLIENT_WRAPPER(self);
@@ -925,25 +927,25 @@ static VALUE rb_tinytds_identity_sql(VALUE self)
925927

926928
// TinyTds::Client (protected)
927929

928-
static VALUE rb_tinytds_connect(VALUE self, VALUE opts)
930+
static VALUE rb_tinytds_connect(VALUE self)
929931
{
930932
/* Parsing options hash to local vars. */
931-
VALUE user, pass, dataserver, database, app, version, ltimeout, timeout, charset, azure, contained, use_utf16;
933+
VALUE username, password, dataserver, database, app_name, tds_version, login_timeout, timeout, charset, azure, contained, use_utf16;
932934
GET_CLIENT_WRAPPER(self);
933935

934-
user = rb_hash_aref(opts, sym_username);
935-
pass = rb_hash_aref(opts, sym_password);
936-
dataserver = rb_hash_aref(opts, sym_dataserver);
937-
database = rb_hash_aref(opts, sym_database);
938-
app = rb_hash_aref(opts, sym_appname);
939-
version = rb_hash_aref(opts, sym_tds_version);
940-
ltimeout = rb_hash_aref(opts, sym_login_timeout);
941-
timeout = rb_hash_aref(opts, sym_timeout);
942-
charset = rb_hash_aref(opts, sym_encoding);
943-
azure = rb_hash_aref(opts, sym_azure);
944-
contained = rb_hash_aref(opts, sym_contained);
945-
use_utf16 = rb_hash_aref(opts, sym_use_utf16);
946-
cwrap->userdata->message_handler = rb_hash_aref(opts, sym_message_handler);
936+
app_name = rb_iv_get(self, "@app_name");
937+
azure = rb_iv_get(self, "@azure");
938+
contained = rb_iv_get(self, "@contained");
939+
database = rb_iv_get(self, "@database");
940+
dataserver = rb_iv_get(self, "@dataserver");
941+
charset = rb_iv_get(self, "@charset");
942+
login_timeout = rb_iv_get(self, "@login_timeout");
943+
password = rb_iv_get(self, "@password");
944+
tds_version = rb_iv_get(self, "@tds_version");
945+
timeout = rb_iv_get(self, "@timeout");
946+
username = rb_iv_get(self, "@username");
947+
use_utf16 = rb_iv_get(self, "@use_utf16");
948+
cwrap->userdata->message_handler = rb_iv_get(self, "@message_handler");
947949

948950
/* Dealing with options. */
949951
if (dbinit() == FAIL) {
@@ -955,24 +957,24 @@ static VALUE rb_tinytds_connect(VALUE self, VALUE opts)
955957
dbmsghandle(tinytds_msg_handler);
956958
cwrap->login = dblogin();
957959

958-
if (!NIL_P(version)) {
959-
dbsetlversion(cwrap->login, NUM2INT(version));
960+
if (!NIL_P(tds_version)) {
961+
dbsetlversion(cwrap->login, NUM2INT(tds_version));
960962
}
961963

962-
if (!NIL_P(user)) {
963-
dbsetluser(cwrap->login, StringValueCStr(user));
964+
if (!NIL_P(username)) {
965+
dbsetluser(cwrap->login, StringValueCStr(username));
964966
}
965967

966-
if (!NIL_P(pass)) {
967-
dbsetlpwd(cwrap->login, StringValueCStr(pass));
968+
if (!NIL_P(password)) {
969+
dbsetlpwd(cwrap->login, StringValueCStr(password));
968970
}
969971

970-
if (!NIL_P(app)) {
971-
dbsetlapp(cwrap->login, StringValueCStr(app));
972+
if (!NIL_P(app_name)) {
973+
dbsetlapp(cwrap->login, StringValueCStr(app_name));
972974
}
973975

974-
if (!NIL_P(ltimeout)) {
975-
dbsetlogintime(NUM2INT(ltimeout));
976+
if (!NIL_P(login_timeout)) {
977+
dbsetlogintime(NUM2INT(login_timeout));
976978
}
977979

978980
if (!NIL_P(charset)) {
@@ -981,19 +983,7 @@ static VALUE rb_tinytds_connect(VALUE self, VALUE opts)
981983

982984
if (!NIL_P(database)) {
983985
if (azure == Qtrue || contained == Qtrue) {
984-
#ifdef DBSETLDBNAME
985986
DBSETLDBNAME(cwrap->login, StringValueCStr(database));
986-
#else
987-
988-
if (azure == Qtrue) {
989-
rb_warn("TinyTds: :azure option is not supported in this version of FreeTDS.\n");
990-
}
991-
992-
if (contained == Qtrue) {
993-
rb_warn("TinyTds: :contained option is not supported in this version of FreeTDS.\n");
994-
}
995-
996-
#endif
997987
}
998988
}
999989

@@ -1015,10 +1005,9 @@ static VALUE rb_tinytds_connect(VALUE self, VALUE opts)
10151005
VALUE transposed_encoding, timeout_string;
10161006

10171007
cwrap->closed = 0;
1018-
cwrap->charset = charset;
10191008

1020-
if (!NIL_P(version)) {
1021-
dbsetversion(NUM2INT(version));
1009+
if (!NIL_P(tds_version)) {
1010+
dbsetversion(NUM2INT(tds_version));
10221011
}
10231012

10241013
if (!NIL_P(timeout)) {
@@ -1037,8 +1026,7 @@ static VALUE rb_tinytds_connect(VALUE self, VALUE opts)
10371026
dbuse(cwrap->client, StringValueCStr(database));
10381027
}
10391028

1040-
transposed_encoding = rb_funcall(cTinyTdsClient, intern_transpose_iconv_encoding, 1, charset);
1041-
cwrap->encoding = rb_enc_find(StringValueCStr(transposed_encoding));
1029+
cwrap->encoding = rb_enc_find(StringValueCStr(charset));
10421030
cwrap->identity_insert_sql = "SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident";
10431031
}
10441032

@@ -1053,7 +1041,7 @@ void init_tinytds_client()
10531041
cTinyTdsClient = rb_define_class_under(mTinyTds, "Client", rb_cObject);
10541042
rb_define_alloc_func(cTinyTdsClient, allocate);
10551043
/* Define TinyTds::Client Public Methods */
1056-
rb_define_method(cTinyTdsClient, "tds_version", rb_tinytds_tds_version, 0);
1044+
rb_define_method(cTinyTdsClient, "server_version", rb_tinytds_server_version, 0);
10571045
rb_define_method(cTinyTdsClient, "close", rb_tinytds_close, 0);
10581046
rb_define_method(cTinyTdsClient, "closed?", rb_tinytds_closed, 0);
10591047
rb_define_method(cTinyTdsClient, "canceled?", rb_tinytds_canceled, 0);
@@ -1062,27 +1050,11 @@ void init_tinytds_client()
10621050
rb_define_method(cTinyTdsClient, "execute", rb_tinytds_execute, -1);
10631051
rb_define_method(cTinyTdsClient, "insert", rb_tiny_tds_insert, 1);
10641052
rb_define_method(cTinyTdsClient, "do", rb_tiny_tds_do, 1);
1065-
rb_define_method(cTinyTdsClient, "charset", rb_tinytds_charset, 0);
10661053
rb_define_method(cTinyTdsClient, "encoding", rb_tinytds_encoding, 0);
10671054
rb_define_method(cTinyTdsClient, "escape", rb_tinytds_escape, 1);
10681055
rb_define_method(cTinyTdsClient, "return_code", rb_tinytds_return_code, 0);
10691056
rb_define_method(cTinyTdsClient, "identity_sql", rb_tinytds_identity_sql, 0);
1070-
/* Define TinyTds::Client Protected Methods */
1071-
rb_define_protected_method(cTinyTdsClient, "connect", rb_tinytds_connect, 1);
1072-
/* Symbols For Connect */
1073-
sym_username = ID2SYM(rb_intern("username"));
1074-
sym_password = ID2SYM(rb_intern("password"));
1075-
sym_dataserver = ID2SYM(rb_intern("dataserver"));
1076-
sym_database = ID2SYM(rb_intern("database"));
1077-
sym_appname = ID2SYM(rb_intern("appname"));
1078-
sym_tds_version = ID2SYM(rb_intern("tds_version"));
1079-
sym_login_timeout = ID2SYM(rb_intern("login_timeout"));
1080-
sym_timeout = ID2SYM(rb_intern("timeout"));
1081-
sym_encoding = ID2SYM(rb_intern("encoding"));
1082-
sym_azure = ID2SYM(rb_intern("azure"));
1083-
sym_contained = ID2SYM(rb_intern("contained"));
1084-
sym_use_utf16 = ID2SYM(rb_intern("use_utf16"));
1085-
sym_message_handler = ID2SYM(rb_intern("message_handler"));
1057+
rb_define_method(cTinyTdsClient, "connect", rb_tinytds_connect, 0);
10861058
/* Intern TinyTds::Error Accessors */
10871059
intern_source_eql = rb_intern("source=");
10881060
intern_severity_eql = rb_intern("severity=");
@@ -1091,7 +1063,6 @@ void init_tinytds_client()
10911063
/* Intern Misc */
10921064
intern_new = rb_intern("new");
10931065
intern_dup = rb_intern("dup");
1094-
intern_transpose_iconv_encoding = rb_intern("transpose_iconv_encoding");
10951066
intern_local_offset = rb_intern("local_offset");
10961067
intern_gsub = rb_intern("gsub");
10971068
intern_call = rb_intern("call");
@@ -1115,6 +1086,8 @@ void init_tinytds_client()
11151086
intern_timezone = rb_intern("timezone");
11161087
intern_utc = rb_intern("utc");
11171088
intern_local = rb_intern("local");
1089+
intern_active = rb_intern("active?");
1090+
intern_connect = rb_intern("connect");
11181091

11191092
cTinyTdsClient = rb_const_get(mTinyTds, rb_intern("Client"));
11201093
cTinyTdsResult = rb_const_get(mTinyTds, rb_intern("Result"));

0 commit comments

Comments
 (0)