do_mysql 0.10.3-x86-mswin32-60 → 0.10.4.rc1-x86-mswin32-60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,170 @@
1
+ #ifndef _DO_COMMON_H_
2
+ #define _DO_COMMON_H_
3
+
4
+ #include <ruby.h>
5
+
6
+ #ifdef _WIN32
7
+ #define cCommand_execute cCommand_execute_sync
8
+ typedef signed __int64 do_int64;
9
+ #else
10
+ #define cCommand_execute cCommand_execute_async
11
+ typedef signed long long int do_int64;
12
+ #endif
13
+
14
+ #ifdef HAVE_RUBY_ENCODING_H
15
+ #include <ruby/encoding.h>
16
+
17
+ #define DO_STR_NEW2(str, encoding, internal_encoding) \
18
+ ({ \
19
+ VALUE _string = rb_str_new2((const char *)str); \
20
+ if(encoding != -1) { \
21
+ rb_enc_associate_index(_string, encoding); \
22
+ } \
23
+ if(internal_encoding) { \
24
+ _string = rb_str_export_to_enc(_string, internal_encoding); \
25
+ } \
26
+ _string; \
27
+ })
28
+
29
+ #define DO_STR_NEW(str, len, encoding, internal_encoding) \
30
+ ({ \
31
+ VALUE _string = rb_str_new((const char *)str, (long)len); \
32
+ if(encoding != -1) { \
33
+ rb_enc_associate_index(_string, encoding); \
34
+ } \
35
+ if(internal_encoding) { \
36
+ _string = rb_str_export_to_enc(_string, internal_encoding); \
37
+ } \
38
+ _string; \
39
+ })
40
+
41
+ # else
42
+
43
+ #define DO_STR_NEW2(str, encoding, internal_encoding) \
44
+ rb_str_new2((const char *)str)
45
+
46
+ #define DO_STR_NEW(str, len, encoding, internal_encoding) \
47
+ rb_str_new((const char *)str, (long)len)
48
+ #endif
49
+
50
+ // Needed for defining error.h
51
+ struct errcodes {
52
+ int error_no;
53
+ const char *error_name;
54
+ const char *exception;
55
+ };
56
+
57
+ #define ERRCODE(name,message) {name, #name, message}
58
+
59
+ // To store rb_intern values
60
+ extern ID ID_NEW;
61
+ extern ID ID_NEW_DATE;
62
+ extern ID ID_CONST_GET;
63
+ extern ID ID_RATIONAL;
64
+ extern ID ID_ESCAPE;
65
+ extern ID ID_STRFTIME;
66
+ extern ID ID_LOG;
67
+
68
+ // Reference to Extlib module
69
+ extern VALUE mExtlib;
70
+ extern VALUE rb_cByteArray;
71
+
72
+ // References to DataObjects base classes
73
+ extern VALUE mDO;
74
+ extern VALUE mEncoding;
75
+ extern VALUE cDO_Quoting;
76
+ extern VALUE cDO_Connection;
77
+ extern VALUE cDO_Command;
78
+ extern VALUE cDO_Result;
79
+ extern VALUE cDO_Reader;
80
+ extern VALUE cDO_Logger;
81
+ extern VALUE cDO_Logger_Message;
82
+ extern VALUE cDO_Extension;
83
+ extern VALUE eConnectionError;
84
+ extern VALUE eDataError;
85
+
86
+ // References to Ruby classes that we'll need
87
+ extern VALUE rb_cDate;
88
+ extern VALUE rb_cDateTime;
89
+ extern VALUE rb_cBigDecimal;
90
+
91
+ extern void data_objects_debug(VALUE connection, VALUE string, struct timeval *start);
92
+ extern char *get_uri_option(VALUE query_hash, const char *key);
93
+ extern void assert_file_exists(char *file, const char *message);
94
+ extern VALUE build_query_from_args(VALUE klass, int count, VALUE *args);
95
+
96
+ extern void reduce(do_int64 *numerator, do_int64 *denominator);
97
+ extern int jd_from_date(int year, int month, int day);
98
+ extern VALUE seconds_to_offset(long seconds_offset);
99
+ extern VALUE timezone_to_offset(int hour_offset, int minute_offset);
100
+
101
+ extern VALUE parse_date(const char *date);
102
+ extern VALUE parse_time(const char *date);
103
+ extern VALUE parse_date_time(const char *date);
104
+
105
+ extern VALUE cConnection_character_set(VALUE self);
106
+ extern VALUE cConnection_is_using_socket(VALUE self);
107
+ extern VALUE cConnection_ssl_cipher(VALUE self);
108
+ extern VALUE cConnection_quote_time(VALUE self, VALUE value);
109
+ extern VALUE cConnection_quote_date_time(VALUE self, VALUE value);
110
+ extern VALUE cConnection_quote_date(VALUE self, VALUE value);
111
+
112
+ extern VALUE cCommand_set_types(int argc, VALUE *argv, VALUE self);
113
+
114
+ extern VALUE cReader_values(VALUE self);
115
+ extern VALUE cReader_fields(VALUE self);
116
+ extern VALUE cReader_field_count(VALUE self);
117
+
118
+ extern void common_init(void);
119
+
120
+ static inline VALUE do_const_get(VALUE scope, const char *constant) {
121
+ return rb_funcall(scope, ID_CONST_GET, 1, rb_str_new2(constant));
122
+ }
123
+
124
+ static inline VALUE do_str_new(const void *string, long length, int encoding, void *internal_encoding) {
125
+ VALUE new_string = rb_str_new(string, length);
126
+
127
+ #ifdef HAVE_RUBY_ENCODING_H
128
+ if(encoding != -1) {
129
+ rb_enc_associate_index(new_string, encoding);
130
+ }
131
+
132
+ if(internal_encoding) {
133
+ new_string = rb_str_export_to_enc(new_string, internal_encoding);
134
+ }
135
+ #endif
136
+
137
+ return new_string;
138
+ }
139
+
140
+ static inline VALUE do_str_new2(const void *string, int encoding, void *internal_encoding) {
141
+ VALUE new_string = rb_str_new2(string);
142
+
143
+ #ifdef HAVE_RUBY_ENCODING_H
144
+ if(encoding != -1) {
145
+ rb_enc_associate_index(new_string, encoding);
146
+ }
147
+
148
+ if(internal_encoding) {
149
+ new_string = rb_str_export_to_enc(new_string, internal_encoding);
150
+ }
151
+ #endif
152
+
153
+ return new_string;
154
+ }
155
+
156
+ static inline void do_define_errors(VALUE scope, const struct errcodes *errors) {
157
+ const struct errcodes *e;
158
+
159
+ for (e = errors; e->error_name; e++) {
160
+ rb_const_set(scope, rb_intern(e->error_name), INT2NUM(e->error_no));
161
+ }
162
+ }
163
+
164
+ extern void do_raise_error(VALUE self, const struct errcodes *errors, int errnum, const char *message, VALUE query, VALUE state);
165
+
166
+ extern VALUE do_typecast(const char *value, long length, const VALUE type, int encoding);
167
+
168
+ #define RSTRING_NOT_MODIFIED
169
+
170
+ #endif
@@ -1,8 +1,6 @@
1
1
  #include <ruby.h>
2
- #include <string.h>
3
- #include <math.h>
4
- #include <ctype.h>
5
2
  #include <time.h>
3
+ #include <string.h>
6
4
 
7
5
  #include <mysql.h>
8
6
  #include <errmsg.h>
@@ -12,100 +10,27 @@
12
10
  #include "compat.h"
13
11
  #include "error.h"
14
12
 
13
+ #include "do_common.h"
14
+
15
15
  #ifndef HAVE_CONST_MYSQL_TYPE_STRING
16
16
  #define HAVE_OLD_MYSQL_VERSION
17
17
  #endif
18
18
 
19
- #define CONST_GET(scope, constant) (rb_funcall(scope, ID_CONST_GET, 1, rb_str_new2(constant)))
20
- #define DRIVER_CLASS(klass, parent) (rb_define_class_under(mMysql, klass, parent))
21
19
  #define CHECK_AND_RAISE(mysql_result_value, query) if (0 != mysql_result_value) { raise_error(self, db, query); }
