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 +17 -0
- data/Manifest.txt +2 -2
- data/{README.txt → README.markdown} +2 -1
- data/Rakefile +3 -3
- data/ext/do_mysql_ext/do_mysql_ext.c +255 -106
- data/ext/do_mysql_ext/error.h +527 -0
- data/ext/do_mysql_ext/extconf.rb +1 -6
- data/lib/do_mysql.rb +20 -17
- data/lib/do_mysql/encoding.rb +38 -0
- data/lib/do_mysql/transaction.rb +9 -13
- data/lib/do_mysql/version.rb +1 -1
- data/lib/do_mysql_ext.so +0 -0
- data/spec/connection_spec.rb +43 -1
- data/spec/result_spec.rb +7 -0
- data/spec/spec_helper.rb +107 -11
- data/tasks/gem.rake +1 -53
- data/tasks/release.rake +7 -7
- data/tasks/retrieve.rake +1 -1
- data/tasks/spec.rake +1 -0
- data/tasks/ssl.rake +29 -0
- metadata +13 -10
- data/History.txt +0 -9
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
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 =
|
12
|
-
BINARY_VERSION = '5.0.
|
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,
|
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(
|
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
|
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,
|
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,
|
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,
|
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
|
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
|
-
|
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
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
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,
|
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
|
-
|
396
|
-
|
397
|
-
|
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,
|
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
|
-
|
417
|
-
|
418
|
-
|
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,
|
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,
|
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
|
-
|
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
|
-
|
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
|
-
|
470
|
-
|
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 =
|
480
|
-
|
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 =
|
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
|
-
|
490
|
-
|
491
|
-
|
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(
|
542
|
+
rb_raise(eConnectionError, "Database must be specified");
|
497
543
|
}
|
498
544
|
|
499
|
-
|
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
|
-
|
511
|
-
|
512
|
-
|
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
|
-
|
516
|
-
|
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
|
-
|
520
|
-
|
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
|
-
|
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
|
-
|
545
|
-
|
546
|
-
|
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
|
-
|
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
|
560
|
-
VALUE
|
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
|
-
|
642
|
+
MYSQL *db = 0;
|
643
|
+
db = (MYSQL *)mysql_init(NULL);
|
564
644
|
|
565
|
-
|
566
|
-
|
645
|
+
rb_iv_set(self, "@using_socket", Qfalse);
|
646
|
+
rb_iv_set(self, "@ssl_cipher", Qnil);
|
567
647
|
|
568
|
-
|
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
|
681
|
+
rb_iv_set(self, "@encoding", rb_str_new2(encoding));
|
571
682
|
|
572
|
-
|
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,
|
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,
|
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,
|
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 =
|
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(
|
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(
|
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",
|
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,
|
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, "@
|
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, "@
|
988
|
+
VALUE state = rb_iv_get(self, "@opened");
|
845
989
|
if ( state == Qnil || state == Qfalse ) {
|
846
|
-
rb_raise(
|
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,
|
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
|
-
|
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
|
-
|
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
|
}
|