do_mysql 0.9.12 → 0.10.0

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