22
20
 
23
- #ifdef _WIN32
24
- #define cCommand_execute cCommand_execute_sync
25
- #define do_int64 signed __int64
26
- #else
27
- #define cCommand_execute cCommand_execute_async
28
- #define do_int64 signed long long int
29
- #endif
30
-
31
- #ifdef HAVE_RUBY_ENCODING_H
32
- #include <ruby/encoding.h>
33
-
34
- #define DO_STR_NEW2(str, encoding, internal_encoding) \
35
- ({ \
36
- VALUE _string = rb_str_new2((const char *)str); \
37
- if(encoding != -1) { \
38
- rb_enc_associate_index(_string, encoding); \
39
- } \
40
- if(internal_encoding) { \
41
- _string = rb_str_export_to_enc(_string, internal_encoding); \
42
- } \
43
- _string; \
44
- })
45
-
46
- #define DO_STR_NEW(str, len, encoding, internal_encoding) \
47
- ({ \
48
- VALUE _string = rb_str_new((const char *)str, (long)len); \
49
- if(encoding != -1) { \
50
- rb_enc_associate_index(_string, encoding); \
51
- } \
52
- if(internal_encoding) { \
53
- _string = rb_str_export_to_enc(_string, internal_encoding); \
54
- } \
55
- _string; \
56
- })
57
-
58
- #else
59
-
60
- #define DO_STR_NEW2(str, encoding, internal_encoding) \
61
- rb_str_new2((const char *)str)
62
-
63
- #define DO_STR_NEW(str, len, encoding, internal_encoding) \
64
- rb_str_new((const char *)str, (long)len)
65
- #endif
66
-
67
-
68
- // To store rb_intern values
69
- static ID ID_NEW;
70
- static ID ID_NEW_DATE;
71
- static ID ID_CONST_GET;
72
- static ID ID_RATIONAL;
73
- static ID ID_ESCAPE;
74
- static ID ID_STRFTIME;
75
- static ID ID_LOG;
76
-
77
- // Reference to Extlib module
78
- static VALUE mExtlib;
79
-
80
- // References to DataObjects base classes
81
- static VALUE mDO;
82
- static VALUE mEncoding;
83
- static VALUE cDO_Quoting;
84
- static VALUE cDO_Connection;
85
- static VALUE cDO_Command;
86
- static VALUE cDO_Result;
87
- static VALUE cDO_Reader;
88
- static VALUE cDO_Logger;
89
- static VALUE cDO_Logger_Message;
90
-
91
- // References to Ruby classes that we'll need
92
- static VALUE rb_cDate;
93
- static VALUE rb_cDateTime;
94
- static VALUE rb_cBigDecimal;
95
- static VALUE rb_cByteArray;
21
+ void full_connect(VALUE self, MYSQL *db);
96
22
 
97
23
  // Classes that we'll build in Init
98
- static VALUE mMysql;
99
- static VALUE cConnection;
100
- static VALUE cCommand;
101
- static VALUE cResult;
102
- static VALUE cReader;
103
- static VALUE eConnectionError;
104
- static VALUE eDataError;
24
+ VALUE mMysql;
25
+ VALUE mEncoding;
26
+ VALUE cConnection;
27
+ VALUE cCommand;
28
+ VALUE cResult;
29
+ VALUE cReader;
105
30
 
106
31
  // Figures out what we should cast a given mysql field type to
