mysql2 0.4.10 → 0.5.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +66 -32
- data/ext/mysql2/client.c +125 -59
- data/ext/mysql2/client.h +1 -39
- data/ext/mysql2/extconf.rb +24 -21
- data/ext/mysql2/mysql2_ext.c +2 -1
- data/ext/mysql2/mysql2_ext.h +8 -4
- data/ext/mysql2/mysql_enc_name_to_ruby.h +60 -56
- data/ext/mysql2/mysql_enc_to_ruby.h +64 -3
- data/ext/mysql2/result.c +32 -85
- data/ext/mysql2/result.h +2 -3
- data/ext/mysql2/statement.c +81 -72
- data/ext/mysql2/statement.h +0 -2
- data/ext/mysql2/wait_for_single_fd.h +2 -1
- data/lib/mysql2.rb +17 -15
- data/lib/mysql2/client.rb +33 -27
- data/lib/mysql2/em.rb +2 -4
- data/lib/mysql2/error.rb +51 -22
- data/lib/mysql2/result.rb +2 -0
- data/lib/mysql2/statement.rb +3 -9
- data/lib/mysql2/version.rb +1 -1
- data/support/5072E1F5.asc +5 -5
- data/support/mysql_enc_to_ruby.rb +8 -3
- data/support/ruby_enc_to_mysql.rb +7 -5
- metadata +8 -58
- data/examples/eventmachine.rb +0 -21
- data/examples/threaded.rb +0 -18
- data/spec/configuration.yml.example +0 -11
- data/spec/em/em_spec.rb +0 -136
- data/spec/my.cnf.example +0 -9
- data/spec/mysql2/client_spec.rb +0 -1039
- data/spec/mysql2/error_spec.rb +0 -82
- data/spec/mysql2/result_spec.rb +0 -545
- data/spec/mysql2/statement_spec.rb +0 -776
- data/spec/rcov.opts +0 -3
- data/spec/spec_helper.rb +0 -108
- data/spec/ssl/ca-cert.pem +0 -17
- data/spec/ssl/ca-key.pem +0 -27
- data/spec/ssl/ca.cnf +0 -22
- data/spec/ssl/cert.cnf +0 -22
- data/spec/ssl/client-cert.pem +0 -17
- data/spec/ssl/client-key.pem +0 -27
- data/spec/ssl/client-req.pem +0 -15
- data/spec/ssl/gen_certs.sh +0 -48
- data/spec/ssl/pkcs8-client-key.pem +0 -28
- data/spec/ssl/pkcs8-server-key.pem +0 -28
- data/spec/ssl/server-cert.pem +0 -17
- data/spec/ssl/server-key.pem +0 -27
- data/spec/ssl/server-req.pem +0 -15
- data/spec/test_data +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8be4e0f4afbea38c5460544e39c9e0d987dd040c9de5ebdbc4c1e200102ca8e4
|
4
|
+
data.tar.gz: 996e05358297b03bf8f06abffd37d83a590912246ec607d2c3ee53b325c43022
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: daf37441bcb29366453963529b5a144df0d599b79b7a0b9d90b2ae5ed3dee97c1945a58111d6fe6bc2f1c20f75c9960c3cc1cd988a0e5d1be5ce44b7dcdf3633
|
7
|
+
data.tar.gz: 421df08c45f4257c2f04f3dc0a0e1c1557c695598c4e1a80236d618d1a79510459b8919b753ad9af2d46d21fa19ba060d5b53da2f54a00ff90ca45a4534c9108
|
data/README.md
CHANGED
@@ -7,7 +7,7 @@ The Mysql2 gem is meant to serve the extremely common use-case of connecting, qu
|
|
7
7
|
Some database libraries out there serve as direct 1:1 mappings of the already complex C APIs available.
|
8
8
|
This one is not.
|
9
9
|
|
10
|
-
It also forces the use of UTF-8 [or binary] for the connection
|
10
|
+
It also forces the use of UTF-8 [or binary] for the connection and uses encoding-aware MySQL API calls where it can.
|
11
11
|
|
12
12
|
The API consists of three classes:
|
13
13
|
|
@@ -18,16 +18,18 @@ The API consists of three classes:
|
|
18
18
|
`Mysql2::Statement` - returned from issuing a #prepare on the connection. Execute the statement to get a Result.
|
19
19
|
|
20
20
|
## Installing
|
21
|
+
|
21
22
|
### General Instructions
|
23
|
+
|
22
24
|
``` sh
|
23
25
|
gem install mysql2
|
24
26
|
```
|
25
27
|
|
26
28
|
This gem links against MySQL's `libmysqlclient` library or `Connector/C`
|
27
29
|
library, and compatible alternatives such as MariaDB.
|
28
|
-
You may need to install a package such as `
|
29
|
-
or other appropriate package for your system. See below for
|
30
|
-
instructions.
|
30
|
+
You may need to install a package such as `libmariadb-dev`, `libmysqlclient-dev`,
|
31
|
+
`mysql-devel`, or other appropriate package for your system. See below for
|
32
|
+
system-specific instructions.
|
31
33
|
|
32
34
|
By default, the mysql2 gem will try to find a copy of MySQL in this order:
|
33
35
|
|
@@ -74,10 +76,11 @@ To see line numbers in backtraces, declare these environment variables
|
|
74
76
|
|
75
77
|
### Linux and other Unixes
|
76
78
|
|
77
|
-
You may need to install a package such as `
|
78
|
-
refer to your distribution's package guide to
|
79
|
-
The most common issue we see is a user who has
|
80
|
-
|
79
|
+
You may need to install a package such as `libmariadb-dev`, `libmysqlclient-dev`,
|
80
|
+
`mysql-devel`, or `default-libmysqlclient-dev`; refer to your distribution's package guide to
|
81
|
+
find the particular package. The most common issue we see is a user who has
|
82
|
+
the library file `libmysqlclient.so` but is missing the header file `mysql.h`
|
83
|
+
-- double check that you have the _-dev_ packages installed.
|
81
84
|
|
82
85
|
### Mac OS X
|
83
86
|
|
@@ -89,6 +92,7 @@ If you have not done so already, you will need to install the XCode select tools
|
|
89
92
|
`xcode-select --install`.
|
90
93
|
|
91
94
|
### Windows
|
95
|
+
|
92
96
|
Make sure that you have Ruby and the DevKit compilers installed. We recommend
|
93
97
|
the [Ruby Installer](http://rubyinstaller.org) distribution.
|
94
98
|
|
@@ -138,7 +142,7 @@ results.each do |row|
|
|
138
142
|
# conveniently, row is a hash
|
139
143
|
# the keys are the fields, as you'd expect
|
140
144
|
# the values are pre-built ruby primitives mapped from their corresponding field types in MySQL
|
141
|
-
puts row["id"] # row["id"].
|
145
|
+
puts row["id"] # row["id"].is_a? Integer
|
142
146
|
if row["dne"] # non-existant hash entry is nil
|
143
147
|
puts row["dne"]
|
144
148
|
end
|
@@ -156,7 +160,7 @@ end
|
|
156
160
|
How about with symbolized keys?
|
157
161
|
|
158
162
|
``` ruby
|
159
|
-
client.query("SELECT * FROM users WHERE group='githubbers'", :symbolize_keys => true) do |row|
|
163
|
+
client.query("SELECT * FROM users WHERE group='githubbers'", :symbolize_keys => true).each do |row|
|
160
164
|
# do something with row, it's ready to rock
|
161
165
|
end
|
162
166
|
```
|
@@ -175,7 +179,11 @@ end
|
|
175
179
|
Prepared statements are supported, as well. In a prepared statement, use a `?`
|
176
180
|
in place of each value and then execute the statement to retrieve a result set.
|
177
181
|
Pass your arguments to the execute method in the same number and order as the
|
178
|
-
question marks in the statement.
|
182
|
+
question marks in the statement. Query options can be passed as keyword arguments
|
183
|
+
to the execute method.
|
184
|
+
|
185
|
+
Be sure to read about the known limitations of prepared statements at
|
186
|
+
[https://dev.mysql.com/doc/refman/5.6/en/c-api-prepared-statement-problems.html](https://dev.mysql.com/doc/refman/5.6/en/c-api-prepared-statement-problems.html)
|
179
187
|
|
180
188
|
``` ruby
|
181
189
|
statement = @client.prepare("SELECT * FROM users WHERE login_count = ?")
|
@@ -184,6 +192,9 @@ result2 = statement.execute(2)
|
|
184
192
|
|
185
193
|
statement = @client.prepare("SELECT * FROM users WHERE last_login >= ? AND location LIKE ?")
|
186
194
|
result = statement.execute(1, "CA")
|
195
|
+
|
196
|
+
statement = @client.prepare("SELECT * FROM users WHERE last_login >= ? AND location LIKE ?")
|
197
|
+
result = statement.execute(1, "CA", :as => :array)
|
187
198
|
```
|
188
199
|
|
189
200
|
## Connection options
|
@@ -203,12 +214,14 @@ Mysql2::Client.new(
|
|
203
214
|
:read_timeout = seconds,
|
204
215
|
:write_timeout = seconds,
|
205
216
|
:connect_timeout = seconds,
|
217
|
+
:connect_attrs = {:program_name => $PROGRAM_NAME, ...},
|
206
218
|
:reconnect = true/false,
|
207
219
|
:local_infile = true/false,
|
208
220
|
:secure_auth = true/false,
|
209
221
|
:ssl_mode = :disabled / :preferred / :required / :verify_ca / :verify_identity,
|
210
222
|
:default_file = '/path/to/my.cfg',
|
211
223
|
:default_group = 'my.cfg section',
|
224
|
+
:default_auth = 'authentication_windows_client'
|
212
225
|
:init_command => sql
|
213
226
|
)
|
214
227
|
```
|
@@ -265,8 +278,10 @@ The string form will be split on whitespace and parsed as with the array form:
|
|
265
278
|
Plain flags are added to the default flags, while flags prefixed with `-`
|
266
279
|
(minus) are removed from the default flags.
|
267
280
|
|
268
|
-
|
269
|
-
|
281
|
+
### Using Active Record's database.yml
|
282
|
+
|
283
|
+
Active Record typically reads its configuration from a file named `database.yml` or an environment variable `DATABASE_URL`.
|
284
|
+
Use the value `mysql2` as the adapter name. For example:
|
270
285
|
|
271
286
|
``` yaml
|
272
287
|
development:
|
@@ -284,6 +299,15 @@ development:
|
|
284
299
|
secure_auth: false
|
285
300
|
```
|
286
301
|
|
302
|
+
### Using Active Record's DATABASE_URL
|
303
|
+
|
304
|
+
Active Record typically reads its configuration from a file named `database.yml` or an environment variable `DATABASE_URL`.
|
305
|
+
Use the value `mysql2` as the protocol name. For example:
|
306
|
+
|
307
|
+
``` shell
|
308
|
+
DATABASE_URL=mysql2://sql_user:sql_pass@sql_host_name:port/sql_db_name?option1=value1&option2=value2
|
309
|
+
```
|
310
|
+
|
287
311
|
### Reading a MySQL config file
|
288
312
|
|
289
313
|
You may read configuration options from a MySQL configuration file by passing
|
@@ -338,7 +362,8 @@ end
|
|
338
362
|
```
|
339
363
|
|
340
364
|
Yields:
|
341
|
-
|
365
|
+
|
366
|
+
```ruby
|
342
367
|
{"1"=>1}
|
343
368
|
{"2"=>2}
|
344
369
|
next_result: Unknown column 'A' in 'field list' (Mysql2::Error)
|
@@ -381,6 +406,15 @@ c = Mysql2::Client.new
|
|
381
406
|
c.query(sql, :symbolize_keys => true)
|
382
407
|
```
|
383
408
|
|
409
|
+
or
|
410
|
+
|
411
|
+
``` ruby
|
412
|
+
# this will set the options for the Mysql2::Result instance returned from the #execute method
|
413
|
+
c = Mysql2::Client.new
|
414
|
+
s = c.prepare(sql)
|
415
|
+
s.execute(arg1, args2, :symbolize_keys => true)
|
416
|
+
```
|
417
|
+
|
384
418
|
## Result types
|
385
419
|
|
386
420
|
### Array of Arrays
|
@@ -488,7 +522,7 @@ There are a few things that need to be kept in mind while using streaming:
|
|
488
522
|
* `:cache_rows` is ignored currently. (if you want to use `:cache_rows` you probably don't want to be using `:stream`)
|
489
523
|
* You must fetch all rows in the result set of your query before you can make new queries. (i.e. with `Mysql2::Result#each`)
|
490
524
|
|
491
|
-
Read more about the consequences of using `mysql_use_result` (what streaming is implemented with) here: http://dev.mysql.com/doc/refman/5.0/en/mysql-use-result.html.
|
525
|
+
Read more about the consequences of using `mysql_use_result` (what streaming is implemented with) here: [http://dev.mysql.com/doc/refman/5.0/en/mysql-use-result.html](http://dev.mysql.com/doc/refman/5.0/en/mysql-use-result.html).
|
492
526
|
|
493
527
|
### Lazy Everything
|
494
528
|
|
@@ -509,21 +543,21 @@ As for field values themselves, I'm workin on it - but expect that soon.
|
|
509
543
|
|
510
544
|
This gem is tested with the following Ruby versions on Linux and Mac OS X:
|
511
545
|
|
512
|
-
|
513
|
-
|
514
|
-
* Rubinius 2.x and 3.x do work but may fail under some workloads
|
546
|
+
* Ruby MRI 2.0.0, 2.1.x, 2.2.x, 2.3.x, 2.4.x, 2.5.x, 2.6.x
|
547
|
+
* Rubinius 2.x and 3.x do work but may fail under some workloads
|
515
548
|
|
516
549
|
This gem is tested with the following MySQL and MariaDB versions:
|
517
550
|
|
518
|
-
|
519
|
-
|
520
|
-
|
551
|
+
* MySQL 5.5, 5.6, 5.7, 8.0
|
552
|
+
* MySQL Connector/C 6.0 and 6.1 (primarily on Windows)
|
553
|
+
* MariaDB 5.5, 10.0, 10.1, 10.2, 10.3
|
521
554
|
|
522
555
|
### Ruby on Rails / Active Record
|
523
556
|
|
524
|
-
|
525
|
-
|
526
|
-
|
557
|
+
* mysql2 0.5.x works with Rails / Active Record 5.0.7, 5.1.6, and higher.
|
558
|
+
* mysql2 0.4.x works with Rails / Active Record 4.2.5 - 5.0 and higher.
|
559
|
+
* mysql2 0.3.x works with Rails / Active Record 3.1, 3.2, 4.x, 5.0.
|
560
|
+
* mysql2 0.2.x works with Rails / Active Record 2.3 - 3.0.
|
527
561
|
|
528
562
|
### Asynchronous Active Record
|
529
563
|
|
@@ -606,11 +640,11 @@ though.
|
|
606
640
|
## Special Thanks
|
607
641
|
|
608
642
|
* Eric Wong - for the contribution (and the informative explanations) of some thread-safety, non-blocking I/O and cleanup patches. You rock dude
|
609
|
-
* Yury Korolev
|
610
|
-
* Aaron Patterson
|
611
|
-
* Mike Perham
|
612
|
-
* Aaron Stone
|
613
|
-
* Kouhei Ueno
|
614
|
-
* John Cant
|
615
|
-
* Justin Case
|
616
|
-
* Tamir Duberstein
|
643
|
+
* [Yury Korolev](http://github.com/yury) - for TONS of help testing the Active Record adapter
|
644
|
+
* [Aaron Patterson](http://github.com/tenderlove) - tons of contributions, suggestions and general badassness
|
645
|
+
* [Mike Perham](http://github.com/mperham) - Async Active Record adapter (uses Fibers and EventMachine)
|
646
|
+
* [Aaron Stone](http://github.com/sodabrew) - additional client settings, local files, microsecond time, maintenance support
|
647
|
+
* [Kouhei Ueno](https://github.com/nyaxt) - for the original work on Prepared Statements way back in 2012
|
648
|
+
* [John Cant](http://github.com/johncant) - polishing and updating Prepared Statements support
|
649
|
+
* [Justin Case](http://github.com/justincase) - polishing and updating Prepared Statements support and getting it merged
|
650
|
+
* [Tamir Duberstein](http://github.com/tamird) - for help with timeouts and all around updates and cleanups
|
data/ext/mysql2/client.c
CHANGED
@@ -15,15 +15,11 @@
|
|
15
15
|
#include "mysql_enc_name_to_ruby.h"
|
16
16
|
|
17
17
|
VALUE cMysql2Client;
|
18
|
-
extern VALUE mMysql2, cMysql2Error;
|
18
|
+
extern VALUE mMysql2, cMysql2Error, cMysql2TimeoutError;
|
19
19
|
static VALUE sym_id, sym_version, sym_header_version, sym_async, sym_symbolize_keys, sym_as, sym_array, sym_stream;
|
20
|
-
static
|
21
|
-
|
22
|
-
|
23
|
-
VALUE rb_hash_dup(VALUE other) {
|
24
|
-
return rb_funcall(rb_cHash, intern_brackets, 1, other);
|
25
|
-
}
|
26
|
-
#endif
|
20
|
+
static VALUE sym_no_good_index_used, sym_no_index_used, sym_query_was_slow;
|
21
|
+
static ID intern_brackets, intern_merge, intern_merge_bang, intern_new_with_args,
|
22
|
+
intern_current_query_options, intern_read_timeout;
|
27
23
|
|
28
24
|
#define REQUIRE_INITIALIZED(wrapper) \
|
29
25
|
if (!wrapper->initialized) { \
|
@@ -117,15 +113,19 @@ static VALUE rb_set_ssl_mode_option(VALUE self, VALUE setting) {
|
|
117
113
|
#ifdef HAVE_CONST_MYSQL_OPT_SSL_ENFORCE
|
118
114
|
GET_CLIENT(self);
|
119
115
|
int val = NUM2INT( setting );
|
120
|
-
|
116
|
+
// Either MySQL 5.7.3 - 5.7.10, or Connector/C 6.1.3 - 6.1.x
|
117
|
+
if ((version >= 50703 && version < 50711) || (version >= 60103 && version < 60200)) {
|
121
118
|
if (val == SSL_MODE_DISABLED || val == SSL_MODE_REQUIRED) {
|
122
|
-
|
119
|
+
my_bool b = ( val == SSL_MODE_REQUIRED );
|
123
120
|
int result = mysql_options( wrapper->client, MYSQL_OPT_SSL_ENFORCE, &b );
|
124
121
|
return INT2NUM(result);
|
125
122
|
} else {
|
126
123
|
rb_warn( "MySQL client libraries between 5.7.3 and 5.7.10 only support SSL_MODE_DISABLED and SSL_MODE_REQUIRED" );
|
127
124
|
return Qnil;
|
128
125
|
}
|
126
|
+
} else {
|
127
|
+
rb_warn( "Your mysql client library does not support ssl_mode as expected." );
|
128
|
+
return Qnil;
|
129
129
|
}
|
130
130
|
#endif
|
131
131
|
#ifdef FULL_SSL_MODE_SUPPORT
|
@@ -178,10 +178,8 @@ static VALUE rb_raise_mysql2_error(mysql_client_wrapper *wrapper) {
|
|
178
178
|
VALUE rb_sql_state = rb_tainted_str_new2(mysql_sqlstate(wrapper->client));
|
179
179
|
VALUE e;
|
180
180
|
|
181
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
182
181
|
rb_enc_associate(rb_error_msg, rb_utf8_encoding());
|
183
182
|
rb_enc_associate(rb_sql_state, rb_usascii_encoding());
|
184
|
-
#endif
|
185
183
|
|
186
184
|
e = rb_funcall(cMysql2Error, intern_new_with_args, 4,
|
187
185
|
rb_error_msg,
|
@@ -357,9 +355,7 @@ static VALUE rb_mysql_client_escape(RB_MYSQL_UNUSED VALUE klass, VALUE str) {
|
|
357
355
|
return str;
|
358
356
|
} else {
|
359
357
|
rb_str = rb_str_new((const char*)newStr, newLen);
|
360
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
361
358
|
rb_enc_copy(rb_str, str);
|
362
|
-
#endif
|
363
359
|
xfree(newStr);
|
364
360
|
return rb_str;
|
365
361
|
}
|
@@ -386,9 +382,7 @@ static VALUE rb_mysql_info(VALUE self) {
|
|
386
382
|
}
|
387
383
|
|
388
384
|
rb_str = rb_str_new2(info);
|
389
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
390
385
|
rb_enc_associate(rb_str, rb_utf8_encoding());
|
391
|
-
#endif
|
392
386
|
|
393
387
|
return rb_str;
|
394
388
|
}
|
@@ -406,14 +400,25 @@ static VALUE rb_mysql_get_ssl_cipher(VALUE self)
|
|
406
400
|
}
|
407
401
|
|
408
402
|
rb_str = rb_str_new2(cipher);
|
409
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
410
403
|
rb_enc_associate(rb_str, rb_utf8_encoding());
|
411
|
-
#endif
|
412
404
|
|
413
405
|
return rb_str;
|
414
406
|
}
|
415
407
|
|
416
|
-
|
408
|
+
#ifdef CLIENT_CONNECT_ATTRS
|
409
|
+
static int opt_connect_attr_add_i(VALUE key, VALUE value, VALUE arg)
|
410
|
+
{
|
411
|
+
mysql_client_wrapper *wrapper = (mysql_client_wrapper *)arg;
|
412
|
+
rb_encoding *enc = rb_to_encoding(wrapper->encoding);
|
413
|
+
key = rb_str_export_to_enc(key, enc);
|
414
|
+
value = rb_str_export_to_enc(value, enc);
|
415
|
+
|
416
|
+
mysql_options4(wrapper->client, MYSQL_OPT_CONNECT_ATTR_ADD, StringValueCStr(key), StringValueCStr(value));
|
417
|
+
return ST_CONTINUE;
|
418
|
+
}
|
419
|
+
#endif
|
420
|
+
|
421
|
+
static VALUE rb_mysql_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE port, VALUE database, VALUE socket, VALUE flags, VALUE conn_attrs) {
|
417
422
|
struct nogvl_connect_args args;
|
418
423
|
time_t start_time, end_time, elapsed_time, connect_timeout;
|
419
424
|
VALUE rv;
|
@@ -428,6 +433,11 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
|
|
428
433
|
args.mysql = wrapper->client;
|
429
434
|
args.client_flag = NUM2ULONG(flags);
|
430
435
|
|
436
|
+
#ifdef CLIENT_CONNECT_ATTRS
|
437
|
+
mysql_options(wrapper->client, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
|
438
|
+
rb_hash_foreach(conn_attrs, opt_connect_attr_add_i, (VALUE)wrapper);
|
439
|
+
#endif
|
440
|
+
|
431
441
|
if (wrapper->connect_timeout)
|
432
442
|
time(&start_time);
|
433
443
|
rv = (VALUE) rb_thread_call_without_gvl(nogvl_connect, &args, RUBY_UBF_IO, 0);
|
@@ -521,7 +531,7 @@ static VALUE do_send_query(void *args) {
|
|
521
531
|
*/
|
522
532
|
static void *nogvl_read_query_result(void *ptr) {
|
523
533
|
MYSQL * client = ptr;
|
524
|
-
|
534
|
+
my_bool res = mysql_read_query_result(client);
|
525
535
|
|
526
536
|
return (void *)(res == 0 ? Qtrue : Qfalse);
|
527
537
|
}
|
@@ -574,7 +584,7 @@ static VALUE rb_mysql_client_async_result(VALUE self) {
|
|
574
584
|
rb_raise_mysql2_error(wrapper);
|
575
585
|
}
|
576
586
|
|
577
|
-
is_streaming = rb_hash_aref(
|
587
|
+
is_streaming = rb_hash_aref(rb_ivar_get(self, intern_current_query_options), sym_stream);
|
578
588
|
if (is_streaming == Qtrue) {
|
579
589
|
result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_use_result, wrapper, RUBY_UBF_IO, 0);
|
580
590
|
} else {
|
@@ -590,11 +600,14 @@ static VALUE rb_mysql_client_async_result(VALUE self) {
|
|
590
600
|
return Qnil;
|
591
601
|
}
|
592
602
|
|
593
|
-
|
603
|
+
// Duplicate the options hash and put the copy in the Result object
|
604
|
+
current = rb_hash_dup(rb_ivar_get(self, intern_current_query_options));
|
594
605
|
(void)RB_GC_GUARD(current);
|
595
606
|
Check_Type(current, T_HASH);
|
596
607
|
resultObj = rb_mysql_result_to_obj(self, wrapper->encoding, current, result, Qnil);
|
597
608
|
|
609
|
+
rb_mysql_set_server_query_flags(wrapper->client, resultObj);
|
610
|
+
|
598
611
|
return resultObj;
|
599
612
|
}
|
600
613
|
|
@@ -631,7 +644,7 @@ static VALUE do_query(void *args) {
|
|
631
644
|
int retval;
|
632
645
|
VALUE read_timeout;
|
633
646
|
|
634
|
-
read_timeout =
|
647
|
+
read_timeout = rb_ivar_get(async_args->self, intern_read_timeout);
|
635
648
|
|
636
649
|
tvp = NULL;
|
637
650
|
if (!NIL_P(read_timeout)) {
|
@@ -652,7 +665,7 @@ static VALUE do_query(void *args) {
|
|
652
665
|
retval = rb_wait_for_single_fd(async_args->fd, RB_WAITFD_IN, tvp);
|
653
666
|
|
654
667
|
if (retval == 0) {
|
655
|
-
rb_raise(
|
668
|
+
rb_raise(cMysql2TimeoutError, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));
|
656
669
|
}
|
657
670
|
|
658
671
|
if (retval < 0) {
|
@@ -747,7 +760,7 @@ static VALUE rb_mysql_client_abandon_results(VALUE self) {
|
|
747
760
|
* Query the database with +sql+, with optional +options+. For the possible
|
748
761
|
* options, see default_query_options on the Mysql2::Client class.
|
749
762
|
*/
|
750
|
-
static VALUE
|
763
|
+
static VALUE rb_mysql_query(VALUE self, VALUE sql, VALUE current) {
|
751
764
|
#ifndef _WIN32
|
752
765
|
struct async_query_args async_args;
|
753
766
|
#endif
|
@@ -759,15 +772,11 @@ static VALUE rb_query(VALUE self, VALUE sql, VALUE current) {
|
|
759
772
|
|
760
773
|
(void)RB_GC_GUARD(current);
|
761
774
|
Check_Type(current, T_HASH);
|
762
|
-
|
775
|
+
rb_ivar_set(self, intern_current_query_options, current);
|
763
776
|
|
764
777
|
Check_Type(sql, T_STRING);
|
765
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
766
778
|
/* ensure the string is in the encoding the connection is expecting */
|
767
779
|
args.sql = rb_str_export_to_enc(sql, rb_to_encoding(wrapper->encoding));
|
768
|
-
#else
|
769
|
-
args.sql = sql;
|
770
|
-
#endif
|
771
780
|
args.sql_ptr = RSTRING_PTR(args.sql);
|
772
781
|
args.sql_len = RSTRING_LEN(args.sql);
|
773
782
|
args.wrapper = wrapper;
|
@@ -804,20 +813,16 @@ static VALUE rb_mysql_client_real_escape(VALUE self, VALUE str) {
|
|
804
813
|
unsigned char *newStr;
|
805
814
|
VALUE rb_str;
|
806
815
|
unsigned long newLen, oldLen;
|
807
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
808
816
|
rb_encoding *default_internal_enc;
|
809
817
|
rb_encoding *conn_enc;
|
810
|
-
#endif
|
811
818
|
GET_CLIENT(self);
|
812
819
|
|
813
820
|
REQUIRE_CONNECTED(wrapper);
|
814
821
|
Check_Type(str, T_STRING);
|
815
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
816
822
|
default_internal_enc = rb_default_internal_encoding();
|
817
823
|
conn_enc = rb_to_encoding(wrapper->encoding);
|
818
824
|
/* ensure the string is in the encoding the connection is expecting */
|
819
825
|
str = rb_str_export_to_enc(str, conn_enc);
|
820
|
-
#endif
|
821
826
|
|
822
827
|
oldLen = RSTRING_LEN(str);
|
823
828
|
newStr = xmalloc(oldLen*2+1);
|
@@ -825,21 +830,17 @@ static VALUE rb_mysql_client_real_escape(VALUE self, VALUE str) {
|
|
825
830
|
newLen = mysql_real_escape_string(wrapper->client, (char *)newStr, RSTRING_PTR(str), oldLen);
|
826
831
|
if (newLen == oldLen) {
|
827
832
|
/* no need to return a new ruby string if nothing changed */
|
828
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
829
833
|
if (default_internal_enc) {
|
830
834
|
str = rb_str_export_to_enc(str, default_internal_enc);
|
831
835
|
}
|
832
|
-
#endif
|
833
836
|
xfree(newStr);
|
834
837
|
return str;
|
835
838
|
} else {
|
836
839
|
rb_str = rb_str_new((const char*)newStr, newLen);
|
837
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
838
840
|
rb_enc_associate(rb_str, conn_enc);
|
839
841
|
if (default_internal_enc) {
|
840
842
|
rb_str = rb_str_export_to_enc(rb_str, default_internal_enc);
|
841
843
|
}
|
842
|
-
#endif
|
843
844
|
xfree(newStr);
|
844
845
|
return rb_str;
|
845
846
|
}
|
@@ -850,7 +851,7 @@ static VALUE _mysql_client_options(VALUE self, int opt, VALUE value) {
|
|
850
851
|
const void *retval = NULL;
|
851
852
|
unsigned int intval = 0;
|
852
853
|
const char * charval = NULL;
|
853
|
-
|
854
|
+
my_bool boolval;
|
854
855
|
|
855
856
|
GET_CLIENT(self);
|
856
857
|
|
@@ -907,6 +908,11 @@ static VALUE _mysql_client_options(VALUE self, int opt, VALUE value) {
|
|
907
908
|
retval = charval;
|
908
909
|
break;
|
909
910
|
|
911
|
+
case MYSQL_DEFAULT_AUTH:
|
912
|
+
charval = (const char *)StringValueCStr(value);
|
913
|
+
retval = charval;
|
914
|
+
break;
|
915
|
+
|
910
916
|
#ifdef HAVE_CONST_MYSQL_ENABLE_CLEARTEXT_PLUGIN
|
911
917
|
case MYSQL_ENABLE_CLEARTEXT_PLUGIN:
|
912
918
|
boolval = (value == Qfalse ? 0 : 1);
|
@@ -950,10 +956,8 @@ static VALUE rb_mysql_client_info(RB_MYSQL_UNUSED VALUE klass) {
|
|
950
956
|
version = rb_str_new2(mysql_get_client_info());
|
951
957
|
header_version = rb_str_new2(MYSQL_LINK_VERSION);
|
952
958
|
|
953
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
954
959
|
rb_enc_associate(version, rb_usascii_encoding());
|
955
960
|
rb_enc_associate(header_version, rb_usascii_encoding());
|
956
|
-
#endif
|
957
961
|
|
958
962
|
rb_hash_aset(version_info, sym_id, LONG2NUM(mysql_get_client_version()));
|
959
963
|
rb_hash_aset(version_info, sym_version, version);
|
@@ -969,27 +973,21 @@ static VALUE rb_mysql_client_info(RB_MYSQL_UNUSED VALUE klass) {
|
|
969
973
|
*/
|
970
974
|
static VALUE rb_mysql_client_server_info(VALUE self) {
|
971
975
|
VALUE version, server_info;
|
972
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
973
976
|
rb_encoding *default_internal_enc;
|
974
977
|
rb_encoding *conn_enc;
|
975
|
-
#endif
|
976
978
|
GET_CLIENT(self);
|
977
979
|
|
978
980
|
REQUIRE_CONNECTED(wrapper);
|
979
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
980
981
|
default_internal_enc = rb_default_internal_encoding();
|
981
982
|
conn_enc = rb_to_encoding(wrapper->encoding);
|
982
|
-
#endif
|
983
983
|
|
984
984
|
version = rb_hash_new();
|
985
985
|
rb_hash_aset(version, sym_id, LONG2FIX(mysql_get_server_version(wrapper->client)));
|
986
986
|
server_info = rb_str_new2(mysql_get_server_info(wrapper->client));
|
987
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
988
987
|
rb_enc_associate(server_info, conn_enc);
|
989
988
|
if (default_internal_enc) {
|
990
989
|
server_info = rb_str_export_to_enc(server_info, default_internal_enc);
|
991
990
|
}
|
992
|
-
#endif
|
993
991
|
rb_hash_aset(version, sym_version, server_info);
|
994
992
|
return version;
|
995
993
|
}
|
@@ -1110,6 +1108,23 @@ static VALUE rb_mysql_client_ping(VALUE self) {
|
|
1110
1108
|
}
|
1111
1109
|
}
|
1112
1110
|
|
1111
|
+
/* call-seq:
|
1112
|
+
* client.set_server_option(value)
|
1113
|
+
*
|
1114
|
+
* Enables or disables an option for the connection.
|
1115
|
+
* Read https://dev.mysql.com/doc/refman/5.7/en/mysql-set-server-option.html
|
1116
|
+
* for more information.
|
1117
|
+
*/
|
1118
|
+
static VALUE rb_mysql_client_set_server_option(VALUE self, VALUE value) {
|
1119
|
+
GET_CLIENT(self);
|
1120
|
+
|
1121
|
+
if (mysql_set_server_option(wrapper->client, NUM2INT(value)) == 0) {
|
1122
|
+
return Qtrue;
|
1123
|
+
} else {
|
1124
|
+
return Qfalse;
|
1125
|
+
}
|
1126
|
+
}
|
1127
|
+
|
1113
1128
|
/* call-seq:
|
1114
1129
|
* client.more_results?
|
1115
1130
|
*
|
@@ -1168,7 +1183,8 @@ static VALUE rb_mysql_client_store_result(VALUE self)
|
|
1168
1183
|
return Qnil;
|
1169
1184
|
}
|
1170
1185
|
|
1171
|
-
|
1186
|
+
// Duplicate the options hash and put the copy in the Result object
|
1187
|
+
current = rb_hash_dup(rb_ivar_get(self, intern_current_query_options));
|
1172
1188
|
(void)RB_GC_GUARD(current);
|
1173
1189
|
Check_Type(current, T_HASH);
|
1174
1190
|
resultObj = rb_mysql_result_to_obj(self, wrapper->encoding, current, result, Qnil);
|
@@ -1176,7 +1192,6 @@ static VALUE rb_mysql_client_store_result(VALUE self)
|
|
1176
1192
|
return resultObj;
|
1177
1193
|
}
|
1178
1194
|
|
1179
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
1180
1195
|
/* call-seq:
|
1181
1196
|
* client.encoding
|
1182
1197
|
*
|
@@ -1186,7 +1201,6 @@ static VALUE rb_mysql_client_encoding(VALUE self) {
|
|
1186
1201
|
GET_CLIENT(self);
|
1187
1202
|
return wrapper->encoding;
|
1188
1203
|
}
|
1189
|
-
#endif
|
1190
1204
|
|
1191
1205
|
/* call-seq:
|
1192
1206
|
* client.automatic_close?
|
@@ -1256,7 +1270,7 @@ static VALUE set_read_timeout(VALUE self, VALUE value) {
|
|
1256
1270
|
/* Set the instance variable here even though _mysql_client_options
|
1257
1271
|
might not succeed, because the timeout is used in other ways
|
1258
1272
|
elsewhere */
|
1259
|
-
|
1273
|
+
rb_ivar_set(self, intern_read_timeout, value);
|
1260
1274
|
return _mysql_client_options(self, MYSQL_OPT_READ_TIMEOUT, value);
|
1261
1275
|
}
|
1262
1276
|
|
@@ -1272,17 +1286,14 @@ static VALUE set_write_timeout(VALUE self, VALUE value) {
|
|
1272
1286
|
|
1273
1287
|
static VALUE set_charset_name(VALUE self, VALUE value) {
|
1274
1288
|
char *charset_name;
|
1275
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
1276
1289
|
const struct mysql2_mysql_enc_name_to_rb_map *mysql2rb;
|
1277
1290
|
rb_encoding *enc;
|
1278
1291
|
VALUE rb_enc;
|
1279
|
-
#endif
|
1280
1292
|
GET_CLIENT(self);
|
1281
1293
|
|
1282
1294
|
Check_Type(value, T_STRING);
|
1283
1295
|
charset_name = RSTRING_PTR(value);
|
1284
1296
|
|
1285
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
1286
1297
|
mysql2rb = mysql2_mysql_enc_name_to_rb(charset_name, (unsigned int)RSTRING_LEN(value));
|
1287
1298
|
if (mysql2rb == NULL || mysql2rb->rb_name == NULL) {
|
1288
1299
|
VALUE inspect = rb_inspect(value);
|
@@ -1292,7 +1303,6 @@ static VALUE set_charset_name(VALUE self, VALUE value) {
|
|
1292
1303
|
rb_enc = rb_enc_from_encoding(enc);
|
1293
1304
|
wrapper->encoding = rb_enc;
|
1294
1305
|
}
|
1295
|
-
#endif
|
1296
1306
|
|
1297
1307
|
if (mysql_options(wrapper->client, MYSQL_SET_CHARSET_NAME, charset_name)) {
|
1298
1308
|
/* TODO: warning - unable to set charset */
|
@@ -1336,6 +1346,10 @@ static VALUE set_init_command(VALUE self, VALUE value) {
|
|
1336
1346
|
return _mysql_client_options(self, MYSQL_INIT_COMMAND, value);
|
1337
1347
|
}
|
1338
1348
|
|
1349
|
+
static VALUE set_default_auth(VALUE self, VALUE value) {
|
1350
|
+
return _mysql_client_options(self, MYSQL_DEFAULT_AUTH, value);
|
1351
|
+
}
|
1352
|
+
|
1339
1353
|
static VALUE set_enable_cleartext_plugin(VALUE self, VALUE value) {
|
1340
1354
|
#ifdef HAVE_CONST_MYSQL_ENABLE_CLEARTEXT_PLUGIN
|
1341
1355
|
return _mysql_client_options(self, MYSQL_ENABLE_CLEARTEXT_PLUGIN, value);
|
@@ -1416,6 +1430,7 @@ void init_mysql2_client() {
|
|
1416
1430
|
rb_define_method(cMysql2Client, "thread_id", rb_mysql_client_thread_id, 0);
|
1417
1431
|
rb_define_method(cMysql2Client, "ping", rb_mysql_client_ping, 0);
|
1418
1432
|
rb_define_method(cMysql2Client, "select_db", rb_mysql_client_select_db, 1);
|
1433
|
+
rb_define_method(cMysql2Client, "set_server_option", rb_mysql_client_set_server_option, 1);
|
1419
1434
|
rb_define_method(cMysql2Client, "more_results?", rb_mysql_client_more_results, 0);
|
1420
1435
|
rb_define_method(cMysql2Client, "next_result", rb_mysql_client_next_result, 0);
|
1421
1436
|
rb_define_method(cMysql2Client, "store_result", rb_mysql_client_store_result, 0);
|
@@ -1425,9 +1440,7 @@ void init_mysql2_client() {
|
|
1425
1440
|
rb_define_method(cMysql2Client, "warning_count", rb_mysql_client_warning_count, 0);
|
1426
1441
|
rb_define_method(cMysql2Client, "query_info_string", rb_mysql_info, 0);
|
1427
1442
|
rb_define_method(cMysql2Client, "ssl_cipher", rb_mysql_get_ssl_cipher, 0);
|
1428
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
1429
1443
|
rb_define_method(cMysql2Client, "encoding", rb_mysql_client_encoding, 0);
|
1430
|
-
#endif
|
1431
1444
|
|
1432
1445
|
rb_define_private_method(cMysql2Client, "connect_timeout=", set_connect_timeout, 1);
|
1433
1446
|
rb_define_private_method(cMysql2Client, "read_timeout=", set_read_timeout, 1);
|
@@ -1438,12 +1451,13 @@ void init_mysql2_client() {
|
|
1438
1451
|
rb_define_private_method(cMysql2Client, "default_file=", set_read_default_file, 1);
|
1439
1452
|
rb_define_private_method(cMysql2Client, "default_group=", set_read_default_group, 1);
|
1440
1453
|
rb_define_private_method(cMysql2Client, "init_command=", set_init_command, 1);
|
1454
|
+
rb_define_private_method(cMysql2Client, "default_auth=", set_default_auth, 1);
|
1441
1455
|
rb_define_private_method(cMysql2Client, "ssl_set", set_ssl_options, 5);
|
1442
1456
|
rb_define_private_method(cMysql2Client, "ssl_mode=", rb_set_ssl_mode_option, 1);
|
1443
1457
|
rb_define_private_method(cMysql2Client, "enable_cleartext_plugin=", set_enable_cleartext_plugin, 1);
|
1444
1458
|
rb_define_private_method(cMysql2Client, "initialize_ext", initialize_ext, 0);
|
1445
|
-
rb_define_private_method(cMysql2Client, "connect",
|
1446
|
-
rb_define_private_method(cMysql2Client, "_query",
|
1459
|
+
rb_define_private_method(cMysql2Client, "connect", rb_mysql_connect, 8);
|
1460
|
+
rb_define_private_method(cMysql2Client, "_query", rb_mysql_query, 2);
|
1447
1461
|
|
1448
1462
|
sym_id = ID2SYM(rb_intern("id"));
|
1449
1463
|
sym_version = ID2SYM(rb_intern("version"));
|
@@ -1454,10 +1468,16 @@ void init_mysql2_client() {
|
|
1454
1468
|
sym_array = ID2SYM(rb_intern("array"));
|
1455
1469
|
sym_stream = ID2SYM(rb_intern("stream"));
|
1456
1470
|
|
1471
|
+
sym_no_good_index_used = ID2SYM(rb_intern("no_good_index_used"));
|
1472
|
+
sym_no_index_used = ID2SYM(rb_intern("no_index_used"));
|
1473
|
+
sym_query_was_slow = ID2SYM(rb_intern("query_was_slow"));
|
1474
|
+
|
1457
1475
|
intern_brackets = rb_intern("[]");
|
1458
1476
|
intern_merge = rb_intern("merge");
|
1459
1477
|
intern_merge_bang = rb_intern("merge!");
|
1460
1478
|
intern_new_with_args = rb_intern("new_with_args");
|
1479
|
+
intern_current_query_options = rb_intern("@current_query_options");
|
1480
|
+
intern_read_timeout = rb_intern("@read_timeout");
|
1461
1481
|
|
1462
1482
|
#ifdef CLIENT_LONG_PASSWORD
|
1463
1483
|
rb_const_set(cMysql2Client, rb_intern("LONG_PASSWORD"),
|
@@ -1543,6 +1563,16 @@ void init_mysql2_client() {
|
|
1543
1563
|
rb_const_set(cMysql2Client, rb_intern("SECURE_CONNECTION"), LONG2NUM(0));
|
1544
1564
|
#endif
|
1545
1565
|
|
1566
|
+
#ifdef HAVE_CONST_MYSQL_OPTION_MULTI_STATEMENTS_ON
|
1567
|
+
rb_const_set(cMysql2Client, rb_intern("OPTION_MULTI_STATEMENTS_ON"),
|
1568
|
+
LONG2NUM(MYSQL_OPTION_MULTI_STATEMENTS_ON));
|
1569
|
+
#endif
|
1570
|
+
|
1571
|
+
#ifdef HAVE_CONST_MYSQL_OPTION_MULTI_STATEMENTS_OFF
|
1572
|
+
rb_const_set(cMysql2Client, rb_intern("OPTION_MULTI_STATEMENTS_OFF"),
|
1573
|
+
LONG2NUM(MYSQL_OPTION_MULTI_STATEMENTS_OFF));
|
1574
|
+
#endif
|
1575
|
+
|
1546
1576
|
#ifdef CLIENT_MULTI_STATEMENTS
|
1547
1577
|
rb_const_set(cMysql2Client, rb_intern("MULTI_STATEMENTS"),
|
1548
1578
|
LONG2NUM(CLIENT_MULTI_STATEMENTS));
|
@@ -1573,6 +1603,16 @@ void init_mysql2_client() {
|
|
1573
1603
|
LONG2NUM(CLIENT_BASIC_FLAGS));
|
1574
1604
|
#endif
|
1575
1605
|
|
1606
|
+
#ifdef CLIENT_CONNECT_ATTRS
|
1607
|
+
rb_const_set(cMysql2Client, rb_intern("CONNECT_ATTRS"),
|
1608
|
+
LONG2NUM(CLIENT_CONNECT_ATTRS));
|
1609
|
+
#else
|
1610
|
+
/* HACK because MySQL 5.5 and earlier don't define this constant,
|
1611
|
+
* but we're using it in our default connection flags. */
|
1612
|
+
rb_const_set(cMysql2Client, rb_intern("CONNECT_ATTRS"),
|
1613
|
+
INT2NUM(0));
|
1614
|
+
#endif
|
1615
|
+
|
1576
1616
|
#if defined(FULL_SSL_MODE_SUPPORT) // MySQL 5.7.11 and above
|
1577
1617
|
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_DISABLED"), INT2NUM(SSL_MODE_DISABLED));
|
1578
1618
|
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_PREFERRED"), INT2NUM(SSL_MODE_PREFERRED));
|
@@ -1600,3 +1640,29 @@ void init_mysql2_client() {
|
|
1600
1640
|
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_VERIFY_IDENTITY"), INT2NUM(0));
|
1601
1641
|
#endif
|
1602
1642
|
}
|
1643
|
+
|
1644
|
+
#define flag_to_bool(f) ((client->server_status & f) ? Qtrue : Qfalse)
|
1645
|
+
|
1646
|
+
void rb_mysql_set_server_query_flags(MYSQL *client, VALUE result) {
|
1647
|
+
VALUE server_flags = rb_hash_new();
|
1648
|
+
|
1649
|
+
#ifdef HAVE_CONST_SERVER_QUERY_NO_GOOD_INDEX_USED
|
1650
|
+
rb_hash_aset(server_flags, sym_no_good_index_used, flag_to_bool(SERVER_QUERY_NO_GOOD_INDEX_USED));
|
1651
|
+
#else
|
1652
|
+
rb_hash_aset(server_flags, sym_no_good_index_used, Qnil);
|
1653
|
+
#endif
|
1654
|
+
|
1655
|
+
#ifdef HAVE_CONST_SERVER_QUERY_NO_INDEX_USED
|
1656
|
+
rb_hash_aset(server_flags, sym_no_index_used, flag_to_bool(SERVER_QUERY_NO_INDEX_USED));
|
1657
|
+
#else
|
1658
|
+
rb_hash_aset(server_flags, sym_no_index_used, Qnil);
|
1659
|
+
#endif
|
1660
|
+
|
1661
|
+
#ifdef HAVE_CONST_SERVER_QUERY_WAS_SLOW
|
1662
|
+
rb_hash_aset(server_flags, sym_query_was_slow, flag_to_bool(SERVER_QUERY_WAS_SLOW));
|
1663
|
+
#else
|
1664
|
+
rb_hash_aset(server_flags, sym_query_was_slow, Qnil);
|
1665
|
+
#endif
|
1666
|
+
|
1667
|
+
rb_iv_set(result, "@server_flags", server_flags);
|
1668
|
+
}
|