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

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
  }