107
- static VALUE infer_ruby_type(MYSQL_FIELD *field) {
108
- switch(field->type) {
32
+ VALUE infer_ruby_type(const MYSQL_FIELD *field) {
33
+ switch (field->type) {
109
34
  case MYSQL_TYPE_NULL:
110
35
  return Qnil;
111
36
  case MYSQL_TYPE_TINY:
@@ -140,9 +65,10 @@ static VALUE infer_ruby_type(MYSQL_FIELD *field) {
140
65
  case MYSQL_TYPE_LONG_BLOB:
141
66
  case MYSQL_TYPE_BLOB:
142
67
  #ifdef HAVE_ST_CHARSETNR
143
- if(field->charsetnr == 63) {
68
+ if (field->charsetnr == 63) {
144
69
  return rb_cByteArray;
145
- } else {
70
+ }
71
+ else {
146
72
  return rb_cString;
147
73
  }
148
74
  #else
@@ -154,331 +80,48 @@ static VALUE infer_ruby_type(MYSQL_FIELD *field) {
154
80
  }
155
81
  }
156
82
 
157
- // Find the greatest common denominator and reduce the provided numerator and denominator.
158
- // This replaces calles to Rational.reduce! which does the same thing, but really slowly.
159
- static void reduce( do_int64 *numerator, do_int64 *denominator ) {
160
- do_int64 a, b, c;
161
- a = *numerator;
162
- b = *denominator;
163
- while ( a != 0 ) {
164
- c = a; a = b % a; b = c;
165
- }
166
- *numerator = *numerator / b;
167
- *denominator = *denominator / b;
168
- }
169
-
170
- // Generate the date integer which Date.civil_to_jd returns
171
- static int jd_from_date(int year, int month, int day) {
172
- int a, b;
173
- if ( month <= 2 ) {
174
- year -= 1;
175
- month += 12;
176
- }
177
- a = year / 100;
178
- b = 2 - a + (a / 4);
179
- return (int) (floor(365.25 * (year + 4716)) + floor(30.6001 * (month + 1)) + day + b - 1524);
180
- }
181
-
182
- static VALUE seconds_to_offset(long seconds_offset) {
183
- do_int64 num = seconds_offset, den = 86400;
184
- reduce(&num, &den);
185
- return rb_funcall(rb_mKernel, ID_RATIONAL, 2, rb_ll2inum(num), rb_ll2inum(den));
186
- }
187
-
188
- static VALUE timezone_to_offset(int hour_offset, int minute_offset) {
189
- do_int64 seconds = 0;
190
-
191
- seconds += hour_offset * 3600;
192
- seconds += minute_offset * 60;
193
-
194
- return seconds_to_offset(seconds);
195
- }
196
-
197
- static VALUE parse_date(const char *date) {
198
- int year, month, day;
199
- int jd, ajd;
200
- VALUE rational;
201
-
202
- sscanf(date, "%4d-%2d-%2d", &year, &month, &day);
203
-
204
- jd = jd_from_date(year, month, day);
205
-
206
- // Math from Date.jd_to_ajd
207
- ajd = jd * 2 - 1;
208
- rational = rb_funcall(rb_mKernel, ID_RATIONAL, 2, INT2NUM(ajd), INT2NUM(2));
209
- return rb_funcall(rb_cDate, ID_NEW_DATE, 3, rational, INT2NUM(0), INT2NUM(2299161));
210
- }
211
-
212
- static VALUE parse_time(const char *date) {
213
-
214
- int year, month, day, hour, min, sec, usec, tokens;
215
- char subsec[7];
216
-
217
- if (0 != strchr(date, '.')) {
218
- // right padding usec with 0. e.g. '012' will become 12000 microsecond, since Time#local use microsecond
219
- sscanf(date, "%4d-%2d-%2d %2d:%2d:%2d.%s", &year, &month, &day, &hour, &min, &sec, subsec);
220
- sscanf(subsec, "%d", &usec);
221
- } else {
222
- tokens = sscanf(date, "%4d-%2d-%2d %2d:%2d:%2d", &year, &month, &day, &hour, &min, &sec);
223
- if (tokens == 3) {
224
- hour = 0;
225
- min = 0;
226
- sec = 0;
227
- }
228
- usec = 0;
229
- }
230
-
231
- if ( year + month + day + hour + min + sec + usec == 0 ) { // Mysql TIMESTAMPS can default to 0
232
- return Qnil;
233
- }
234
-
235
- return rb_funcall(rb_cTime, rb_intern("local"), 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), INT2NUM(usec));
236
- }
237
-
238
- static VALUE parse_date_time(const char *date) {
239
- VALUE ajd, offset;
240
-
241
- int year, month, day, hour, min, sec, usec, hour_offset, minute_offset;
242
- int jd;
243
- do_int64 num, den;
244
-
245
-
246
- time_t gmt_offset;
247
- int dst_adjustment;
248
-
249
- time_t rawtime;
250
- struct tm timeinfo;
251
-
252
- int tokens_read, max_tokens;
253
-
254
- if ( strcmp(date, "") == 0 ) {
255
- return Qnil;
256
- }
257
-
258
- if (0 != strchr(date, '.')) {
259
- // This is a datetime with sub-second precision
260
- tokens_read = sscanf(date, "%4d-%2d-%2d%*c%2d:%2d:%2d.%d%3d:%2d", &year, &month, &day, &hour, &min, &sec, &usec, &hour_offset, &minute_offset);
261
- max_tokens = 9;
262
- } else {
263
- // This is a datetime second precision
264
- tokens_read = sscanf(date, "%4d-%2d-%2d%*c%2d:%2d:%2d%3d:%2d", &year, &month, &day, &hour, &min, &sec, &hour_offset, &minute_offset);
265
- max_tokens = 8;
266
- }
267
-
268
- if (max_tokens == tokens_read) {
269
- // We read the Date, Time, and Timezone info
270
- minute_offset *= hour_offset < 0 ? -1 : 1;
271
- } else if ((max_tokens - 1) == tokens_read) {
272
- // We read the Date and Time, but no Minute Offset
273
- minute_offset = 0;
274
- } else if (tokens_read == 3 || tokens_read >= (max_tokens - 3)) {
275
- if (tokens_read == 3) {
276
- hour = 0;
277
- min = 0;
278
- hour_offset = 0;
279
- minute_offset = 0;
280
- sec = 0;
281
- }
282
- // We read the Date and Time, default to the current locale's offset
283
-
284
- tzset();
285
-
286
- // Get localtime
287
- time(&rawtime);
288
- #ifdef HAVE_LOCALTIME_R
289
- localtime_r(&rawtime, &timeinfo);
290
- #else
291
- timeinfo = *localtime(&rawtime);
292
- #endif
293
-
294
- timeinfo.tm_sec = sec;
295
- timeinfo.tm_min = min;
296
- timeinfo.tm_hour = hour;
297
- timeinfo.tm_mday = day;
298
- timeinfo.tm_mon = month;
299
- timeinfo.tm_year = year - 1900;
300
- timeinfo.tm_isdst = -1;
301
-
302
- // Update tm_isdst
303
- mktime(&timeinfo);
304
-
305
- if (timeinfo.tm_isdst) {
306
- dst_adjustment = 3600;
307
- } else {
308
- dst_adjustment = 0;
309
- }
310
-
311
- // Reset to GM Time
312
- #ifdef HAVE_GMTIME_R
313
- gmtime_r(&rawtime, &timeinfo);
314
- #else
315
- timeinfo = *gmtime(&rawtime);
316
- #endif
317
-
318
- gmt_offset = rawtime - mktime(&timeinfo);
319
-
320
- if (dst_adjustment) {
321
- gmt_offset += dst_adjustment;
322
- }
323
-
324
- hour_offset = ((int)gmt_offset / 3600);
325
- minute_offset = ((int)gmt_offset % 3600 / 60);
326
-
327
- } else {
328
- // Something went terribly wrong
329
- rb_raise(eDataError, "Couldn't parse date: %s", date);
330
- }
331
-
332
- jd = jd_from_date(year, month, day);
333
-
334
- // Generate ajd with fractional days for the time
335
- // Extracted from Date#jd_to_ajd, Date#day_fraction_to_time, and Rational#+ and #-
336
- num = (hour * 1440) + (min * 24);
337
-
338
- // Modify the numerator so when we apply the timezone everything works out
339
- num -= (hour_offset * 1440) + (minute_offset * 24);
340
-
341
- den = (24 * 1440);
342
- reduce(&num, &den);
343
-
344
- num = (num * 86400) + (sec * den);
345
- den = den * 86400;
346
- reduce(&num, &den);
347
-
348
- num = (jd * den) + num;
349
-
350
- num = num * 2;
351
- num = num - den;
352
- den = den * 2;
353
-
354
- reduce(&num, &den);
355
-
356
- ajd = rb_funcall(rb_mKernel, ID_RATIONAL, 2, rb_ull2inum(num), rb_ull2inum(den));
357
- offset = timezone_to_offset(hour_offset, minute_offset);
358
-
359
- return rb_funcall(rb_cDateTime, ID_NEW_DATE, 3, ajd, offset, INT2NUM(2299161));
360
- }
361
-
362
83
  // Convert C-string to a Ruby instance of Ruby type "type"
363
- static VALUE typecast(const char *value, long length, const VALUE type, int encoding) {
364
-
365
- if(NULL == value) {
84
+ VALUE typecast(const char *value, long length, const VALUE type, int encoding) {
85
+ if (!value) {
366
86
  return Qnil;
367
87
  }
368
88
 
369
- #ifdef HAVE_RUBY_ENCODING_H
370
- rb_encoding * internal_encoding = rb_default_internal_encoding();
371
- #else
372
- void * internal_encoding = NULL;
373
- #endif
374
-
375
- if (type == rb_cInteger) {
376
- return rb_cstr2inum(value, 10);
377
- } else if (type == rb_cString) {
378
- return DO_STR_NEW(value, length, encoding, internal_encoding);
379
- } else if (type == rb_cFloat) {
380
- return rb_float_new(rb_cstr_to_dbl(value, Qfalse));
381
- } else if (type == rb_cBigDecimal) {
382
- return rb_funcall(rb_cBigDecimal, ID_NEW, 1, rb_str_new(value, length));
383
- } else if (type == rb_cDate) {
384
- return parse_date(value);
385
- } else if (type == rb_cDateTime) {
386
- return parse_date_time(value);
387
- } else if (type == rb_cTime) {
388
- return parse_time(value);
389
- } else if (type == rb_cTrueClass) {
390
- return (0 == value || 0 == strcmp("0", value)) ? Qfalse : Qtrue;
391
- } else if (type == rb_cByteArray) {
89
+ if (type == rb_cTrueClass) {
90
+ return (value == 0 || strcmp("0", value) == 0) ? Qfalse : Qtrue;
91
+ }
92
+ else if (type == rb_cByteArray) {
392
93
  return rb_funcall(rb_cByteArray, ID_NEW, 1, rb_str_new(value, length));
393
- } else if (type == rb_cClass) {
394
- return rb_funcall(mDO, rb_intern("full_const_get"), 1, rb_str_new(value, length));
395
- } else if (type == rb_cNilClass) {
396
- return Qnil;
397
- } else {
398
- return DO_STR_NEW(value, length, encoding, internal_encoding);
399
94
  }
400
-
401
- }
402
-
403
- static void data_objects_debug(VALUE connection, VALUE string, struct timeval* start) {
404
- struct timeval stop;
405
- VALUE message;
406
-
407
- gettimeofday(&stop, NULL);
408
- do_int64 duration = (stop.tv_sec - start->tv_sec) * 1000000 + stop.tv_usec - start->tv_usec;
409
-
410
- message = rb_funcall(cDO_Logger_Message, ID_NEW, 3, string, rb_time_new(start->tv_sec, start->tv_usec), INT2NUM(duration));
411
-
412
- rb_funcall(connection, ID_LOG, 1, message);
413
- }
414
-
415
- static void raise_error(VALUE self, MYSQL *db, VALUE query) {
416
- VALUE exception;
417
- const char *exception_type = "SQLError";
418
- char *mysql_error_message = (char *)mysql_error(db);
419
- int mysql_error_code = mysql_errno(db);
420
-
421
- struct errcodes *errs;
422
-
423
- for (errs = errors; errs->error_name; errs++) {
424
- if(errs->error_no == mysql_error_code) {
425
- exception_type = errs->exception;
426
- break;
427
- }
95
+ else {
96
+ return do_typecast(value, length, type, encoding);
428
97
  }
98
+ }
429
99
 
430
- VALUE uri = rb_funcall(rb_iv_get(self, "@connection"), rb_intern("to_s"), 0);
431
-
100
+ void raise_error(VALUE self, MYSQL *db, VALUE query) {
101
+ int errnum = mysql_errno(db);
102
+ const char *message = mysql_error(db);
432
103
  VALUE sql_state = Qnil;
104
+
433
105
  #ifdef HAVE_MYSQL_SQLSTATE
434
106
  sql_state = rb_str_new2(mysql_sqlstate(db));
435
107
  #endif
436
108
 
437
- exception = rb_funcall(CONST_GET(mDO, exception_type), ID_NEW, 5,
438
- rb_str_new2(mysql_error_message),
439
- INT2NUM(mysql_error_code),
440
- sql_state,
441
- query,
442
- uri);
443
- rb_exc_raise(exception);
444
- }
445
-
446
- static char * get_uri_option(VALUE query_hash, const char * key) {
447
- VALUE query_value;
448
- char * value = NULL;
449
-
450
- if(!rb_obj_is_kind_of(query_hash, rb_cHash)) { return NULL; }
451
-
452
- query_value = rb_hash_aref(query_hash, rb_str_new2(key));
453
-
454
- if (Qnil != query_value) {
455
- value = StringValuePtr(query_value);
456
- }
457
-
458
- return value;
459
- }
460
-
461
- static void assert_file_exists(char * file, const char * message) {
462
- if (file == NULL) { return; }
463
- if (rb_funcall(rb_cFile, rb_intern("exist?"), 1, rb_str_new2(file)) == Qfalse) {
464
- rb_raise(rb_eArgError, "%s", message);
465
- }
109
+ do_raise_error(self, errors, errnum, message, query, sql_state);
466
110
  }
467
111
 
468
- static void full_connect(VALUE self, MYSQL *db);
469
-
470
112
  #ifdef _WIN32
471
- static MYSQL_RES* cCommand_execute_sync(VALUE self, VALUE connection, MYSQL* db, VALUE query) {
113
+ MYSQL_RES *cCommand_execute_sync(VALUE self, VALUE connection, MYSQL *db, VALUE query) {
472
114
  int retval;
473
115
  struct timeval start;
474
- const char* str = rb_str_ptr_readonly(query);
475
- int len = rb_str_len(query);
116
+ const char *str = rb_str_ptr_readonly(query);
117
+ long len = rb_str_len(query);
476
118
 
477
- if(mysql_ping(db) && mysql_errno(db) == CR_SERVER_GONE_ERROR) {
119
+ if (mysql_ping(db) && mysql_errno(db) == CR_SERVER_GONE_ERROR) {
478
120
  // Ok, we do one more try here by doing a full connect
479
121
  VALUE connection = rb_iv_get(self, "@connection");
480
122
  full_connect(connection, db);
481
123
  }
124
+
482
125
  gettimeofday(&start, NULL);
483
126
  retval = mysql_real_query(db, str, len);
484
127
  data_objects_debug(connection, query, &start);
@@ -488,38 +131,37 @@ static MYSQL_RES* cCommand_execute_sync(VALUE self, VALUE connection, MYSQL* db,
488
131
  return mysql_store_result(db);
489
132
  }
490
133
  #else
491
- static MYSQL_RES* cCommand_execute_async(VALUE self, VALUE connection, MYSQL* db, VALUE query) {
492
- int socket_fd;
134
+ MYSQL_RES *cCommand_execute_async(VALUE self, VALUE connection, MYSQL *db, VALUE query) {
493
135
  int retval;
494
- fd_set rset;
495
- struct timeval start;
496
- const char* str = rb_str_ptr_readonly(query);
497
- size_t len = rb_str_len(query);
498
- MYSQL_RES* result;
499
136
 
500
- if((retval = mysql_ping(db)) && mysql_errno(db) == CR_SERVER_GONE_ERROR) {
137
+ if ((retval = mysql_ping(db)) && mysql_errno(db) == CR_SERVER_GONE_ERROR) {
501
138
  full_connect(connection, db);
502
139
  }
503
- gettimeofday(&start, NULL);
504
140
 
141
+ struct timeval start;
142
+ const char *str = rb_str_ptr_readonly(query);
143
+ long len = rb_str_len(query);
144
+
145
+ gettimeofday(&start, NULL);
505
146
  retval = mysql_send_query(db, str, len);
506
147
 
507
148
  CHECK_AND_RAISE(retval, query);
508
149
 
509
- socket_fd = db->net.fd;
150
+ int socket_fd = db->net.fd;
151
+ fd_set rset;
510
152
 
511
- for(;;) {
153
+ while (1) {
512
154
  FD_ZERO(&rset);
513
155
  FD_SET(socket_fd, &rset);
514
156
 
515
157
  retval = rb_thread_select(socket_fd + 1, &rset, NULL, NULL, NULL);
516
158
 
517
159
  if (retval < 0) {
518
- rb_sys_fail(0);
160
+ rb_sys_fail(0);
519
161
  }
520
162
 
521
163
  if (retval == 0) {
522
- continue;
164
+ continue;
523
165
  }
524
166
 
525
167
  if (db->status == MYSQL_STATUS_READY) {
@@ -531,60 +173,66 @@ static MYSQL_RES* cCommand_execute_async(VALUE self, VALUE connection, MYSQL* db
531
173
  CHECK_AND_RAISE(retval, query);
532
174
  data_objects_debug(connection, query, &start);
533
175
 
534
- result = mysql_store_result(db);
176
+ MYSQL_RES *result = mysql_store_result(db);
535
177
 
536
- if (!result)
178
+ if (!result) {
537
179
  CHECK_AND_RAISE(mysql_errno(db), query);
180
+ }
538
181
 
539
182
  return result;
540
183
  }
541
184
  #endif
542
185
 
186
+ void full_connect(VALUE self, MYSQL *db) {
187
+ VALUE r_host = rb_iv_get(self, "@host");
188
+ const char *host = "localhost";
543
189
 
544
- static void full_connect(VALUE self, MYSQL* db) {
545
- // Check to see if we're on the db machine. If so, try to use the socket
546
- VALUE r_host, r_user, r_password, r_path, r_query, r_port;
547
-
548
- const char *host = "localhost", *user = "root";
549
- char *database = NULL, *socket = NULL, *password = NULL, *path = NULL;
550
- VALUE encoding = Qnil;
551
-
552
- MYSQL *result;
190
+ if (r_host != Qnil) {
191
+ host = StringValuePtr(r_host);
192
+ }
553
193
 
554
- int port = 3306;
555
- unsigned long client_flags = 0;
556
- int encoding_error;
194
+ VALUE r_user = rb_iv_get(self, "@user");
195
+ const char *user = "root";
557
196
 
558
- if((r_host = rb_iv_get(self, "@host")) != Qnil) {
559
- host = StringValuePtr(r_host);
197
+ if (r_user != Qnil) {
198
+ user = StringValuePtr(r_user);
560
199
  }
561
200
 
562
- if((r_user = rb_iv_get(self, "@user")) != Qnil) {
563
- user = StringValuePtr(r_user);
564
- }
201
+ VALUE r_password = rb_iv_get(self, "@password");
202
+ char *password = NULL;
565
203
 
566
- if((r_password = rb_iv_get(self, "@password")) != Qnil) {
204
+ if (r_password != Qnil) {
567
205
  password = StringValuePtr(r_password);
568
206
  }
569
207
 
570
- if((r_port = rb_iv_get(self, "@port")) != Qnil) {
208
+ VALUE r_port = rb_iv_get(self, "@port");
209
+ int port = 3306;
210
+
211
+ if (r_port != Qnil) {
571
212
  port = NUM2INT(r_port);
572
213
  }
573
214
 
574
- if((r_path = rb_iv_get(self, "@path")) != Qnil) {
215
+ VALUE r_path = rb_iv_get(self, "@path");
216
+ char *path = NULL;
217
+ char *database = NULL;
218
+
219
+ if (r_path != Qnil) {
575
220
  path = StringValuePtr(r_path);
576
- database = strtok(path, "/");
221
+ database = strtok(path, "/"); // not threadsafe
577
222
  }
578
223
 
579
- if (NULL == database || 0 == strlen(database)) {
224
+ if (!database || !*database) {
580
225
  rb_raise(eConnectionError, "Database must be specified");
581
226
  }
582
227
 
583
- r_query = rb_iv_get(self, "@query");
228
+ VALUE r_query = rb_iv_get(self, "@query");
229
+ char *socket = NULL;
584
230
 
585
- if (0 == strcasecmp(host, "localhost")) {
231
+ // Check to see if we're on the db machine. If so, try to use the socket
232
+ if (strcasecmp(host, "localhost") == 0) {
586
233
  socket = get_uri_option(r_query, "socket");
587
- if (NULL != socket) {
234
+
235
+ if (socket) {
588
236
  rb_iv_set(self, "@using_socket", Qtrue);
589
237
  }
590
238
  }
@@ -593,10 +241,10 @@ static void full_connect(VALUE self, MYSQL* db) {
593
241
  char *ssl_client_key, *ssl_client_cert, *ssl_ca_cert, *ssl_ca_path, *ssl_cipher;
594
242
  VALUE r_ssl;
595
243
 
596
- if(rb_obj_is_kind_of(r_query, rb_cHash)) {
244
+ if (rb_obj_is_kind_of(r_query, rb_cHash)) {
597
245
  r_ssl = rb_hash_aref(r_query, rb_str_new2("ssl"));
598
246
 
599
- if(rb_obj_is_kind_of(r_ssl, rb_cHash)) {
247
+ if (rb_obj_is_kind_of(r_ssl, rb_cHash)) {
600
248
  ssl_client_key = get_uri_option(r_ssl, "client_key");
601
249
  ssl_client_cert = get_uri_option(r_ssl, "client_cert");
602
250
  ssl_ca_cert = get_uri_option(r_ssl, "ca_cert");
@@ -608,13 +256,16 @@ static void full_connect(VALUE self, MYSQL* db) {
608
256
  assert_file_exists(ssl_ca_cert, "ca_cert doesn't exist");
609
257
 
610
258
  mysql_ssl_set(db, ssl_client_key, ssl_client_cert, ssl_ca_cert, ssl_ca_path, ssl_cipher);
611
- } else if(r_ssl != Qnil) {
259
+ }
260
+ else if (r_ssl != Qnil) {
612
261
  rb_raise(rb_eArgError, "ssl must be passed a hash");
613
262
  }
614
263
  }
615
264
  #endif
616
265
 
617
- result = (MYSQL *)mysql_real_connect(
266
+ unsigned long client_flags = 0;
267
+
268
+ MYSQL *result = mysql_real_connect(
618
269
  db,
619
270
  host,
620
271
  user,
@@ -625,14 +276,14 @@ static void full_connect(VALUE self, MYSQL* db) {
625
276
  client_flags
626
277
  );
627
278
 
628
- if (NULL == result) {
279
+ if (!result) {
629
280
  raise_error(self, db, Qnil);
630
281
  }
631
282
 
632
283
  #ifdef HAVE_MYSQL_GET_SSL_CIPHER
633
284
  const char *ssl_cipher_used = mysql_get_ssl_cipher(db);
634
285
 
635
- if (NULL != ssl_cipher_used) {
286
+ if (ssl_cipher_used) {
636
287
  rb_iv_set(self, "@ssl_cipher", rb_str_new2(ssl_cipher_used));
637
288
  }
638
289
  #endif
@@ -642,7 +293,6 @@ static void full_connect(VALUE self, MYSQL* db) {
642
293
  mysql_options(db, MYSQL_OPT_RECONNECT, &reconnect);
643
294
  #endif
644
295
 
645
-
646
296
  // We only support encoding for MySQL versions providing mysql_set_character_set.
647
297
  // Without this function there are potential issues with mysql_real_escape_string
648
298
  // since that doesn't take the character set into consideration when setting it
@@ -651,21 +301,24 @@ static void full_connect(VALUE self, MYSQL* db) {
651
301
 
652
302
  #ifdef HAVE_MYSQL_SET_CHARACTER_SET
653
303
  // Set the connections character set
654
- encoding = rb_iv_get(self, "@encoding");
304
+ VALUE encoding = rb_iv_get(self, "@encoding");
305
+ VALUE my_encoding = rb_hash_aref(do_const_get(mEncoding, "MAP"), encoding);
655
306
 
656
- VALUE my_encoding = rb_hash_aref(CONST_GET(mEncoding, "MAP"), encoding);
657
- if(my_encoding != Qnil) {
307
+ if (my_encoding != Qnil) {
308
+ int encoding_error = mysql_set_character_set(db, rb_str_ptr_readonly(my_encoding));
658
309
 
659
- encoding_error = mysql_set_character_set(db, rb_str_ptr_readonly(my_encoding));
660
- if (0 != encoding_error) {
310
+ if (encoding_error != 0) {
661
311
  raise_error(self, db, Qnil);
662
- } else {
312
+ }
313
+ else {
663
314
  #ifdef HAVE_RUBY_ENCODING_H
664
315
  rb_iv_set(self, "@encoding_id", INT2FIX(rb_enc_find_index(rb_str_ptr_readonly(encoding))));
665
316
  #endif
317
+
666
318
  rb_iv_set(self, "@my_encoding", my_encoding);
667
319
  }
668
- } else {
320
+ }
321
+ else {
669
322
  rb_warn("Encoding %s is not a known Ruby encoding for MySQL\n", rb_str_ptr_readonly(encoding));
670
323
  rb_iv_set(self, "@encoding", rb_str_new2("UTF-8"));
671
324
  #ifdef HAVE_RUBY_ENCODING_H
@@ -673,7 +326,6 @@ static void full_connect(VALUE self, MYSQL* db) {
673
326
  #endif
674
327
  rb_iv_set(self, "@my_encoding", rb_str_new2("utf8"));
675
328
  }
676
-
677
329
  #endif
678
330
 
679
331
  // Disable sql_auto_is_null
@@ -684,9 +336,10 @@ static void full_connect(VALUE self, MYSQL* db) {
684
336
  // For really anscient MySQL versions we don't attempt any strictness
685
337
  #ifdef HAVE_MYSQL_GET_SERVER_VERSION
686
338
  //4.x versions do not support certain session parameters
687
- if(mysql_get_server_version(db) < 50000 ){
339
+ if (mysql_get_server_version(db) < 50000) {
688
340
  cCommand_execute(Qnil, self, db, rb_str_new2("SET SESSION sql_mode = 'ANSI,NO_DIR_IN_CREATE,NO_UNSIGNED_SUBTRACTION'"));
689
- }else{
341
+ }
342
+ else {
690
343
  cCommand_execute(Qnil, self, db, rb_str_new2("SET SESSION sql_mode = 'ANSI,NO_BACKSLASH_ESCAPES,NO_DIR_IN_CREATE,NO_ENGINE_SUBSTITUTION,NO_UNSIGNED_SUBTRACTION,TRADITIONAL'"));
691
344
  }
692
345
  #endif
@@ -694,153 +347,104 @@ static void full_connect(VALUE self, MYSQL* db) {
694
347
  rb_iv_set(self, "@connection", Data_Wrap_Struct(rb_cObject, 0, 0, db));
695
348
  }
696
349
 
697
- static VALUE cConnection_initialize(VALUE self, VALUE uri) {
698
- VALUE r_host, r_user, r_password, r_path, r_query, r_port;
699
-
700
- MYSQL *db = 0;
701
- db = (MYSQL *)mysql_init(NULL);
702
-
350
+ VALUE cConnection_initialize(VALUE self, VALUE uri) {
703
351
  rb_iv_set(self, "@using_socket", Qfalse);
704
352
  rb_iv_set(self, "@ssl_cipher", Qnil);
705
353
 
706
- r_host = rb_funcall(uri, rb_intern("host"), 0);
707
- if (Qnil != r_host) {
354
+ VALUE r_host = rb_funcall(uri, rb_intern("host"), 0);
355
+
356
+ if (r_host != Qnil) {
708
357
  rb_iv_set(self, "@host", r_host);
709
358
  }
710
359
 
711
- r_user = rb_funcall(uri, rb_intern("user"), 0);
712
- if (Qnil != r_user) {
360
+ VALUE r_user = rb_funcall(uri, rb_intern("user"), 0);
361
+
362
+ if (r_user != Qnil) {
713
363
  rb_iv_set(self, "@user", r_user);
714
364
  }
715
365
 
716
- r_password = rb_funcall(uri, rb_intern("password"), 0);
717
- if (Qnil != r_password) {
366
+ VALUE r_password = rb_funcall(uri, rb_intern("password"), 0);
367
+
368
+ if (r_password != Qnil) {
718
369
  rb_iv_set(self, "@password", r_password);
719
370
  }
720
371
 
721
- r_path = rb_funcall(uri, rb_intern("path"), 0);
722
- if (Qnil != r_path) {
372
+ VALUE r_path = rb_funcall(uri, rb_intern("path"), 0);
373
+
374
+ if (r_path != Qnil) {
723
375
  rb_iv_set(self, "@path", r_path);
724
376
  }
725
377
 
726
- r_port = rb_funcall(uri, rb_intern("port"), 0);
727
- if (Qnil != r_port) {
378
+ VALUE r_port = rb_funcall(uri, rb_intern("port"), 0);
379
+
380
+ if (r_port != Qnil) {
728
381
  rb_iv_set(self, "@port", r_port);
729
382
  }
730
383
 
731
384
  // Pull the querystring off the URI
732
- r_query = rb_funcall(uri, rb_intern("query"), 0);
385
+ VALUE r_query = rb_funcall(uri, rb_intern("query"), 0);
386
+
733
387
  rb_iv_set(self, "@query", r_query);
734
388
 
735
- const char* encoding = get_uri_option(r_query, "encoding");
736
- if (!encoding) { encoding = get_uri_option(r_query, "charset"); }
737
- if (!encoding) { encoding = "UTF-8"; }
389
+ const char *encoding = get_uri_option(r_query, "encoding");
390
+
391
+ if (!encoding) {
392
+ encoding = get_uri_option(r_query, "charset");
393
+
394
+ if (!encoding) { encoding = "UTF-8"; }
395
+ }
738
396
 
739
397
  rb_iv_set(self, "@encoding", rb_str_new2(encoding));
740
398
 
741
- full_connect(self, db);
399
+ MYSQL *db = mysql_init(NULL);
742
400
 
401
+ full_connect(self, db);
743
402
  rb_iv_set(self, "@uri", uri);
744
-
745
403
  return Qtrue;
746
404
  }
747
405
 
748
- static VALUE cConnection_character_set(VALUE self) {
749
- return rb_iv_get(self, "@encoding");
750
- }
751
-
752
- static VALUE cConnection_is_using_socket(VALUE self) {
753
- return rb_iv_get(self, "@using_socket");
754
- }
755
-
756
- static VALUE cConnection_ssl_cipher(VALUE self) {
757
- return rb_iv_get(self, "@ssl_cipher");
758
- }
759
-
760
- static VALUE cConnection_dispose(VALUE self) {
406
+ VALUE cConnection_dispose(VALUE self) {
761
407
  VALUE connection_container = rb_iv_get(self, "@connection");
762
408
 
763
409
  MYSQL *db;
764
410
 
765
- if (Qnil == connection_container)
411
+ if (connection_container == Qnil) {
766
412
  return Qfalse;
413
+ }
767
414
 
768
415
  db = DATA_PTR(connection_container);
769
416
 
770
- if (NULL == db)
417
+ if (!db) {
771
418
  return Qfalse;
419
+ }
772
420
 
773
421
  mysql_close(db);
774
422
  rb_iv_set(self, "@connection", Qnil);
775
-
776
423
  return Qtrue;
777
424
  }
778
425
 
779
- /*
780
- Accepts an array of Ruby types (Fixnum, Float, String, etc...) and turns them
781
- into Ruby-strings so we can easily typecast later
782
- */
783
- static VALUE cCommand_set_types(int argc, VALUE *argv, VALUE self) {
784
- VALUE type_strings = rb_ary_new();
785
- VALUE array = rb_ary_new();
786
-
787
- int i, j;
788
-
789
- for ( i = 0; i < argc; i++) {
790
- rb_ary_push(array, argv[i]);
791
- }
792
-
793
- for (i = 0; i < RARRAY_LEN(array); i++) {
794
- VALUE entry = rb_ary_entry(array, i);
795
- if(TYPE(entry) == T_CLASS) {
796
- rb_ary_push(type_strings, entry);
797
- } else if (TYPE(entry) == T_ARRAY) {
798
- for (j = 0; j < RARRAY_LEN(entry); j++) {
799
- VALUE sub_entry = rb_ary_entry(entry, j);
800
- if(TYPE(sub_entry) == T_CLASS) {
801
- rb_ary_push(type_strings, sub_entry);
802
- } else {
803
- rb_raise(rb_eArgError, "Invalid type given");
804
- }
805
- }
806
- } else {
807
- rb_raise(rb_eArgError, "Invalid type given");
808
- }
809
- }
810
-
811
- rb_iv_set(self, "@field_types", type_strings);
812
-
813
- return array;
814
- }
815
-
816
- VALUE cConnection_quote_time(VALUE self, VALUE value) {
817
- return rb_funcall(value, ID_STRFTIME, 1, rb_str_new2("'%Y-%m-%d %H:%M:%S'"));
818
- }
819
-
820
-
821
- VALUE cConnection_quote_date_time(VALUE self, VALUE value) {
822
- // TODO: Support non-local dates. we need to call #new_offset on the date to be
823
- // quoted and pass in the current locale's date offset (self.new_offset((hours * 3600).to_r / 86400)
824
- return rb_funcall(value, ID_STRFTIME, 1, rb_str_new2("'%Y-%m-%d %H:%M:%S'"));
825
- }
826
-
827
- VALUE cConnection_quote_date(VALUE self, VALUE value) {
828
- return rb_funcall(value, ID_STRFTIME, 1, rb_str_new2("'%Y-%m-%d'"));
829
- }
830
-
831
- static VALUE cConnection_quote_string(VALUE self, VALUE string) {
426
+ VALUE cConnection_quote_string(VALUE self, VALUE string) {
832
427
  MYSQL *db = DATA_PTR(rb_iv_get(self, "@connection"));
833
428
  const char *source = rb_str_ptr_readonly(string);
834
- size_t source_len = rb_str_len(string);
835
- char *escaped;
836
- VALUE result;
429
+ long source_len = rb_str_len(string);
430
+ long buffer_len = source_len * 2 + 3;
837
431
 
838
- size_t quoted_length = 0;
432
+ // Overflow check
433
+ if(buffer_len <= source_len) {
434
+ rb_raise(rb_eArgError, "Input string is too large to be safely quoted");
435
+ }
839
436
 
840
437
  // Allocate space for the escaped version of 'string'. Use + 3 allocate space for null term.
841
438
  // and the leading and trailing single-quotes.
842
439
  // Thanks to http://www.browardphp.com/mysql_manual_en/manual_MySQL_APIs.html#mysql_real_escape_string
843
- escaped = (char *)calloc(source_len * 2 + 3, sizeof(char));
440
+ char *escaped = calloc(buffer_len, sizeof(char));
441
+
442
+ if (!escaped) {
443
+ rb_memerror();
444
+ }
445
+
446
+ unsigned long quoted_length;
447
+ VALUE result;
844
448
 
845
449
  // Escape 'source' using the current encoding in use on the conection 'db'
846
450
  quoted_length = mysql_real_escape_string(db, escaped + 1, source, source_len);
@@ -855,101 +459,78 @@ static VALUE cConnection_quote_string(VALUE self, VALUE string) {
855
459
  return result;
856
460
  }
857
461
 
858
- static VALUE build_query_from_args(VALUE klass, int count, VALUE *args) {
859
- VALUE query = rb_iv_get(klass, "@text");
860
-
861
- int i;
862
- VALUE array = rb_ary_new();
863
- for ( i = 0; i < count; i++) {
864
- rb_ary_push(array, (VALUE)args[i]);
865
- }
866
- query = rb_funcall(klass, ID_ESCAPE, 1, array);
867
-
868
- return query;
869
- }
870
-
871
- static VALUE cCommand_execute_non_query(int argc, VALUE *argv, VALUE self) {
872
- VALUE query;
873
-
874
- MYSQL_RES *response = 0;
875
-
876
- my_ulonglong affected_rows;
877
- my_ulonglong insert_id;
462
+ VALUE cCommand_execute_non_query(int argc, VALUE *argv, VALUE self) {
878
463
  VALUE connection = rb_iv_get(self, "@connection");
879
464
  VALUE mysql_connection = rb_iv_get(connection, "@connection");
880
- if (Qnil == mysql_connection) {
465
+
466
+ if (mysql_connection == Qnil) {
881
467
  rb_raise(eConnectionError, "This connection has already been closed.");
882
468
  }
883
469
 
884
470
  MYSQL *db = DATA_PTR(mysql_connection);
885
- query = build_query_from_args(self, argc, argv);
471
+ VALUE query = build_query_from_args(self, argc, argv);
472
+ MYSQL_RES *response = cCommand_execute(self, connection, db, query);
886
473
 
887
- response = cCommand_execute(self, connection, db, query);
474
+ my_ulonglong affected_rows = mysql_affected_rows(db);
475
+ my_ulonglong insert_id = mysql_insert_id(db);
888
476
 
889
- affected_rows = mysql_affected_rows(db);
890
- insert_id = mysql_insert_id(db);
891
477
  mysql_free_result(response);
892
478
 
893
- if ((my_ulonglong)-1 == affected_rows) {
479
+ if (((my_ulonglong)-1) == affected_rows) {
894
480
  return Qnil;
895
481
  }
896
482
 
897
483
  return rb_funcall(cResult, ID_NEW, 3, self, INT2NUM(affected_rows), insert_id == 0 ? Qnil : INT2NUM(insert_id));
898
484
  }
899
485
 
900
- static VALUE cCommand_execute_reader(int argc, VALUE *argv, VALUE self) {
901
- VALUE query, reader;
902
- VALUE field_names, field_types;
903
-
904
- unsigned int field_count;
905
- unsigned int i;
906
-
907
- char guess_default_field_types = 0;
486
+ VALUE cCommand_execute_reader(int argc, VALUE *argv, VALUE self) {
908
487
  VALUE connection = rb_iv_get(self, "@connection");
909
488
  VALUE mysql_connection = rb_iv_get(connection, "@connection");
910
- if (Qnil == mysql_connection) {
489
+
490
+ if (mysql_connection == Qnil) {
911
491
  rb_raise(eConnectionError, "This connection has already been closed.");
912
492
  }
913
493
 
494
+ VALUE query = build_query_from_args(self, argc, argv);
914
495
  MYSQL *db = DATA_PTR(mysql_connection);
915
-
916
- MYSQL_RES *response = 0;
917
- MYSQL_FIELD *field;
918
-
919
- query = build_query_from_args(self, argc, argv);
920
-
921
- response = cCommand_execute(self, connection, db, query);
496
+ MYSQL_RES *response = cCommand_execute(self, connection, db, query);
922
497
 
923
498
  if (!response) {
924
- return Qnil;
499
+ rb_raise(eConnectionError, "No result set received for a query that should yield one.");
925
500
  }
926
501
 
927
- field_count = mysql_field_count(db);
502
+ unsigned int field_count = mysql_field_count(db);
503
+ VALUE reader = rb_funcall(cReader, ID_NEW, 0);
928
504
 
929
- reader = rb_funcall(cReader, ID_NEW, 0);
930
505
  rb_iv_set(reader, "@connection", connection);
931
506
  rb_iv_set(reader, "@reader", Data_Wrap_Struct(rb_cObject, 0, 0, response));
932
507
  rb_iv_set(reader, "@opened", Qfalse);
933
508
  rb_iv_set(reader, "@field_count", INT2NUM(field_count));
934
509
 
935
- field_names = rb_ary_new();
936
- field_types = rb_iv_get(self, "@field_types");
510
+ VALUE field_names = rb_ary_new();
511
+ VALUE field_types = rb_iv_get(self, "@field_types");
512
+
513
+ char guess_default_field_types = 0;
937
514
 
938
- if ( field_types == Qnil || 0 == RARRAY_LEN(field_types) ) {
515
+ if (field_types == Qnil || RARRAY_LEN(field_types) == 0) {
939
516
  field_types = rb_ary_new();
940
517
  guess_default_field_types = 1;
941
- } else if (RARRAY_LEN(field_types) != field_count) {
942
- // Whoops... wrong number of types passed to set_types. Close the reader and raise
518
+ }
519
+ else if (RARRAY_LEN(field_types) != field_count) {
520
+ // Whoops... wrong number of types passed to set_types. Close the reader and raise
943
521
  // and error
944
522
  rb_funcall(reader, rb_intern("close"), 0);
945
523
  rb_raise(rb_eArgError, "Field-count mismatch. Expected %ld fields, but the query yielded %d", RARRAY_LEN(field_types), field_count);
946
524
  }
947
525
 
526
+ MYSQL_FIELD *field;
527
+ unsigned int i;
528
+
948
529
  for(i = 0; i < field_count; i++) {
949
530
  field = mysql_fetch_field_direct(response, i);
950
531
  rb_ary_push(field_names, rb_str_new2(field->name));
951
532
 
952
- if (1 == guess_default_field_types) {
533
+ if (guess_default_field_types == 1) {
953
534
  rb_ary_push(field_types, infer_ruby_type(field));
954
535
  }
955
536
  }
@@ -966,51 +547,43 @@ static VALUE cCommand_execute_reader(int argc, VALUE *argv, VALUE self) {
966
547
  }
967
548
 
968
549
  // This should be called to ensure that the internal result reader is freed
969
- static VALUE cReader_close(VALUE self) {
550
+ VALUE cReader_close(VALUE self) {
970
551
  // Get the reader from the instance variable, maybe refactor this?
971
552
  VALUE reader_container = rb_iv_get(self, "@reader");
972
553
 
973
- MYSQL_RES *reader;
974
-
975
- if (Qnil == reader_container)
554
+ if (reader_container == Qnil) {
976
555
  return Qfalse;
556
+ }
977
557
 
978
- reader = DATA_PTR(reader_container);
558
+ MYSQL_RES *reader = DATA_PTR(reader_container);
979
559
 
980
560
  // The Meat
981
- if (NULL == reader)
561
+ if (!reader) {
982
562
  return Qfalse;
563
+ }
983
564
 
984
565
  mysql_free_result(reader);
985
566
  rb_iv_set(self, "@reader", Qnil);
986
567
  rb_iv_set(self, "@opened", Qfalse);
987
-
988
568
  return Qtrue;
989
569
  }
990
570
 
991
571
  // Retrieve a single row
992
- static VALUE cReader_next(VALUE self) {
572
+ VALUE cReader_next(VALUE self) {
993
573
  // Get the reader from the instance variable, maybe refactor this?
994
574
  VALUE reader_container = rb_iv_get(self, "@reader");
995
- VALUE field_types, field_type, row;
996
-
997
- MYSQL_RES *reader;
998
- MYSQL_ROW result;
999
- unsigned long *lengths;
1000
-
1001
- unsigned int i;
1002
575
 
1003
- if (Qnil == reader_container) {
576
+ if (reader_container == Qnil) {
1004
577
  return Qfalse;
1005
578
  }
1006
579
 
1007
- reader = DATA_PTR(reader_container);
580
+ MYSQL_RES *reader = DATA_PTR(reader_container);
581
+ MYSQL_ROW result = mysql_fetch_row(reader);
1008
582
 
1009
583
  // The Meat
1010
- field_types = rb_iv_get(self, "@field_types");
1011
- row = rb_ary_new();
1012
- result = mysql_fetch_row(reader);
1013
- lengths = mysql_fetch_lengths(reader);
584
+ VALUE field_types = rb_iv_get(self, "@field_types");
585
+ VALUE row = rb_ary_new();
586
+ unsigned long *lengths = mysql_fetch_lengths(reader);
1014
587
 
1015
588
  rb_iv_set(self, "@opened", result ? Qtrue : Qfalse);
1016
589
 
@@ -1021,11 +594,15 @@ static VALUE cReader_next(VALUE self) {
1021
594
  int enc = -1;
1022
595
  #ifdef HAVE_RUBY_ENCODING_H
1023
596
  VALUE encoding_id = rb_iv_get(rb_iv_get(self, "@connection"), "@encoding_id");
597
+
1024
598
  if (encoding_id != Qnil) {
1025
599
  enc = FIX2INT(encoding_id);
1026
600
  }
1027
601
  #endif
1028
602
 
603
+ VALUE field_type;
604
+ unsigned int i;
605
+
1029
606
  for (i = 0; i < reader->field_count; i++) {
1030
607
  // The field_type data could be cached in a c-array
1031
608
  field_type = rb_ary_entry(field_types, i);
@@ -1033,72 +610,17 @@ static VALUE cReader_next(VALUE self) {
1033
610
  }
1034
611
 
1035
612
  rb_iv_set(self, "@values", row);
1036
-
1037
613
  return Qtrue;
1038
614
  }
1039
615
 
1040
- static VALUE cReader_values(VALUE self) {
1041
- VALUE state = rb_iv_get(self, "@opened");
1042
- if ( state == Qnil || state == Qfalse ) {
1043
- rb_raise(eDataError, "Reader is not initialized");
1044
- }
1045
- return rb_iv_get(self, "@values");
1046
- }
1047
-
1048
- static VALUE cReader_fields(VALUE self) {
1049
- return rb_iv_get(self, "@fields");
1050
- }
1051
-
1052
- static VALUE cReader_field_count(VALUE self) {
1053
- return rb_iv_get(self, "@field_count");
1054
- }
1055
-
1056
616
  void Init_do_mysql() {
1057
- rb_require("bigdecimal");
1058
- rb_require("rational");
1059
- rb_require("date");
1060
- rb_require("data_objects");
1061
-
1062
- ID_CONST_GET = rb_intern("const_get");
1063
-
1064
- // Get references classes needed for Date/Time parsing
1065
- rb_cDate = CONST_GET(rb_mKernel, "Date");
1066
- rb_cDateTime = CONST_GET(rb_mKernel, "DateTime");
1067
- rb_cBigDecimal = CONST_GET(rb_mKernel, "BigDecimal");
1068
-
1069
- ID_NEW = rb_intern("new");
1070
- #ifdef RUBY_LESS_THAN_186
1071
- ID_NEW_DATE = rb_intern("new0");
1072
- #else
1073
- ID_NEW_DATE = rb_intern("new!");
1074
- #endif
1075
- ID_CONST_GET = rb_intern("const_get");
1076
- ID_RATIONAL = rb_intern("Rational");
1077
- ID_ESCAPE = rb_intern("escape_sql");
1078
- ID_STRFTIME = rb_intern("strftime");
1079
- ID_LOG = rb_intern("log");
1080
-
1081
- // Get references to the Extlib module
1082
- mExtlib = CONST_GET(rb_mKernel, "Extlib");
1083
- rb_cByteArray = CONST_GET(mExtlib, "ByteArray");
1084
-
1085
- // Get references to the DataObjects module and its classes
1086
- mDO = CONST_GET(rb_mKernel, "DataObjects");
1087
- cDO_Quoting = CONST_GET(mDO, "Quoting");
1088
- cDO_Connection = CONST_GET(mDO, "Connection");
1089
- cDO_Command = CONST_GET(mDO, "Command");
1090
- cDO_Result = CONST_GET(mDO, "Result");
1091
- cDO_Reader = CONST_GET(mDO, "Reader");
1092
- cDO_Logger = CONST_GET(mDO, "Logger");
1093
- cDO_Logger_Message = CONST_GET(cDO_Logger, "Message");
617
+ common_init();
1094
618
 
1095
619
  // Top Level Module that all the classes live under
1096
- mMysql = rb_define_module_under(mDO, "Mysql");
1097
- eConnectionError = CONST_GET(mDO, "ConnectionError");
1098
- eDataError = CONST_GET(mDO, "DataError");
620
+ mMysql = rb_define_module_under(mDO, "Mysql");
1099
621
  mEncoding = rb_define_module_under(mMysql, "Encoding");
1100
622
 
1101
- cConnection = DRIVER_CLASS("Connection", cDO_Connection);
623
+ cConnection = rb_define_class_under(mMysql, "Connection", cDO_Connection);
1102
624
  rb_define_method(cConnection, "initialize", cConnection_initialize, 1);
1103
625
  rb_define_method(cConnection, "using_socket?", cConnection_is_using_socket, 0);
1104
626
  rb_define_method(cConnection, "ssl_cipher", cConnection_ssl_cipher, 0);
@@ -1109,46 +631,24 @@ void Init_do_mysql() {
1109
631
  rb_define_method(cConnection, "quote_time", cConnection_quote_time, 1);
1110
632
  rb_define_method(cConnection, "quote_datetime", cConnection_quote_date_time, 1);
1111
633
 
1112
- cCommand = DRIVER_CLASS("Command", cDO_Command);
634
+ cCommand = rb_define_class_under(mMysql, "Command", cDO_Command);
1113
635
  rb_define_method(cCommand, "set_types", cCommand_set_types, -1);
1114
636
  rb_define_method(cCommand, "execute_non_query", cCommand_execute_non_query, -1);
1115
637
  rb_define_method(cCommand, "execute_reader", cCommand_execute_reader, -1);
1116
638
 
1117
639
  // Non-Query result
1118
- cResult = DRIVER_CLASS("Result", cDO_Result);
640
+ cResult = rb_define_class_under(mMysql, "Result", cDO_Result);
1119
641
 
1120
642
  // Query result
1121
- cReader = DRIVER_CLASS("Reader", cDO_Reader);
643
+ cReader = rb_define_class_under(mMysql, "Reader", cDO_Reader);
1122
644
  rb_define_method(cReader, "close", cReader_close, 0);
1123
645
  rb_define_method(cReader, "next!", cReader_next, 0);
1124
646
  rb_define_method(cReader, "values", cReader_values, 0);
1125
647
  rb_define_method(cReader, "fields", cReader_fields, 0);
1126
648
  rb_define_method(cReader, "field_count", cReader_field_count, 0);
1127
649
 
1128
- rb_global_variable(&ID_NEW_DATE);
1129
- rb_global_variable(&ID_RATIONAL);
1130
- rb_global_variable(&ID_CONST_GET);
1131
- rb_global_variable(&ID_ESCAPE);
1132
- rb_global_variable(&ID_LOG);
1133
- rb_global_variable(&ID_NEW);
1134
-
1135
- rb_global_variable(&rb_cDate);
1136
- rb_global_variable(&rb_cDateTime);
1137
- rb_global_variable(&rb_cBigDecimal);
1138
- rb_global_variable(&rb_cByteArray);
1139
-
1140
- rb_global_variable(&mDO);
1141
- rb_global_variable(&cDO_Logger_Message);
1142
-
1143
650
  rb_global_variable(&cResult);
1144
651
  rb_global_variable(&cReader);
1145
652
 
1146
- rb_global_variable(&eConnectionError);
1147
- rb_global_variable(&eDataError);
1148
-
1149
- struct errcodes *errs;
1150
-
1151
- for (errs = errors; errs->error_name; errs++) {
1152
- rb_const_set(mMysql, rb_intern(errs->error_name), INT2NUM(errs->error_no));
1153
- }
653
+ do_define_errors(mMysql, errors);
1154
654
  }