do_mysql 0.9.12-x86-mingw32 → 0.10.0-x86-mingw32

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.
data/HISTORY.markdown ADDED
@@ -0,0 +1,17 @@
1
+ ## 0.10.0 2009-10-15
2
+ * Improvements
3
+ * JRuby Support (using *do_jdbc*)
4
+
5
+ ## 0.9.12 2009-05-17
6
+ * Improvements
7
+ * Windows support
8
+
9
+ ## 0.9.11 2009-01-19
10
+ * Improvements
11
+ * Ruby 1.9 support
12
+ * Fixes
13
+ * Reconnecting now works properly
14
+
15
+ ## 0.9.9 2008-11-27
16
+ * Improvements
17
+ * Added initial support for Ruby 1.9 [John Harrison]
data/Manifest.txt CHANGED
@@ -1,8 +1,8 @@
1
1
  .gitignore
2
- History.txt
2
+ HISTORY.markdown
3
3
  LICENSE
4
4
  Manifest.txt
5
- README.txt
5
+ README.markdown
6
6
  Rakefile
7
7
  buildfile
8
8
  ext-java/src/main/java/DoMysqlExtService.java
@@ -1,3 +1,4 @@
1
- = do_mysql
1
+ do_mysql
2
+ ========
2
3
 
3
4
  A MySQL driver for DataObjects
data/Rakefile CHANGED
@@ -8,9 +8,9 @@ require 'lib/do_mysql/version'
8
8
  ROOT = Pathname(__FILE__).dirname.expand_path
9
9
  JRUBY = RUBY_PLATFORM =~ /java/
10
10
  WINDOWS = Gem.win_platform?
11
- SUDO = (WINDOWS || JRUBY) ? '' : ('sudo' unless ENV['SUDOLESS'])
12
- BINARY_VERSION = '5.0.77'
11
+ SUDO = WINDOWS ? '' : ('sudo' unless ENV['SUDOLESS'])
12
+ BINARY_VERSION = '5.0.85'
13
13
 
14
- Dir['tasks/*.rake'].each { |f| import f }
14
+ Dir['tasks/*.rake'].sort.each { |f| import f }
15
15
 
