tiny_tds 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +13 -0
- data/README.rdoc +9 -3
- data/ext/tiny_tds/result.c +72 -44
- data/ext/tiny_tds/result.h +3 -3
- data/lib/tiny_tds.rb +1 -1
- metadata +4 -4
data/CHANGELOG
CHANGED
@@ -1,3 +1,16 @@
|
|
1
1
|
|
2
|
+
* 0.2.0 *
|
3
|
+
|
4
|
+
* Convert GUID's in a more compatible way. [Klaus Gundermann]
|
5
|
+
|
6
|
+
* Handle multiple result sets in command buffer or stored procs. [Ken Collins]
|
7
|
+
|
8
|
+
* Fixed some compiler warnings. [Erik Bryn]
|
9
|
+
|
10
|
+
* Avoid segfault related to smalldatetime conversion. [Erik Bryn]
|
11
|
+
|
12
|
+
* Properly encode column names in 1.9. [Erik Bryn]
|
13
|
+
|
14
|
+
|
2
15
|
* 0.1.0 Initial release!
|
3
16
|
|
data/README.rdoc
CHANGED
@@ -46,7 +46,7 @@ Below is a list of the data types we plan to support using future versions of Fr
|
|
46
46
|
|
47
47
|
Connect to a database.
|
48
48
|
|
49
|
-
client = TinyTds::Client.new(:
|
49
|
+
client = TinyTds::Client.new(:username => 'sa', :password => 'secret', :dataserver => 'mytds_box')
|
50
50
|
|
51
51
|
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 highly recommended to leave blank for the UTF-8 default.
|
52
52
|
|
@@ -142,6 +142,13 @@ Besides the standard query options, the result object can take one additional op
|
|
142
142
|
By default row caching is turned on because the SQL Server adapter for ActiveRecord would not work without it. I hope to find some time to create some performance patches for ActiveRecord that would allow it to take advantages of lazily created yielded rows from result objects. Currently only TinyTds and the Mysql2 gem allow such a performance gain.
|
143
143
|
|
144
144
|
|
145
|
+
== Using TinyTds With the ActiveRecord SQL Server adapter.
|
146
|
+
|
147
|
+
As of version 2.3.11 & 3.0.3 of the adapter, you can specify a :dblib mode in database.yml and use TinyTds as the low level connection mode. Make sure to add a :dataserver option to that matches the name in your freetds.conf file. The SQL Server adapter can be found here.
|
148
|
+
|
149
|
+
http://github.com/rails-sqlserver/activerecord-sqlserver-adapter
|
150
|
+
|
151
|
+
|
145
152
|
|
146
153
|
== Development & Testing
|
147
154
|
|
@@ -158,7 +165,6 @@ For help and support.
|
|
158
165
|
Current to do list.
|
159
166
|
|
160
167
|
* Test 0.83 development of FreeTDS.
|
161
|
-
* Handle multiple result sets.
|
162
168
|
* Find someone brave enough to compile/test for Windows.
|
163
169
|
* Install an interrupt handler.
|
164
170
|
* Allow #escape to accept all ruby primitives.
|
@@ -168,7 +174,7 @@ Current to do list.
|
|
168
174
|
|
169
175
|
== About Me
|
170
176
|
|
171
|
-
My name is Ken Collins and I have no love for Microsoft nor do I work on Windows or have I ever owned a PC
|
177
|
+
My name is Ken Collins and to avoid confusion – I have no love for Microsoft nor do I work on Windows or have I ever owned a PC, just so we know :) – I currently maintain the SQL Server adapter for ActiveRecord and wrote this library as my first cut into learning ruby C extensions. Hopefully it will help promote the power of ruby and the rails framework to those that have not yet discovered it. My blog is http://metaskills.net and I can be found on twitter as @metaskills. Enjoy!
|
172
178
|
|
173
179
|
|
174
180
|
|
data/ext/tiny_tds/result.c
CHANGED
@@ -23,9 +23,9 @@ static ID sym_symbolize_keys, sym_as, sym_array, sym_cache_rows, sym_first, sym_
|
|
23
23
|
})
|
24
24
|
#else
|
25
25
|
#define ENCODED_STR_NEW(_data, _len) \
|
26
|
-
rb_str_new((char *)_data, (long)_len)
|
26
|
+
rb_str_new((char *)_data, (long)_len)
|
27
27
|
#define ENCODED_STR_NEW2(_data2) \
|
28
|
-
rb_str_new2((char *)_data2)
|
28
|
+
rb_str_new2((char *)_data2)
|
29
29
|
#endif
|
30
30
|
|
31
31
|
|
@@ -36,7 +36,7 @@ static void rb_tinytds_result_mark(void *ptr) {
|
|
36
36
|
if (rwrap) {
|
37
37
|
rb_gc_mark(rwrap->local_offset);
|
38
38
|
rb_gc_mark(rwrap->fields);
|
39
|
-
rb_gc_mark(rwrap->
|
39
|
+
rb_gc_mark(rwrap->results);
|
40
40
|
}
|
41
41
|
}
|
42
42
|
|
@@ -50,10 +50,10 @@ VALUE rb_tinytds_new_result_obj(DBPROCESS *c) {
|
|
50
50
|
tinytds_result_wrapper *rwrap;
|
51
51
|
obj = Data_Make_Struct(cTinyTdsResult, tinytds_result_wrapper, rb_tinytds_result_mark, rb_tinytds_result_free, rwrap);
|
52
52
|
rwrap->client = c;
|
53
|
-
rwrap->return_code = 0;
|
54
53
|
rwrap->local_offset = Qnil;
|
55
54
|
rwrap->fields = Qnil;
|
56
|
-
rwrap->
|
55
|
+
rwrap->results = Qnil;
|
56
|
+
rwrap->number_of_results = 0;
|
57
57
|
rwrap->number_of_fields = 0;
|
58
58
|
rwrap->number_of_rows = 0;
|
59
59
|
rb_obj_call_init(obj, 0, NULL);
|
@@ -66,25 +66,10 @@ VALUE rb_tinytds_new_result_obj(DBPROCESS *c) {
|
|
66
66
|
static VALUE rb_tinytds_result_fetch_row(VALUE self, ID timezone, int symbolize_keys, int as_array) {
|
67
67
|
/* Wrapper And Local Vars */
|
68
68
|
GET_RESULT_WRAPPER(self);
|
69
|
-
VALUE row;
|
70
|
-
unsigned int i = 0;
|
71
|
-
/* One-Time Fields Info & Container */
|
72
|
-
if (NIL_P(rwrap->fields)) {
|
73
|
-
rwrap->number_of_fields = dbnumcols(rwrap->client);
|
74
|
-
rwrap->fields = rb_ary_new2(rwrap->number_of_fields);
|
75
|
-
for (i = 0; i < rwrap->number_of_fields; i++) {
|
76
|
-
char *colname = dbcolname(rwrap->client, i+1);
|
77
|
-
VALUE field = symbolize_keys ? ID2SYM(rb_intern(colname)) : rb_obj_freeze(rb_str_new2(colname));
|
78
|
-
rb_ary_store(rwrap->fields, i, field);
|
79
|
-
}
|
80
|
-
}
|
81
69
|
/* Create Empty Row */
|
82
|
-
|
83
|
-
row = rb_ary_new2(rwrap->number_of_fields);
|
84
|
-
} else {
|
85
|
-
row = rb_hash_new();
|
86
|
-
}
|
70
|
+
VALUE row = as_array ? rb_ary_new2(rwrap->number_of_fields) : rb_hash_new();
|
87
71
|
/* Storing Values */
|
72
|
+
unsigned int i = 0;
|
88
73
|
for (i = 0; i < rwrap->number_of_fields; i++) {
|
89
74
|
VALUE val = Qnil;
|
90
75
|
int col = i+1;
|
@@ -152,13 +137,17 @@ static VALUE rb_tinytds_result_fetch_row(VALUE self, ID timezone, int symbolize_
|
|
152
137
|
#endif
|
153
138
|
break;
|
154
139
|
case 36: { // SYBUNIQUE
|
155
|
-
char converted_unique[
|
156
|
-
dbconvert(rwrap->client, coltype, data,
|
140
|
+
char converted_unique[36];
|
141
|
+
dbconvert(rwrap->client, coltype, data, data_len, SYBVARCHAR, (BYTE *)converted_unique, sizeof(converted_unique));
|
157
142
|
val = ENCODED_STR_NEW2(converted_unique);
|
158
143
|
break;
|
159
144
|
}
|
160
|
-
case SYBDATETIME4:
|
161
|
-
|
145
|
+
case SYBDATETIME4: {
|
146
|
+
DBDATETIME new_data;
|
147
|
+
dbconvert(rwrap->client, coltype, data, data_len, SYBDATETIME, (BYTE *)&new_data, sizeof(new_data));
|
148
|
+
data = (BYTE *)&new_data;
|
149
|
+
data_len = sizeof(new_data);
|
150
|
+
}
|
162
151
|
case SYBDATETIME: {
|
163
152
|
DBDATEREC date_rec;
|
164
153
|
dbdatecrack(rwrap->client, &date_rec, (DBDATETIME *)data);
|
@@ -203,7 +192,13 @@ static VALUE rb_tinytds_result_fetch_row(VALUE self, ID timezone, int symbolize_
|
|
203
192
|
if (as_array) {
|
204
193
|
rb_ary_store(row, i, val);
|
205
194
|
} else {
|
206
|
-
|
195
|
+
VALUE key;
|
196
|
+
if (rwrap->number_of_results == 0) {
|
197
|
+
key = rb_ary_entry(rwrap->fields, i);
|
198
|
+
} else {
|
199
|
+
key = rb_ary_entry(rb_ary_entry(rwrap->fields, rwrap->number_of_results), i);
|
200
|
+
}
|
201
|
+
rb_hash_aset(row, key, val);
|
207
202
|
}
|
208
203
|
}
|
209
204
|
return row;
|
@@ -242,21 +237,43 @@ static VALUE rb_tinytds_result_each(int argc, VALUE * argv, VALUE self) {
|
|
242
237
|
rb_warn(":timezone option must be :utc or :local - defaulting to :local");
|
243
238
|
timezone = intern_local;
|
244
239
|
}
|
245
|
-
/* Make The
|
246
|
-
if (NIL_P(rwrap->
|
247
|
-
rwrap->
|
248
|
-
RETCODE
|
249
|
-
|
250
|
-
|
251
|
-
if
|
252
|
-
|
253
|
-
|
254
|
-
|
240
|
+
/* Make The Results Or Yield Existing */
|
241
|
+
if (NIL_P(rwrap->results)) {
|
242
|
+
rwrap->results = rb_ary_new();
|
243
|
+
RETCODE dbresults_rc = 0;
|
244
|
+
dbresults_rc = dbresults(rwrap->client);
|
245
|
+
while (dbresults_rc == SUCCEED) {
|
246
|
+
/* Only do field and row work if there are rows in this result set. */
|
247
|
+
int has_rows = (DBROWS(rwrap->client) == SUCCEED) ? 1 : 0;
|
248
|
+
int number_of_fields = has_rows ? dbnumcols(rwrap->client) : 0;
|
249
|
+
if (has_rows && (number_of_fields > 0)) {
|
250
|
+
/* Create fields for this result set. */
|
251
|
+
unsigned int fldi = 0;
|
252
|
+
rwrap->number_of_fields = number_of_fields;
|
253
|
+
VALUE fields = rb_ary_new2(rwrap->number_of_fields);
|
254
|
+
for (fldi = 0; fldi < rwrap->number_of_fields; fldi++) {
|
255
|
+
char *colname = dbcolname(rwrap->client, fldi+1);
|
256
|
+
VALUE field = symbolize_keys ? ID2SYM(rb_intern(colname)) : rb_obj_freeze(ENCODED_STR_NEW2(colname));
|
257
|
+
rb_ary_store(fields, fldi, field);
|
258
|
+
}
|
259
|
+
/* Store the fields. */
|
260
|
+
if (rwrap->number_of_results == 0) {
|
261
|
+
rwrap->fields = fields;
|
262
|
+
} else if (rwrap->number_of_results == 1) {
|
263
|
+
VALUE multi_rs_fields = rb_ary_new();
|
264
|
+
rb_ary_store(multi_rs_fields, 0, rwrap->fields);
|
265
|
+
rb_ary_store(multi_rs_fields, 1, fields);
|
266
|
+
rwrap->fields = multi_rs_fields;
|
267
|
+
} else {
|
268
|
+
rb_ary_store(rwrap->fields, rwrap->number_of_results, fields);
|
269
|
+
}
|
270
|
+
/* Create rows for this result set. */
|
255
271
|
unsigned long rowi = 0;
|
272
|
+
VALUE result = rb_ary_new();
|
256
273
|
while (dbnextrow(rwrap->client) != NO_MORE_ROWS) {
|
257
274
|
VALUE row = rb_tinytds_result_fetch_row(self, timezone, symbolize_keys, as_array);
|
258
275
|
if (cache_rows)
|
259
|
-
rb_ary_store(
|
276
|
+
rb_ary_store(result, rowi, row);
|
260
277
|
if (!NIL_P(block))
|
261
278
|
rb_yield(row);
|
262
279
|
if (first)
|
@@ -264,22 +281,33 @@ static VALUE rb_tinytds_result_each(int argc, VALUE * argv, VALUE self) {
|
|
264
281
|
rowi++;
|
265
282
|
}
|
266
283
|
rwrap->number_of_rows = rowi;
|
267
|
-
|
268
|
-
|
269
|
-
|
284
|
+
/* Store the result. */
|
285
|
+
if (rwrap->number_of_results == 0) {
|
286
|
+
rwrap->results = result;
|
287
|
+
} else if (rwrap->number_of_results == 1) {
|
288
|
+
VALUE multi_resultsets = rb_ary_new();
|
289
|
+
rb_ary_store(multi_resultsets, 0, rwrap->results);
|
290
|
+
rb_ary_store(multi_resultsets, 1, result);
|
291
|
+
rwrap->results = multi_resultsets;
|
292
|
+
} else {
|
293
|
+
rb_ary_store(rwrap->results, rwrap->number_of_results, result);
|
294
|
+
}
|
295
|
+
/* Record the result set */
|
296
|
+
rwrap->number_of_results = rwrap->number_of_results + 1;
|
270
297
|
}
|
298
|
+
dbresults_rc = dbresults(rwrap->client);
|
271
299
|
}
|
272
|
-
if (
|
300
|
+
if (dbresults_rc == FAIL) {
|
273
301
|
// TODO: Account for something in the dbresults() while loop set the return code to FAIL.
|
274
302
|
rb_warn("TinyTds: Something in the dbresults() while loop set the return code to FAIL.\n");
|
275
303
|
}
|
276
304
|
} else if (!NIL_P(block)) {
|
277
305
|
unsigned long i;
|
278
306
|
for (i = 0; i < rwrap->number_of_rows; i++) {
|
279
|
-
rb_yield(rb_ary_entry(rwrap->
|
307
|
+
rb_yield(rb_ary_entry(rwrap->results, i));
|
280
308
|
}
|
281
309
|
}
|
282
|
-
return rwrap->
|
310
|
+
return rwrap->results;
|
283
311
|
}
|
284
312
|
|
285
313
|
static VALUE rb_tinytds_result_fields(VALUE self) {
|
data/ext/tiny_tds/result.h
CHANGED
@@ -7,14 +7,14 @@ VALUE rb_tinytds_new_result_obj(DBPROCESS *c);
|
|
7
7
|
|
8
8
|
typedef struct {
|
9
9
|
DBPROCESS *client;
|
10
|
-
RETCODE return_code;
|
11
10
|
VALUE local_offset;
|
12
11
|
VALUE fields;
|
13
|
-
VALUE
|
12
|
+
VALUE results;
|
14
13
|
#ifdef HAVE_RUBY_ENCODING_H
|
15
14
|
rb_encoding *encoding;
|
16
15
|
#endif
|
17
|
-
|
16
|
+
unsigned int number_of_results;
|
17
|
+
unsigned int number_of_fields;
|
18
18
|
unsigned long number_of_rows;
|
19
19
|
} tinytds_result_wrapper;
|
20
20
|
|
data/lib/tiny_tds.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tiny_tds
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 2
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Ken Collins
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-10-
|
19
|
+
date: 2010-10-21 00:00:00 -04:00
|
20
20
|
default_executable:
|
21
21
|
dependencies: []
|
22
22
|
|