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 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
 
@@ -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(:user => 'sa', :password => 'secret', :dataserver => 'mytds_box')
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. 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!
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
 
@@ -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->rows);
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->rows = Qnil;
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
- if (as_array) {
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[32];
156
- dbconvert(rwrap->client, coltype, data, 32, SYBVARCHAR, (BYTE *)converted_unique, -1);
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
- dbconvert(rwrap->client, coltype, data, data_len, SYBDATETIME, data, data_len);
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
- rb_hash_aset(row, rb_ary_entry(rwrap->fields, i), val);
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 Rows Or Yield Existing */
246
- if (NIL_P(rwrap->rows)) {
247
- rwrap->rows = rb_ary_new();
248
- RETCODE return_code;
249
- while (return_code != NO_MORE_RESULTS) {
250
- return_code = dbresults(rwrap->client);
251
- if (return_code != FAIL) {
252
- /* If no actual rows, return the empty array. */
253
- if (DBROWS(rwrap->client) != SUCCEED)
254
- return rwrap->rows;
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(rwrap->rows, rowi, row);
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
- } else {
268
- // TODO: Account for failed dbresults() must have returned FAIL.
269
- rb_warn("TinyTds: dbresults() must have returned FAIL.\n");
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 (return_code == FAIL) {
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->rows, i));
307
+ rb_yield(rb_ary_entry(rwrap->results, i));
280
308
  }
281
309
  }
282
- return rwrap->rows;
310
+ return rwrap->results;
283
311
  }
284
312
 
285
313
  static VALUE rb_tinytds_result_fields(VALUE self) {
@@ -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 rows;
12
+ VALUE results;
14
13
  #ifdef HAVE_RUBY_ENCODING_H
15
14
  rb_encoding *encoding;
16
15
  #endif
17
- long number_of_fields;
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
 
@@ -15,5 +15,5 @@ require 'tiny_tds/tiny_tds'
15
15
  #
16
16
  # Tiny Ruby Wrapper For FreeTDS Using DB-Library
17
17
  module TinyTds
18
- VERSION = '0.1.0'
18
+ VERSION = '0.2.0'
19
19
  end
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: 27
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 1
8
+ - 2
9
9
  - 0
10
- version: 0.1.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-17 00:00:00 -04:00
19
+ date: 2010-10-21 00:00:00 -04:00
20
20
  default_executable:
21
21
  dependencies: []
22
22