16
16
  CLEAN.include(%w[ {tmp,pkg}/ **/*.{o,so,bundle,jar,log,a,gem,dSYM,obj,pdb,exp,DS_Store,rbc,db} ext/do_mysql_ext/Makefile ext-java/target ])
@@ -6,14 +6,12 @@
6
6
  #include <mysql.h>
7
7
  #include <errmsg.h>
8
8
  #include <mysqld_error.h>
9
+ #include "error.h"
9
10
 
10
11
  #define RUBY_CLASS(name) rb_const_get(rb_cObject, rb_intern(name))
11
- #define RUBY_STRING(char_ptr) rb_str_new2(char_ptr)
12
- #define TAINTED_STRING(name, length) rb_tainted_str_new(name, length)
13
12
  #define DRIVER_CLASS(klass, parent) (rb_define_class_under(mDOMysql, klass, parent))
14
13
  #define CONST_GET(scope, constant) (rb_funcall(scope, ID_CONST_GET, 1, rb_str_new2(constant)))
15
- #define CHECK_AND_RAISE(mysql_result_value, str) if (0 != mysql_result_value) { raise_mysql_error(connection, db, mysql_result_value, str); }
16
- #define PUTS(string) rb_funcall(rb_mKernel, rb_intern("puts"), 1, RUBY_STRING(string))
14
+ #define CHECK_AND_RAISE(mysql_result_value, query) if (0 != mysql_result_value) { raise_error(self, db, query); }
17
15
 
18
16
  #ifndef RSTRING_PTR
19
17
  #define RSTRING_PTR(s) (RSTRING(s)->ptr)
@@ -35,6 +33,37 @@
35
33
  #define do_int64 signed long long int
36
34
  #endif
37
35
 
36
+ #ifdef HAVE_RUBY_ENCODING_H
37
+ #include <ruby/encoding.h>
38
+
39
+ #define DO_STR_NEW2(str, encoding) \
40
+ ({ \
41
+ VALUE _string = rb_str_new2((const char *)str); \
42
+ if(encoding != -1) { \
43
+ rb_enc_associate_index(_string, encoding); \
44
+ } \
45
+ _string; \
46
+ })
47
+
48
+ #define DO_STR_NEW(str, len, encoding) \
49
+ ({ \
50
+ VALUE _string = rb_str_new((const char *)str, (long)len); \
51
+ if(encoding != -1) { \
52
+ rb_enc_associate_index(_string, encoding); \
53
+ } \
54
+ _string; \
55
+ })
56
+
57
+ #else
58
+
59
+ #define DO_STR_NEW2(str, encoding) \
60
+ rb_str_new2((const char *)str)
61
+
62
+ #define DO_STR_NEW(str, len, encoding) \
63
+ rb_str_new((const char *)str, (long)len)
64
+ #endif
65
+
66
+
38
67
  // To store rb_intern values
39
68
  static ID ID_TO_I;
40
69
  static ID ID_TO_F;
@@ -56,6 +85,7 @@ static VALUE mExtlib;
56
85
 
57
86
  // References to DataObjects base classes
58
87
  static VALUE mDO;
88
+ static VALUE mEncoding;
59
89
  static VALUE cDO_Quoting;
60
90
  static VALUE cDO_Connection;
61
91
  static VALUE cDO_Command;
@@ -74,8 +104,9 @@ static VALUE cConnection;
74
104
  static VALUE cCommand;
75
105
  static VALUE cResult;
76
106
  static VALUE cReader;
77
- static VALUE eMysqlError;
78
107
  static VALUE eArgumentError;
108
+ static VALUE eConnectionError;
109
+ static VALUE eDataError;
79
110
 
80
111
  // Figures out what we should cast a given mysql field type to
81
112
  static VALUE infer_ruby_type(MYSQL_FIELD *field) {
@@ -100,8 +131,6 @@ static VALUE infer_ruby_type(MYSQL_FIELD *field) {
100
131
  case MYSQL_TYPE_TIMESTAMP:
101
132
  case MYSQL_TYPE_DATETIME:
102
133
  return rb_cDateTime;
103
- case MYSQL_TYPE_TIME:
104
- return rb_cDateTime;
105
134
  case MYSQL_TYPE_DATE:
106
135
  case MYSQL_TYPE_NEWDATE:
107
136
  return rb_cDate;
@@ -239,7 +268,7 @@ static VALUE parse_date_time(const char *date) {
239
268
  hour_offset = 0;
240
269
  minute_offset = 0;
241
270
  sec = 0;
242
- }
271
+ }
243
272
  // We read the Date and Time, default to the current locale's offset
244
273
 
245
274
  // Get localtime
@@ -261,7 +290,7 @@ static VALUE parse_date_time(const char *date) {
261
290
 
262
291
  } else {
263
292
  // Something went terribly wrong
264
- rb_raise(eMysqlError, "Couldn't parse date: %s", date);
293
+ rb_raise(eDataError, "Couldn't parse date: %s", date);
265
294
  }
266
295
 
267
296
  jd = jd_from_date(year, month, day);
@@ -295,7 +324,7 @@ static VALUE parse_date_time(const char *date) {
295
324
  }
296
325
 
297
326
  // Convert C-string to a Ruby instance of Ruby type "type"
298
- static VALUE typecast(const char *value, long length, const VALUE type) {
327
+ static VALUE typecast(const char *value, long length, const VALUE type, int encoding) {
299
328
 
300
329
  if(NULL == value) {
301
330
  return Qnil;
@@ -304,11 +333,11 @@ static VALUE typecast(const char *value, long length, const VALUE type) {
304
333
  if (type == rb_cInteger) {
305
334
  return rb_cstr2inum(value, 10);
306
335
  } else if (type == rb_cString) {
307
- return TAINTED_STRING(value, length);
336
+ return DO_STR_NEW(value, length, encoding);
308
337
  } else if (type == rb_cFloat) {
309
338
  return rb_float_new(rb_cstr_to_dbl(value, Qfalse));
310
339
  } else if (type == rb_cBigDecimal) {
311
- return rb_funcall(rb_cBigDecimal, ID_NEW, 1, TAINTED_STRING(value, length));
340
+ return rb_funcall(rb_cBigDecimal, ID_NEW, 1, rb_str_new(value, length));
312
341
  } else if (type == rb_cDate) {
313
342
  return parse_date(value);
314
343
  } else if (type == rb_cDateTime) {
@@ -318,15 +347,15 @@ static VALUE typecast(const char *value, long length, const VALUE type) {
318
347
  } else if (type == rb_cTrueClass) {
319
348
  return (0 == value || 0 == strcmp("0", value)) ? Qfalse : Qtrue;
320
349
  } else if (type == rb_cByteArray) {
321
- return rb_funcall(rb_cByteArray, ID_NEW, 1, TAINTED_STRING(value, length));
350
+ return rb_funcall(rb_cByteArray, ID_NEW, 1, rb_str_new(value, length));
322
351
  } else if (type == rb_cClass) {
323
- return rb_funcall(rb_cObject, rb_intern("full_const_get"), 1, TAINTED_STRING(value, length));
352
+ return rb_funcall(rb_cObject, rb_intern("full_const_get"), 1, rb_str_new(value, length));
324
353
  } else if (type == rb_cObject) {
325
354
  return rb_marshal_load(rb_str_new(value, length));
326
355
  } else if (type == rb_cNilClass) {
327
356
  return Qnil;
328
357
  } else {
329
- return TAINTED_STRING(value, length);
358
+ return DO_STR_NEW(value, length, encoding);
330
359
  }
331
360
 
332
361
  }
@@ -354,17 +383,31 @@ static void data_objects_debug(VALUE string, struct timeval* start) {
354
383
  rb_funcall(logger, ID_DEBUG, 1, rb_str_new(message, length + strlen(total_time) + 3));
355
384
  }
356
385
  }
357
- static void raise_mysql_error(VALUE connection, MYSQL *db, int mysql_error_code, char* str) {
386
+
387
+ static void raise_error(VALUE self, MYSQL *db, VALUE query) {
388
+ VALUE exception;
389
+ const char *exception_type = "SQLError";
358
390
  char *mysql_error_message = (char *)mysql_error(db);
391
+ int mysql_error_code = mysql_errno(db);
359
392
 
360
- if(mysql_error_code == 1) {
361
- mysql_error_code = mysql_errno(db);
362
- }
363
- if(str) {
364
- rb_raise(eMysqlError, "(mysql_errno=%04d, sql_state=%s) %s\nQuery: %s", mysql_error_code, mysql_sqlstate(db), mysql_error_message, str);
365
- } else {
366
- rb_raise(eMysqlError, "(mysql_errno=%04d, sql_state=%s) %s", mysql_error_code, mysql_sqlstate(db), mysql_error_message);
393
+ struct errcodes *errs;
394
+
395
+ for (errs = errors; errs->error_name; errs++) {
396
+ if(errs->error_no == mysql_error_code) {
397
+ exception_type = errs->exception;
398
+ break;
399
+ }
367
400
  }
401
+
402
+ VALUE uri = rb_funcall(rb_iv_get(self, "@connection"), rb_intern("to_s"), 0);
403
+
404
+ exception = rb_funcall(CONST_GET(mDO, exception_type), ID_NEW, 5,
405
+ rb_str_new2(mysql_error_message),
406
+ INT2NUM(mysql_error_code),
407
+ rb_str_new2(mysql_sqlstate(db)),
408
+ query,
409
+ uri);
410
+ rb_exc_raise(exception);
368
411
  }
369
412
 
370
413
  static char * get_uri_option(VALUE query_hash, char * key) {
@@ -373,7 +416,7 @@ static char * get_uri_option(VALUE query_hash, char * key) {
373
416
 
374
417
  if(!rb_obj_is_kind_of(query_hash, rb_cHash)) { return NULL; }
375
418
 
376
- query_value = rb_hash_aref(query_hash, RUBY_STRING(key));
419
+ query_value = rb_hash_aref(query_hash, rb_str_new2(key));
377
420
 
378
421
  if (Qnil != query_value) {
379
422
  value = StringValuePtr(query_value);
@@ -382,6 +425,15 @@ static char * get_uri_option(VALUE query_hash, char * key) {
382
425
  return value;
383
426
  }
384
427
 
428
+ static void assert_file_exists(char * file, char * message) {
429
+ if (file == NULL) { return; }
430
+ if (rb_funcall(rb_cFile, rb_intern("exist?"), 1, rb_str_new2(file)) == Qfalse) {
431
+ rb_raise(eArgumentError, message);
432
+ }
433
+ }
434
+
435
+ static void full_connect(VALUE self, MYSQL *db);
436
+
385
437
  #ifdef _WIN32
386
438
  static MYSQL_RES* cCommand_execute_sync(VALUE self, MYSQL* db, VALUE query) {
387
439
  int retval;
@@ -389,16 +441,14 @@ static MYSQL_RES* cCommand_execute_sync(VALUE self, MYSQL* db, VALUE query) {
389
441
  char* str = RSTRING_PTR(query);
390
442
  int len = RSTRING_LEN(query);
391
443
 
392
- VALUE connection = rb_iv_get(self, "@connection");
393
-
394
444
  if(mysql_ping(db) && mysql_errno(db) == CR_SERVER_GONE_ERROR) {
395
- CHECK_AND_RAISE(mysql_errno(db), "Mysql server has gone away. \
396
- Please report this issue to the Datamapper project. \
397
- Specify your at least your MySQL version when filing a ticket");
445
+ // Ok, we do one more try here by doing a full connect
446
+ VALUE connection = rb_iv_get(self, "@connection");
447
+ full_connect(connection, db);
398
448
  }
399
449
  gettimeofday(&start, NULL);
400
450
  retval = mysql_real_query(db, str, len);
401
- CHECK_AND_RAISE(retval, str);
451
+ CHECK_AND_RAISE(retval, query);
402
452
 
403
453
  data_objects_debug(query, &start);
404
454
 
@@ -413,16 +463,13 @@ static MYSQL_RES* cCommand_execute_async(VALUE self, MYSQL* db, VALUE query) {
413
463
  char* str = RSTRING_PTR(query);
414
464
  int len = RSTRING_LEN(query);
415
465
 
416
- VALUE connection = rb_iv_get(self, "@connection");
417
-
418
- if(mysql_ping(db) && mysql_errno(db) == CR_SERVER_GONE_ERROR) {
419
- CHECK_AND_RAISE(mysql_errno(db), "Mysql server has gone away. \
420
- Please report this issue to the Datamapper project. \
421
- Specify your at least your MySQL version when filing a ticket");
466
+ if((retval = mysql_ping(db)) && mysql_errno(db) == CR_SERVER_GONE_ERROR) {
467
+ VALUE connection = rb_iv_get(self, "@connection");
468
+ full_connect(connection, db);
422
469
  }
423
470
  retval = mysql_send_query(db, str, len);
424
471
 
425
- CHECK_AND_RAISE(retval, str);
472
+ CHECK_AND_RAISE(retval, query);
426
473
  gettimeofday(&start, NULL);
427
474
 
428
475
  socket_fd = db->net.fd;
@@ -447,7 +494,7 @@ static MYSQL_RES* cCommand_execute_async(VALUE self, MYSQL* db, VALUE query) {
447
494
  }
448
495
 
449
496
  retval = mysql_read_query_result(db);
450
- CHECK_AND_RAISE(retval, str);
497
+ CHECK_AND_RAISE(retval, query);
451
498
 
452
499
  data_objects_debug(query, &start);
453
500
 
@@ -455,51 +502,48 @@ static MYSQL_RES* cCommand_execute_async(VALUE self, MYSQL* db, VALUE query) {
455
502
  }
456
503
  #endif
457
504
 
458
- static VALUE cConnection_initialize(VALUE self, VALUE uri) {
505
+
506
+ static void full_connect(VALUE self, MYSQL* db) {
507
+ // Check to see if we're on the db machine. If so, try to use the socket
459
508
  VALUE r_host, r_user, r_password, r_path, r_query, r_port;
460
509
 
461
510
  char *host = "localhost", *user = "root", *password = NULL, *path;
462
511
  char *database = "", *socket = NULL;
463
- char *encoding = NULL;
512
+ VALUE encoding = Qnil;
513
+
514
+ MYSQL *result;
464
515
 
465
516
  int port = 3306;
466
517
  unsigned long client_flags = 0;
467
518
  int encoding_error;
468
519
 
469
- MYSQL *db = 0, *result;
470
- db = (MYSQL *)mysql_init(NULL);
471
-
472
- rb_iv_set(self, "@using_socket", Qfalse);
473
-
474
- r_host = rb_funcall(uri, rb_intern("host"), 0);
475
- if (Qnil != r_host) {
476
- host = StringValuePtr(r_host);
520
+ if((r_host = rb_iv_get(self, "@host")) != Qnil) {
521
+ host = StringValuePtr(r_host);
477
522
  }
478
523
 
479
- r_user = rb_funcall(uri, rb_intern("user"), 0);
480
- if (Qnil != r_user) {
481
- user = StringValuePtr(r_user);
524
+ if((r_user = rb_iv_get(self, "@user")) != Qnil) {
525
+ user = StringValuePtr(r_user);
482
526
  }
483
527
 
484
- r_password = rb_funcall(uri, rb_intern("password"), 0);
485
- if (Qnil != r_password) {
528
+ if((r_password = rb_iv_get(self, "@password")) != Qnil) {
486
529
  password = StringValuePtr(r_password);
487
530
  }
488
531
 
489
- r_path = rb_funcall(uri, rb_intern("path"), 0);
490
- path = StringValuePtr(r_path);
491
- if (Qnil != r_path) {
532
+ if((r_port = rb_iv_get(self, "@port")) != Qnil) {
533
+ port = NUM2INT(r_port);
534
+ }
535
+
536
+ if((r_path = rb_iv_get(self, "@path")) != Qnil) {
537
+ path = StringValuePtr(r_path);
492
538
  database = strtok(path, "/");
493
539
  }
494
540
 
495
541
  if (NULL == database || 0 == strlen(database)) {
496
- rb_raise(eMysqlError, "Database must be specified");
542
+ rb_raise(eConnectionError, "Database must be specified");
497
543
  }
498
544
 
499
- // Pull the querystring off the URI
500
- r_query = rb_funcall(uri, rb_intern("query"), 0);
545
+ r_query = rb_iv_get(self, "@query");
501
546
 
502
- // Check to see if we're on the db machine. If so, try to use the socket
503
547
  if (0 == strcasecmp(host, "localhost")) {
504
548
  socket = get_uri_option(r_query, "socket");
505
549
  if (NULL != socket) {
@@ -507,18 +551,30 @@ static VALUE cConnection_initialize(VALUE self, VALUE uri) {
507
551
  }
508
552
  }
509
553
 
510
- r_port = rb_funcall(uri, rb_intern("port"), 0);
511
- if (Qnil != r_port) {
512
- port = NUM2INT(r_port);
513
- }
554
+ #ifdef HAVE_MYSQL_SSL_SET
555
+ char *ssl_client_key, *ssl_client_cert, *ssl_ca_cert, *ssl_ca_path, *ssl_cipher;
556
+ VALUE r_ssl;
514
557
 
515
- encoding = get_uri_option(r_query, "encoding");
516
- if (!encoding) { encoding = get_uri_option(r_query, "charset"); }
517
- if (!encoding) { encoding = "utf8"; }
558
+ if(rb_obj_is_kind_of(r_query, rb_cHash)) {
559
+ r_ssl = rb_hash_aref(r_query, rb_str_new2("ssl"));
518
560
 
519
- // If ssl? {
520
- // mysql_ssl_set(db, key, cert, ca, capath, cipher)
521
- // }
561
+ if(rb_obj_is_kind_of(r_ssl, rb_cHash)) {
562
+ ssl_client_key = get_uri_option(r_ssl, "client_key");
563
+ ssl_client_cert = get_uri_option(r_ssl, "client_cert");
564
+ ssl_ca_cert = get_uri_option(r_ssl, "ca_cert");
565
+ ssl_ca_path = get_uri_option(r_ssl, "ca_path");
566
+ ssl_cipher = get_uri_option(r_ssl, "cipher");
567
+
568
+ assert_file_exists(ssl_client_key, "client_key doesn't exist");
569
+ assert_file_exists(ssl_client_cert, "client_cert doesn't exist");
570
+ assert_file_exists(ssl_ca_cert, "ca_cert doesn't exist");
571
+
572
+ mysql_ssl_set(db, ssl_client_key, ssl_client_cert, ssl_ca_cert, ssl_ca_path, ssl_cipher);
573
+ } else if(r_ssl != Qnil) {
574
+ rb_raise(eArgumentError, "ssl must be passed a hash");
575
+ }
576
+ }
577
+ #endif
522
578
 
523
579
  result = (MYSQL *)mysql_real_connect(
524
580
  db,
@@ -532,8 +588,16 @@ static VALUE cConnection_initialize(VALUE self, VALUE uri) {
532
588
  );
533
589
 
534
590
  if (NULL == result) {
535
- raise_mysql_error(Qnil, db, -1, NULL);
591
+ raise_error(self, db, Qnil);
592
+ }
593
+
594
+ #ifdef HAVE_MYSQL_SSL_SET
595
+ const char *ssl_cipher_used = mysql_get_ssl_cipher(db);
596
+
597
+ if (NULL != ssl_cipher_used) {
598
+ rb_iv_set(self, "@ssl_cipher", rb_str_new2(ssl_cipher_used));
536
599
  }
600
+ #endif
537
601
 
538
602
  #ifdef MYSQL_OPT_RECONNECT
539
603
  my_bool reconnect = 1;
@@ -541,41 +605,110 @@ static VALUE cConnection_initialize(VALUE self, VALUE uri) {
541
605
  #endif
542
606
 
543
607
  // Set the connections character set
544
- encoding_error = mysql_set_character_set(db, encoding);
545
- if (0 != encoding_error) {
546
- raise_mysql_error(Qnil, db, encoding_error, NULL);
608
+ encoding = rb_iv_get(self, "@encoding");
609
+
610
+ VALUE my_encoding = rb_hash_aref(CONST_GET(mEncoding, "MAP"), encoding);
611
+ if(my_encoding != Qnil) {
612
+ encoding_error = mysql_set_character_set(db, RSTRING_PTR(my_encoding));
613
+ if (0 != encoding_error) {
614
+ raise_error(self, db, Qnil);
615
+ } else {
616
+ #ifdef HAVE_RUBY_ENCODING_H
617
+ rb_iv_set(self, "@encoding_id", INT2FIX(rb_enc_find_index(RSTRING_PTR(encoding))));
618
+ #endif
619
+ rb_iv_set(self, "@my_encoding", my_encoding);
620
+ }
621
+ } else {
622
+ rb_warn("Encoding %s is not a known Ruby encoding for MySQL\n", RSTRING_PTR(encoding));
623
+ rb_iv_set(self, "@encoding", rb_str_new2("UTF-8"));
624
+ #ifdef HAVE_RUBY_ENCODING_H
625
+ rb_iv_set(self, "@encoding_id", INT2FIX(rb_enc_find_index("UTF-8")));
626
+ #endif
627
+ rb_iv_set(self, "@my_encoding", rb_str_new2("utf8"));
547
628
  }
548
629
 
549
630
  // Disable sql_auto_is_null
550
631
  cCommand_execute(self, db, rb_str_new2("SET sql_auto_is_null = 0"));
551
- cCommand_execute(self, db, rb_str_new2("SET SESSION sql_mode = 'ANSI,NO_AUTO_VALUE_ON_ZERO,NO_DIR_IN_CREATE,NO_ENGINE_SUBSTITUTION,NO_UNSIGNED_SUBTRACTION,TRADITIONAL'"));
632
+ // removed NO_AUTO_VALUE_ON_ZERO because of MySQL bug http://bugs.mysql.com/bug.php?id=42270
633
+ // added NO_BACKSLASH_ESCAPES so that backslashes should not be escaped as in other databases
634
+ cCommand_execute(self, db, rb_str_new2("SET SESSION sql_mode = 'ANSI,NO_BACKSLASH_ESCAPES,NO_DIR_IN_CREATE,NO_ENGINE_SUBSTITUTION,NO_UNSIGNED_SUBTRACTION,TRADITIONAL'"));
552
635
 
553
- rb_iv_set(self, "@uri", uri);
554
636
  rb_iv_set(self, "@connection", Data_Wrap_Struct(rb_cObject, 0, 0, db));
555
-
556
- return Qtrue;
557
637
  }
558
638
 
559
- static VALUE cConnection_character_set(VALUE self) {
560
- VALUE connection_container = rb_iv_get(self, "@connection");
561
- MYSQL *db;
639
+ static VALUE cConnection_initialize(VALUE self, VALUE uri) {
640
+ VALUE r_host, r_user, r_password, r_path, r_query, r_port;
562
641
 
563
- const char *encoding;
642
+ MYSQL *db = 0;
643
+ db = (MYSQL *)mysql_init(NULL);
564
644
 
565
- if (Qnil == connection_container)
566
- return Qfalse;
645
+ rb_iv_set(self, "@using_socket", Qfalse);
646
+ rb_iv_set(self, "@ssl_cipher", Qnil);
567
647
 
568
- db = DATA_PTR(connection_container);
648
+ r_host = rb_funcall(uri, rb_intern("host"), 0);
649
+ if (Qnil != r_host) {
650
+ rb_iv_set(self, "@host", r_host);
651
+ }
652
+
653
+ r_user = rb_funcall(uri, rb_intern("user"), 0);
654
+ if (Qnil != r_user) {
655
+ rb_iv_set(self, "@user", r_user);
656
+ }
657
+
658
+ r_password = rb_funcall(uri, rb_intern("password"), 0);
659
+ if (Qnil != r_password) {
660
+ rb_iv_set(self, "@password", r_password);
661
+ }
662
+
663
+ r_path = rb_funcall(uri, rb_intern("path"), 0);
664
+ if (Qnil != r_path) {
665
+ rb_iv_set(self, "@path", r_path);
666
+ }
667
+
668
+ r_port = rb_funcall(uri, rb_intern("port"), 0);
669
+ if (Qnil != r_port) {
670
+ rb_iv_set(self, "@port", r_port);
671
+ }
672
+
673
+ // Pull the querystring off the URI
674
+ r_query = rb_funcall(uri, rb_intern("query"), 0);
675
+ rb_iv_set(self, "@query", r_query);
676
+
677
+ const char* encoding = get_uri_option(r_query, "encoding");
678
+ if (!encoding) { encoding = get_uri_option(r_query, "charset"); }
679
+ if (!encoding) { encoding = "UTF-8"; }
569
680
 
570
- encoding = mysql_character_set_name(db);
681
+ rb_iv_set(self, "@encoding", rb_str_new2(encoding));
571
682
 
572
- return RUBY_STRING(encoding);
683
+ full_connect(self, db);
684
+
685
+ rb_iv_set(self, "@uri", uri);
686
+
687
+ return Qtrue;
688
+ }
689
+
690
+ static VALUE cConnection_character_set(VALUE self) {
691
+ return rb_iv_get(self, "@encoding");
573
692
  }
574
693
 
575
694
  static VALUE cConnection_is_using_socket(VALUE self) {
576
695
  return rb_iv_get(self, "@using_socket");
577
696
  }
578
697
 
698
+ static VALUE cConnection_ssl_cipher(VALUE self) {
699
+ return rb_iv_get(self, "@ssl_cipher");
700
+ }
701
+
702
+ static VALUE cConnection_secure(VALUE self) {
703
+ VALUE blank_cipher = rb_funcall(rb_iv_get(self, "@ssl_cipher"), rb_intern("blank?"), 0);
704
+
705
+ if (blank_cipher == Qtrue) {
706
+ return Qfalse;
707
+ } else {
708
+ return Qtrue;
709
+ }
710
+ }
711
+
579
712
  static VALUE cConnection_dispose(VALUE self) {
580
713
  VALUE connection_container = rb_iv_get(self, "@connection");
581
714
 
@@ -633,18 +766,18 @@ static VALUE cCommand_set_types(int argc, VALUE *argv, VALUE self) {
633
766
  }
634
767
 
635
768
  VALUE cConnection_quote_time(VALUE self, VALUE value) {
636
- return rb_funcall(value, ID_STRFTIME, 1, RUBY_STRING("'%Y-%m-%d %H:%M:%S'"));
769
+ return rb_funcall(value, ID_STRFTIME, 1, rb_str_new2("'%Y-%m-%d %H:%M:%S'"));
637
770
  }
638
771
 
639
772
 
640
773
  VALUE cConnection_quote_date_time(VALUE self, VALUE value) {
641
774
  // TODO: Support non-local dates. we need to call #new_offset on the date to be
642
775
  // quoted and pass in the current locale's date offset (self.new_offset((hours * 3600).to_r / 86400)
643
- return rb_funcall(value, ID_STRFTIME, 1, RUBY_STRING("'%Y-%m-%d %H:%M:%S'"));
776
+ return rb_funcall(value, ID_STRFTIME, 1, rb_str_new2("'%Y-%m-%d %H:%M:%S'"));
644
777
  }
645
778
 
646
779
  VALUE cConnection_quote_date(VALUE self, VALUE value) {
647
- return rb_funcall(value, ID_STRFTIME, 1, RUBY_STRING("'%Y-%m-%d'"));
780
+ return rb_funcall(value, ID_STRFTIME, 1, rb_str_new2("'%Y-%m-%d'"));
648
781
  }
649
782
 
650
783
  static VALUE cConnection_quote_string(VALUE self, VALUE string) {
@@ -666,7 +799,8 @@ static VALUE cConnection_quote_string(VALUE self, VALUE string) {
666
799
 
667
800
  // Wrap the escaped string in single-quotes, this is DO's convention
668
801
  escaped[0] = escaped[quoted_length + 1] = '\'';
669
- result = rb_str_new(escaped, quoted_length + 2);
802
+ result = DO_STR_NEW(escaped, quoted_length + 2, FIX2INT(rb_iv_get(self, "@encoding_id")));
803
+
670
804
  free(escaped);
671
805
  return result;
672
806
  }
@@ -693,7 +827,7 @@ static VALUE cCommand_execute_non_query(int argc, VALUE *argv, VALUE self) {
693
827
  VALUE connection = rb_iv_get(self, "@connection");
694
828
  VALUE mysql_connection = rb_iv_get(connection, "@connection");
695
829
  if (Qnil == mysql_connection) {
696
- rb_raise(eMysqlError, "This connection has already been closed.");
830
+ rb_raise(eConnectionError, "This connection has already been closed.");
697
831
  }
698
832
 
699
833
  MYSQL *db = DATA_PTR(mysql_connection);
@@ -721,7 +855,7 @@ static VALUE cCommand_execute_reader(int argc, VALUE *argv, VALUE self) {
721
855
  VALUE connection = rb_iv_get(self, "@connection");
722
856
  VALUE mysql_connection = rb_iv_get(connection, "@connection");
723
857
  if (Qnil == mysql_connection) {
724
- rb_raise(eMysqlError, "This connection has already been closed.");
858
+ rb_raise(eConnectionError, "This connection has already been closed.");
725
859
  }
726
860
 
727
861
  MYSQL *db = DATA_PTR(mysql_connection);
@@ -740,8 +874,9 @@ static VALUE cCommand_execute_reader(int argc, VALUE *argv, VALUE self) {
740
874
  field_count = mysql_field_count(db);
741
875
 
742
876
  reader = rb_funcall(cReader, ID_NEW, 0);
877
+ rb_iv_set(reader, "@connection", connection);
743
878
  rb_iv_set(reader, "@reader", Data_Wrap_Struct(rb_cObject, 0, 0, response));
744
- rb_iv_set(reader, "@opened", Qtrue);
879
+ rb_iv_set(reader, "@opened", Qfalse);
745
880
  rb_iv_set(reader, "@field_count", INT2NUM(field_count));
746
881
 
747
882
  field_names = rb_ary_new();
@@ -759,7 +894,7 @@ static VALUE cCommand_execute_reader(int argc, VALUE *argv, VALUE self) {
759
894
 
760
895
  for(i = 0; i < field_count; i++) {
761
896
  field = mysql_fetch_field_direct(response, i);
762
- rb_ary_push(field_names, RUBY_STRING(field->name));
897
+ rb_ary_push(field_names, rb_str_new2(field->name));
763
898
 
764
899
  if (1 == guess_default_field_types) {
765
900
  rb_ary_push(field_types, infer_ruby_type(field));
@@ -795,6 +930,7 @@ static VALUE cReader_close(VALUE self) {
795
930
 
796
931
  mysql_free_result(reader);
797
932
  rb_iv_set(self, "@reader", Qnil);
933
+ rb_iv_set(self, "@opened", Qfalse);
798
934
 
799
935
  return Qtrue;
800
936
  }
@@ -823,16 +959,24 @@ static VALUE cReader_next(VALUE self) {
823
959
  result = mysql_fetch_row(reader);
824
960
  lengths = mysql_fetch_lengths(reader);
825
961
 
826
- rb_iv_set(self, "@state", result ? Qtrue : Qfalse);
962
+ rb_iv_set(self, "@opened", result ? Qtrue : Qfalse);
827
963
 
828
964
  if (!result) {
829
965
  return Qfalse;
830
966
  }
831
967
 
968
+ int enc = -1;
969
+ #ifdef HAVE_RUBY_ENCODING_H
970
+ VALUE encoding_id = rb_iv_get(rb_iv_get(self, "@connection"), "@encoding_id");
971
+ if (encoding_id != Qnil) {
972
+ enc = FIX2INT(encoding_id);
973
+ }
974
+ #endif
975
+
832
976
  for (i = 0; i < reader->field_count; i++) {
833
977
  // The field_type data could be cached in a c-array
834
978
  field_type = rb_ary_entry(field_types, i);
835
- rb_ary_push(row, typecast(result[i], lengths[i], field_type));
979
+ rb_ary_push(row, typecast(result[i], lengths[i], field_type, enc));
836
980
  }
837
981
 
838
982
  rb_iv_set(self, "@values", row);
@@ -841,9 +985,9 @@ static VALUE cReader_next(VALUE self) {
841
985
  }
842
986
 
843
987
  static VALUE cReader_values(VALUE self) {
844
- VALUE state = rb_iv_get(self, "@state");
988
+ VALUE state = rb_iv_get(self, "@opened");
845
989
  if ( state == Qnil || state == Qfalse ) {
846
- rb_raise(eMysqlError, "Reader is not initialized");
990
+ rb_raise(eDataError, "Reader is not initialized");
847
991
  }
848
992
  else {
849
993
  return rb_iv_get(self, "@values");
@@ -858,15 +1002,11 @@ static VALUE cReader_field_count(VALUE self) {
858
1002
  return rb_iv_get(self, "@field_count");
859
1003
  }
860
1004
 
861
- static VALUE cReader_row_count(VALUE self) {
862
- return rb_iv_get(self, "@row_count");
863
- }
864
-
865
1005
  void Init_do_mysql_ext() {
866
1006
  rb_require("bigdecimal");
867
1007
  rb_require("date");
868
1008
 
869
- rb_funcall(rb_mKernel, rb_intern("require"), 1, RUBY_STRING("data_objects"));
1009
+ rb_funcall(rb_mKernel, rb_intern("require"), 1, rb_str_new2("data_objects"));
870
1010
 
871
1011
  ID_TO_I = rb_intern("to_i");
872
1012
  ID_TO_F = rb_intern("to_f");
@@ -908,11 +1048,15 @@ void Init_do_mysql_ext() {
908
1048
  mDOMysql = rb_define_module_under(mDO, "Mysql");
909
1049
 
910
1050
  eArgumentError = CONST_GET(rb_mKernel, "ArgumentError");
911
- eMysqlError = rb_define_class("MysqlError", rb_eStandardError);
1051
+ eConnectionError = CONST_GET(mDO, "ConnectionError");
1052
+ eDataError = CONST_GET(mDO, "DataError");
1053
+ mEncoding = rb_define_module_under(mDOMysql, "Encoding");
912
1054
 
913
1055
  cConnection = DRIVER_CLASS("Connection", cDO_Connection);
914
1056
  rb_define_method(cConnection, "initialize", cConnection_initialize, 1);
915
1057
  rb_define_method(cConnection, "using_socket?", cConnection_is_using_socket, 0);
1058
+ rb_define_method(cConnection, "ssl_cipher", cConnection_ssl_cipher, 0);
1059
+ rb_define_method(cConnection, "secure?", cConnection_secure, 0);
916
1060
  rb_define_method(cConnection, "character_set", cConnection_character_set , 0);
917
1061
  rb_define_method(cConnection, "dispose", cConnection_dispose, 0);
918
1062
  rb_define_method(cConnection, "quote_string", cConnection_quote_string, 1);
@@ -935,5 +1079,10 @@ void Init_do_mysql_ext() {
935
1079
  rb_define_method(cReader, "values", cReader_values, 0);
936
1080
  rb_define_method(cReader, "fields", cReader_fields, 0);
937
1081
  rb_define_method(cReader, "field_count", cReader_field_count, 0);
938
- rb_define_method(cReader, "row_count", cReader_row_count, 0);
1082
+
1083
+ struct errcodes *errs;
1084
+
1085
+ for (errs = errors; errs->error_name; errs++) {
1086
+ rb_const_set(mDOMysql, rb_intern(errs->error_name), INT2NUM(errs->error_no));
1087
+ }
939
1088
  }