mysql2 0.5.0 → 0.5.4
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.
- checksums.yaml +5 -5
- data/README.md +81 -34
- data/ext/mysql2/client.c +123 -25
- data/ext/mysql2/extconf.rb +24 -6
- data/ext/mysql2/mysql2_ext.c +6 -1
- 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 +231 -15
- data/ext/mysql2/result.h +1 -0
- data/ext/mysql2/statement.c +46 -14
- data/lib/mysql2/client.rb +20 -3
- data/lib/mysql2/error.rb +4 -3
- data/lib/mysql2/statement.rb +1 -3
- data/lib/mysql2/version.rb +1 -1
- data/lib/mysql2.rb +7 -3
- data/support/3A79BD29.asc +49 -0
- data/support/5072E1F5.asc +5 -5
- data/support/mysql_enc_to_ruby.rb +6 -1
- data/support/ruby_enc_to_mysql.rb +2 -0
- metadata +10 -55
- data/examples/eventmachine.rb +0 -19
- data/examples/threaded.rb +0 -16
- data/spec/configuration.yml.example +0 -11
- data/spec/em/em_spec.rb +0 -135
- data/spec/my.cnf.example +0 -9
- data/spec/mysql2/client_spec.rb +0 -1072
- data/spec/mysql2/error_spec.rb +0 -78
- data/spec/mysql2/result_spec.rb +0 -485
- data/spec/mysql2/statement_spec.rb +0 -708
- data/spec/rcov.opts +0 -3
- data/spec/spec_helper.rb +0 -112
- 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: f387f841adc885eb4000a960ee34f475c7edab79e276d17ce8889f370bdcf387
|
4
|
+
data.tar.gz: 0c8732c2a45ed8ac68aea92765daba5969f860f1fe5a95d44e89b76deae7108b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8d6afb1b661525183075d14046630195bc79a5f945b92489d3daa0aeea8582e8d17a0fa9d1781fadeaaefaaeac567ead5ad7d0266e1fb9aa96076d26f1c03ad1
|
7
|
+
data.tar.gz: 9b2202a06e36ca910a9648f71d8646e67a6e665153b3ac04dcd535cd768bb78942dd799893e205df841b0461aeb5810985704e18e4a045b540f2d272b11776cd
|
data/README.md
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
# Mysql2 - A modern, simple and very fast MySQL library for Ruby - binding to libmysql
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
GitHub Actions
|
4
|
+
[](https://github.com/brianmario/mysql2/actions/workflows/build.yml)
|
5
|
+
[](https://github.com/brianmario/mysql2/actions/workflows/container.yml)
|
6
|
+
Travis CI
|
7
|
+
[](https://travis-ci.org/brianmario/mysql2)
|
8
|
+
Appveyor CI
|
9
|
+
[](https://ci.appveyor.com/project/sodabrew/mysql2)
|
5
10
|
|
6
11
|
The Mysql2 gem is meant to serve the extremely common use-case of connecting, querying and iterating on results.
|
7
12
|
Some database libraries out there serve as direct 1:1 mappings of the already complex C APIs available.
|
@@ -18,16 +23,18 @@ The API consists of three classes:
|
|
18
23
|
`Mysql2::Statement` - returned from issuing a #prepare on the connection. Execute the statement to get a Result.
|
19
24
|
|
20
25
|
## Installing
|
26
|
+
|
21
27
|
### General Instructions
|
28
|
+
|
22
29
|
``` sh
|
23
30
|
gem install mysql2
|
24
31
|
```
|
25
32
|
|
26
33
|
This gem links against MySQL's `libmysqlclient` library or `Connector/C`
|
27
34
|
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.
|
35
|
+
You may need to install a package such as `libmariadb-dev`, `libmysqlclient-dev`,
|
36
|
+
`mysql-devel`, or other appropriate package for your system. See below for
|
37
|
+
system-specific instructions.
|
31
38
|
|
32
39
|
By default, the mysql2 gem will try to find a copy of MySQL in this order:
|
33
40
|
|
@@ -74,10 +81,11 @@ To see line numbers in backtraces, declare these environment variables
|
|
74
81
|
|
75
82
|
### Linux and other Unixes
|
76
83
|
|
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
|
-
|
84
|
+
You may need to install a package such as `libmariadb-dev`, `libmysqlclient-dev`,
|
85
|
+
`mysql-devel`, or `default-libmysqlclient-dev`; refer to your distribution's package guide to
|
86
|
+
find the particular package. The most common issue we see is a user who has
|
87
|
+
the library file `libmysqlclient.so` but is missing the header file `mysql.h`
|
88
|
+
-- double check that you have the _-dev_ packages installed.
|
81
89
|
|
82
90
|
### Mac OS X
|
83
91
|
|
@@ -89,6 +97,7 @@ If you have not done so already, you will need to install the XCode select tools
|
|
89
97
|
`xcode-select --install`.
|
90
98
|
|
91
99
|
### Windows
|
100
|
+
|
92
101
|
Make sure that you have Ruby and the DevKit compilers installed. We recommend
|
93
102
|
the [Ruby Installer](http://rubyinstaller.org) distribution.
|
94
103
|
|
@@ -139,7 +148,7 @@ results.each do |row|
|
|
139
148
|
# the keys are the fields, as you'd expect
|
140
149
|
# the values are pre-built ruby primitives mapped from their corresponding field types in MySQL
|
141
150
|
puts row["id"] # row["id"].is_a? Integer
|
142
|
-
if row["dne"] # non-
|
151
|
+
if row["dne"] # non-existent hash entry is nil
|
143
152
|
puts row["dne"]
|
144
153
|
end
|
145
154
|
end
|
@@ -156,16 +165,17 @@ end
|
|
156
165
|
How about with symbolized keys?
|
157
166
|
|
158
167
|
``` ruby
|
159
|
-
client.query("SELECT * FROM users WHERE group='githubbers'", :symbolize_keys => true) do |row|
|
168
|
+
client.query("SELECT * FROM users WHERE group='githubbers'", :symbolize_keys => true).each do |row|
|
160
169
|
# do something with row, it's ready to rock
|
161
170
|
end
|
162
171
|
```
|
163
172
|
|
164
|
-
You can get the headers and the
|
173
|
+
You can get the headers, columns, and the field types in the order that they were returned
|
165
174
|
by the query like this:
|
166
175
|
|
167
176
|
``` ruby
|
168
177
|
headers = results.fields # <= that's an array of field names, in order
|
178
|
+
types = results.field_types # <= that's an array of field types, in order
|
169
179
|
results.each(:as => :array) do |row|
|
170
180
|
# Each row is an array, ordered the same as the query results
|
171
181
|
# An otter's den is called a "holt" or "couch"
|
@@ -178,6 +188,9 @@ Pass your arguments to the execute method in the same number and order as the
|
|
178
188
|
question marks in the statement. Query options can be passed as keyword arguments
|
179
189
|
to the execute method.
|
180
190
|
|
191
|
+
Be sure to read about the known limitations of prepared statements at
|
192
|
+
[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)
|
193
|
+
|
181
194
|
``` ruby
|
182
195
|
statement = @client.prepare("SELECT * FROM users WHERE login_count = ?")
|
183
196
|
result1 = statement.execute(1)
|
@@ -190,6 +203,23 @@ statement = @client.prepare("SELECT * FROM users WHERE last_login >= ? AND locat
|
|
190
203
|
result = statement.execute(1, "CA", :as => :array)
|
191
204
|
```
|
192
205
|
|
206
|
+
Session Tracking information can be accessed with
|
207
|
+
|
208
|
+
```ruby
|
209
|
+
c = Mysql2::Client.new(
|
210
|
+
host: "127.0.0.1",
|
211
|
+
username: "root",
|
212
|
+
flags: "SESSION_TRACK",
|
213
|
+
init_command: "SET @@SESSION.session_track_schema=ON"
|
214
|
+
)
|
215
|
+
c.query("INSERT INTO test VALUES (1)")
|
216
|
+
session_track_type = Mysql2::Client::SESSION_TRACK_SCHEMA
|
217
|
+
session_track_data = c.session_track(session_track_type)
|
218
|
+
```
|
219
|
+
|
220
|
+
The types of session track types can be found at
|
221
|
+
[https://dev.mysql.com/doc/refman/5.7/en/session-state-tracking.html](https://dev.mysql.com/doc/refman/5.7/en/session-state-tracking.html)
|
222
|
+
|
193
223
|
## Connection options
|
194
224
|
|
195
225
|
You may set the following connection options in Mysql2::Client.new(...):
|
@@ -214,6 +244,7 @@ Mysql2::Client.new(
|
|
214
244
|
:ssl_mode = :disabled / :preferred / :required / :verify_ca / :verify_identity,
|
215
245
|
:default_file = '/path/to/my.cfg',
|
216
246
|
:default_group = 'my.cfg section',
|
247
|
+
:default_auth = 'authentication_windows_client'
|
217
248
|
:init_command => sql
|
218
249
|
)
|
219
250
|
```
|
@@ -254,7 +285,7 @@ Mysql2::Client.new(
|
|
254
285
|
|
255
286
|
### Secure auth
|
256
287
|
|
257
|
-
Starting
|
288
|
+
Starting with MySQL 5.6.5, secure_auth is enabled by default on servers (it was disabled by default prior to this).
|
258
289
|
When secure_auth is enabled, the server will refuse a connection if the account password is stored in old pre-MySQL 4.1 format.
|
259
290
|
The MySQL 5.6.5 client library may also refuse to attempt a connection if provided an older format password.
|
260
291
|
To bypass this restriction in the client, pass the option `:secure_auth => false` to Mysql2::Client.new().
|
@@ -270,8 +301,10 @@ The string form will be split on whitespace and parsed as with the array form:
|
|
270
301
|
Plain flags are added to the default flags, while flags prefixed with `-`
|
271
302
|
(minus) are removed from the default flags.
|
272
303
|
|
273
|
-
|
274
|
-
|
304
|
+
### Using Active Record's database.yml
|
305
|
+
|
306
|
+
Active Record typically reads its configuration from a file named `database.yml` or an environment variable `DATABASE_URL`.
|
307
|
+
Use the value `mysql2` as the adapter name. For example:
|
275
308
|
|
276
309
|
``` yaml
|
277
310
|
development:
|
@@ -289,6 +322,17 @@ development:
|
|
289
322
|
secure_auth: false
|
290
323
|
```
|
291
324
|
|
325
|
+
In this example, the compression flag is negated with `-COMPRESS`.
|
326
|
+
|
327
|
+
### Using Active Record's DATABASE_URL
|
328
|
+
|
329
|
+
Active Record typically reads its configuration from a file named `database.yml` or an environment variable `DATABASE_URL`.
|
330
|
+
Use the value `mysql2` as the protocol name. For example:
|
331
|
+
|
332
|
+
``` shell
|
333
|
+
DATABASE_URL=mysql2://sql_user:sql_pass@sql_host_name:port/sql_db_name?option1=value1&option2=value2
|
334
|
+
```
|
335
|
+
|
292
336
|
### Reading a MySQL config file
|
293
337
|
|
294
338
|
You may read configuration options from a MySQL configuration file by passing
|
@@ -343,7 +387,8 @@ end
|
|
343
387
|
```
|
344
388
|
|
345
389
|
Yields:
|
346
|
-
|
390
|
+
|
391
|
+
```ruby
|
347
392
|
{"1"=>1}
|
348
393
|
{"2"=>2}
|
349
394
|
next_result: Unknown column 'A' in 'field list' (Mysql2::Error)
|
@@ -403,7 +448,7 @@ Pass the `:as => :array` option to any of the above methods of configuration
|
|
403
448
|
|
404
449
|
### Array of Hashes
|
405
450
|
|
406
|
-
The default result type is set to
|
451
|
+
The default result type is set to `:hash`, but you can override a previous setting to something else with `:as => :hash`
|
407
452
|
|
408
453
|
### Timezones
|
409
454
|
|
@@ -502,7 +547,7 @@ There are a few things that need to be kept in mind while using streaming:
|
|
502
547
|
* `:cache_rows` is ignored currently. (if you want to use `:cache_rows` you probably don't want to be using `:stream`)
|
503
548
|
* You must fetch all rows in the result set of your query before you can make new queries. (i.e. with `Mysql2::Result#each`)
|
504
549
|
|
505
|
-
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.
|
550
|
+
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).
|
506
551
|
|
507
552
|
### Lazy Everything
|
508
553
|
|
@@ -523,20 +568,21 @@ As for field values themselves, I'm workin on it - but expect that soon.
|
|
523
568
|
|
524
569
|
This gem is tested with the following Ruby versions on Linux and Mac OS X:
|
525
570
|
|
526
|
-
|
527
|
-
|
571
|
+
* Ruby MRI 2.0.0, 2.1.x, 2.2.x, 2.3.x, 2.4.x, 2.5.x, 2.6.x
|
572
|
+
* Rubinius 2.x and 3.x do work but may fail under some workloads
|
528
573
|
|
529
574
|
This gem is tested with the following MySQL and MariaDB versions:
|
530
575
|
|
531
|
-
|
532
|
-
|
533
|
-
|
576
|
+
* MySQL 5.5, 5.6, 5.7, 8.0
|
577
|
+
* MySQL Connector/C 6.0 and 6.1 (primarily on Windows)
|
578
|
+
* MariaDB 5.5, 10.0, 10.1, 10.2, 10.3
|
534
579
|
|
535
580
|
### Ruby on Rails / Active Record
|
536
581
|
|
537
|
-
|
538
|
-
|
539
|
-
|
582
|
+
* mysql2 0.5.x works with Rails / Active Record 4.2.11, 5.0.7, 5.1.6, and higher.
|
583
|
+
* mysql2 0.4.x works with Rails / Active Record 4.2.5 - 5.0 and higher.
|
584
|
+
* mysql2 0.3.x works with Rails / Active Record 3.1, 3.2, 4.x, 5.0.
|
585
|
+
* mysql2 0.2.x works with Rails / Active Record 2.3 - 3.0.
|
540
586
|
|
541
587
|
### Asynchronous Active Record
|
542
588
|
|
@@ -619,11 +665,12 @@ though.
|
|
619
665
|
## Special Thanks
|
620
666
|
|
621
667
|
* Eric Wong - for the contribution (and the informative explanations) of some thread-safety, non-blocking I/O and cleanup patches. You rock dude
|
622
|
-
* Yury Korolev
|
623
|
-
* Aaron Patterson
|
624
|
-
* Mike Perham
|
625
|
-
* Aaron Stone
|
626
|
-
* Kouhei Ueno
|
627
|
-
* John Cant
|
628
|
-
* Justin Case
|
629
|
-
* Tamir Duberstein
|
668
|
+
* [Yury Korolev](http://github.com/yury) - for TONS of help testing the Active Record adapter
|
669
|
+
* [Aaron Patterson](http://github.com/tenderlove) - tons of contributions, suggestions and general badassness
|
670
|
+
* [Mike Perham](http://github.com/mperham) - Async Active Record adapter (uses Fibers and EventMachine)
|
671
|
+
* [Aaron Stone](http://github.com/sodabrew) - additional client settings, local files, microsecond time, maintenance support
|
672
|
+
* [Kouhei Ueno](https://github.com/nyaxt) - for the original work on Prepared Statements way back in 2012
|
673
|
+
* [John Cant](http://github.com/johncant) - polishing and updating Prepared Statements support
|
674
|
+
* [Justin Case](http://github.com/justincase) - polishing and updating Prepared Statements support and getting it merged
|
675
|
+
* [Tamir Duberstein](http://github.com/tamird) - for help with timeouts and all around updates and cleanups
|
676
|
+
* [Jun Aruga](http://github.com/junaruga) - for migrating CI tests to GitHub Actions and other improvements
|
data/ext/mysql2/client.c
CHANGED
@@ -18,7 +18,8 @@ VALUE cMysql2Client;
|
|
18
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
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
|
21
|
+
static ID intern_brackets, intern_merge, intern_merge_bang, intern_new_with_args,
|
22
|
+
intern_current_query_options, intern_read_timeout;
|
22
23
|
|
23
24
|
#define REQUIRE_INITIALIZED(wrapper) \
|
24
25
|
if (!wrapper->initialized) { \
|
@@ -44,7 +45,7 @@ static ID intern_brackets, intern_merge, intern_merge_bang, intern_new_with_args
|
|
44
45
|
}
|
45
46
|
|
46
47
|
/*
|
47
|
-
*
|
48
|
+
* compatibility with mysql-connector-c, where LIBMYSQL_VERSION is the correct
|
48
49
|
* variable to use, but MYSQL_SERVER_VERSION gives the correct numbers when
|
49
50
|
* linking against the server itself
|
50
51
|
*/
|
@@ -57,8 +58,23 @@ static ID intern_brackets, intern_merge, intern_merge_bang, intern_new_with_args
|
|
57
58
|
#endif
|
58
59
|
|
59
60
|
/*
|
60
|
-
*
|
61
|
+
* mariadb-connector-c defines CLIENT_SESSION_TRACKING and SESSION_TRACK_TRANSACTION_TYPE
|
62
|
+
* while mysql-connector-c defines CLIENT_SESSION_TRACK and SESSION_TRACK_TRANSACTION_STATE
|
63
|
+
* This is a hack to take care of both clients.
|
61
64
|
*/
|
65
|
+
#if defined(CLIENT_SESSION_TRACK)
|
66
|
+
#elif defined(CLIENT_SESSION_TRACKING)
|
67
|
+
#define CLIENT_SESSION_TRACK CLIENT_SESSION_TRACKING
|
68
|
+
#define SESSION_TRACK_TRANSACTION_STATE SESSION_TRACK_TRANSACTION_TYPE
|
69
|
+
#endif
|
70
|
+
|
71
|
+
/*
|
72
|
+
* compatibility with mysql-connector-c 6.1.x, MySQL 5.7.3 - 5.7.10 & with MariaDB 10.x and later.
|
73
|
+
*/
|
74
|
+
#ifdef HAVE_CONST_MYSQL_OPT_SSL_VERIFY_SERVER_CERT
|
75
|
+
#define SSL_MODE_VERIFY_IDENTITY 5
|
76
|
+
#define HAVE_CONST_SSL_MODE_VERIFY_IDENTITY
|
77
|
+
#endif
|
62
78
|
#ifdef HAVE_CONST_MYSQL_OPT_SSL_ENFORCE
|
63
79
|
#define SSL_MODE_DISABLED 1
|
64
80
|
#define SSL_MODE_REQUIRED 3
|
@@ -109,18 +125,30 @@ static VALUE rb_set_ssl_mode_option(VALUE self, VALUE setting) {
|
|
109
125
|
rb_warn( "Your mysql client library does not support setting ssl_mode; full support comes with 5.7.11." );
|
110
126
|
return Qnil;
|
111
127
|
}
|
112
|
-
#
|
128
|
+
#if defined(HAVE_CONST_MYSQL_OPT_SSL_VERIFY_SERVER_CERT) || defined(HAVE_CONST_MYSQL_OPT_SSL_ENFORCE)
|
113
129
|
GET_CLIENT(self);
|
114
130
|
int val = NUM2INT( setting );
|
115
|
-
|
131
|
+
// Either MySQL 5.7.3 - 5.7.10, or Connector/C 6.1.3 - 6.1.x, or MariaDB 10.x and later
|
132
|
+
if ((version >= 50703 && version < 50711) || (version >= 60103 && version < 60200) || version >= 100000) {
|
133
|
+
#ifdef HAVE_CONST_MYSQL_OPT_SSL_VERIFY_SERVER_CERT
|
134
|
+
if (val == SSL_MODE_VERIFY_IDENTITY) {
|
135
|
+
my_bool b = 1;
|
136
|
+
int result = mysql_options( wrapper->client, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &b );
|
137
|
+
return INT2NUM(result);
|
138
|
+
}
|
139
|
+
#endif
|
140
|
+
#ifdef HAVE_CONST_MYSQL_OPT_SSL_ENFORCE
|
116
141
|
if (val == SSL_MODE_DISABLED || val == SSL_MODE_REQUIRED) {
|
117
142
|
my_bool b = ( val == SSL_MODE_REQUIRED );
|
118
143
|
int result = mysql_options( wrapper->client, MYSQL_OPT_SSL_ENFORCE, &b );
|
119
144
|
return INT2NUM(result);
|
120
|
-
} else {
|
121
|
-
rb_warn( "MySQL client libraries between 5.7.3 and 5.7.10 only support SSL_MODE_DISABLED and SSL_MODE_REQUIRED" );
|
122
|
-
return Qnil;
|
123
145
|
}
|
146
|
+
#endif
|
147
|
+
rb_warn( "Your mysql client library does not support ssl_mode %d.", val );
|
148
|
+
return Qnil;
|
149
|
+
} else {
|
150
|
+
rb_warn( "Your mysql client library does not support ssl_mode as expected." );
|
151
|
+
return Qnil;
|
124
152
|
}
|
125
153
|
#endif
|
126
154
|
#ifdef FULL_SSL_MODE_SUPPORT
|
@@ -135,6 +163,7 @@ static VALUE rb_set_ssl_mode_option(VALUE self, VALUE setting) {
|
|
135
163
|
return INT2NUM(result);
|
136
164
|
#endif
|
137
165
|
#ifdef NO_SSL_MODE_SUPPORT
|
166
|
+
rb_warn( "Your mysql client library does not support setting ssl_mode; full support comes with 5.7.11." );
|
138
167
|
return Qnil;
|
139
168
|
#endif
|
140
169
|
}
|
@@ -170,7 +199,7 @@ static void rb_mysql_client_mark(void * wrapper) {
|
|
170
199
|
|
171
200
|
static VALUE rb_raise_mysql2_error(mysql_client_wrapper *wrapper) {
|
172
201
|
VALUE rb_error_msg = rb_str_new2(mysql_error(wrapper->client));
|
173
|
-
VALUE rb_sql_state =
|
202
|
+
VALUE rb_sql_state = rb_str_new2(mysql_sqlstate(wrapper->client));
|
174
203
|
VALUE e;
|
175
204
|
|
176
205
|
rb_enc_associate(rb_error_msg, rb_utf8_encoding());
|
@@ -264,7 +293,7 @@ static VALUE invalidate_fd(int clientfd)
|
|
264
293
|
static void *nogvl_close(void *ptr) {
|
265
294
|
mysql_client_wrapper *wrapper = ptr;
|
266
295
|
|
267
|
-
if (!wrapper->closed) {
|
296
|
+
if (wrapper->initialized && !wrapper->closed) {
|
268
297
|
mysql_close(wrapper->client);
|
269
298
|
wrapper->closed = 1;
|
270
299
|
wrapper->reconnect_enabled = 0;
|
@@ -318,9 +347,9 @@ static VALUE allocate(VALUE klass) {
|
|
318
347
|
wrapper->server_version = 0;
|
319
348
|
wrapper->reconnect_enabled = 0;
|
320
349
|
wrapper->connect_timeout = 0;
|
321
|
-
wrapper->initialized = 0; /*
|
350
|
+
wrapper->initialized = 0; /* will be set true after calling mysql_init */
|
351
|
+
wrapper->closed = 1; /* will be set false after calling mysql_real_connect */
|
322
352
|
wrapper->refcount = 1;
|
323
|
-
wrapper->closed = 0;
|
324
353
|
wrapper->client = (MYSQL*)xmalloc(sizeof(MYSQL));
|
325
354
|
|
326
355
|
return obj;
|
@@ -462,6 +491,7 @@ static VALUE rb_mysql_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VA
|
|
462
491
|
rb_raise_mysql2_error(wrapper);
|
463
492
|
}
|
464
493
|
|
494
|
+
wrapper->closed = 0;
|
465
495
|
wrapper->server_version = mysql_get_server_version(wrapper->client);
|
466
496
|
return self;
|
467
497
|
}
|
@@ -508,10 +538,10 @@ static void *nogvl_send_query(void *ptr) {
|
|
508
538
|
return (void*)(rv == 0 ? Qtrue : Qfalse);
|
509
539
|
}
|
510
540
|
|
511
|
-
static VALUE do_send_query(
|
512
|
-
struct nogvl_send_query_args *query_args = args;
|
541
|
+
static VALUE do_send_query(VALUE args) {
|
542
|
+
struct nogvl_send_query_args *query_args = (void *)args;
|
513
543
|
mysql_client_wrapper *wrapper = query_args->wrapper;
|
514
|
-
if ((VALUE)rb_thread_call_without_gvl(nogvl_send_query,
|
544
|
+
if ((VALUE)rb_thread_call_without_gvl(nogvl_send_query, query_args, RUBY_UBF_IO, 0) == Qfalse) {
|
515
545
|
/* an error occurred, we're not active anymore */
|
516
546
|
wrapper->active_thread = Qnil;
|
517
547
|
rb_raise_mysql2_error(wrapper);
|
@@ -579,7 +609,7 @@ static VALUE rb_mysql_client_async_result(VALUE self) {
|
|
579
609
|
rb_raise_mysql2_error(wrapper);
|
580
610
|
}
|
581
611
|
|
582
|
-
is_streaming = rb_hash_aref(
|
612
|
+
is_streaming = rb_hash_aref(rb_ivar_get(self, intern_current_query_options), sym_stream);
|
583
613
|
if (is_streaming == Qtrue) {
|
584
614
|
result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_use_result, wrapper, RUBY_UBF_IO, 0);
|
585
615
|
} else {
|
@@ -596,7 +626,7 @@ static VALUE rb_mysql_client_async_result(VALUE self) {
|
|
596
626
|
}
|
597
627
|
|
598
628
|
// Duplicate the options hash and put the copy in the Result object
|
599
|
-
current = rb_hash_dup(
|
629
|
+
current = rb_hash_dup(rb_ivar_get(self, intern_current_query_options));
|
600
630
|
(void)RB_GC_GUARD(current);
|
601
631
|
Check_Type(current, T_HASH);
|
602
632
|
resultObj = rb_mysql_result_to_obj(self, wrapper->encoding, current, result, Qnil);
|
@@ -631,15 +661,15 @@ static VALUE disconnect_and_raise(VALUE self, VALUE error) {
|
|
631
661
|
rb_exc_raise(error);
|
632
662
|
}
|
633
663
|
|
634
|
-
static VALUE do_query(
|
635
|
-
struct async_query_args *async_args = args;
|
664
|
+
static VALUE do_query(VALUE args) {
|
665
|
+
struct async_query_args *async_args = (void *)args;
|
636
666
|
struct timeval tv;
|
637
667
|
struct timeval *tvp;
|
638
668
|
long int sec;
|
639
669
|
int retval;
|
640
670
|
VALUE read_timeout;
|
641
671
|
|
642
|
-
read_timeout =
|
672
|
+
read_timeout = rb_ivar_get(async_args->self, intern_read_timeout);
|
643
673
|
|
644
674
|
tvp = NULL;
|
645
675
|
if (!NIL_P(read_timeout)) {
|
@@ -767,7 +797,7 @@ static VALUE rb_mysql_query(VALUE self, VALUE sql, VALUE current) {
|
|
767
797
|
|
768
798
|
(void)RB_GC_GUARD(current);
|
769
799
|
Check_Type(current, T_HASH);
|
770
|
-
|
800
|
+
rb_ivar_set(self, intern_current_query_options, current);
|
771
801
|
|
772
802
|
Check_Type(sql, T_STRING);
|
773
803
|
/* ensure the string is in the encoding the connection is expecting */
|
@@ -780,6 +810,7 @@ static VALUE rb_mysql_query(VALUE self, VALUE sql, VALUE current) {
|
|
780
810
|
|
781
811
|
#ifndef _WIN32
|
782
812
|
rb_rescue2(do_send_query, (VALUE)&args, disconnect_and_raise, self, rb_eException, (VALUE)0);
|
813
|
+
(void)RB_GC_GUARD(sql);
|
783
814
|
|
784
815
|
if (rb_hash_aref(current, sym_async) == Qtrue) {
|
785
816
|
return Qnil;
|
@@ -792,7 +823,8 @@ static VALUE rb_mysql_query(VALUE self, VALUE sql, VALUE current) {
|
|
792
823
|
return rb_ensure(rb_mysql_client_async_result, self, disconnect_and_mark_inactive, self);
|
793
824
|
}
|
794
825
|
#else
|
795
|
-
do_send_query(&args);
|
826
|
+
do_send_query((VALUE)&args);
|
827
|
+
(void)RB_GC_GUARD(sql);
|
796
828
|
|
797
829
|
/* this will just block until the result is ready */
|
798
830
|
return rb_ensure(rb_mysql_client_async_result, self, disconnect_and_mark_inactive, self);
|
@@ -903,6 +935,13 @@ static VALUE _mysql_client_options(VALUE self, int opt, VALUE value) {
|
|
903
935
|
retval = charval;
|
904
936
|
break;
|
905
937
|
|
938
|
+
#ifdef HAVE_MYSQL_DEFAULT_AUTH
|
939
|
+
case MYSQL_DEFAULT_AUTH:
|
940
|
+
charval = (const char *)StringValueCStr(value);
|
941
|
+
retval = charval;
|
942
|
+
break;
|
943
|
+
#endif
|
944
|
+
|
906
945
|
#ifdef HAVE_CONST_MYSQL_ENABLE_CLEARTEXT_PLUGIN
|
907
946
|
case MYSQL_ENABLE_CLEARTEXT_PLUGIN:
|
908
947
|
boolval = (value == Qfalse ? 0 : 1);
|
@@ -1011,6 +1050,36 @@ static VALUE rb_mysql_client_last_id(VALUE self) {
|
|
1011
1050
|
return ULL2NUM(mysql_insert_id(wrapper->client));
|
1012
1051
|
}
|
1013
1052
|
|
1053
|
+
/* call-seq:
|
1054
|
+
* client.session_track
|
1055
|
+
*
|
1056
|
+
* Returns information about changes to the session state on the server.
|
1057
|
+
*/
|
1058
|
+
static VALUE rb_mysql_client_session_track(VALUE self, VALUE type) {
|
1059
|
+
#ifdef CLIENT_SESSION_TRACK
|
1060
|
+
const char *data;
|
1061
|
+
size_t length;
|
1062
|
+
my_ulonglong retVal;
|
1063
|
+
GET_CLIENT(self);
|
1064
|
+
|
1065
|
+
REQUIRE_CONNECTED(wrapper);
|
1066
|
+
retVal = mysql_session_track_get_first(wrapper->client, NUM2INT(type), &data, &length);
|
1067
|
+
if (retVal != 0) {
|
1068
|
+
return Qnil;
|
1069
|
+
}
|
1070
|
+
VALUE rbAry = rb_ary_new();
|
1071
|
+
VALUE rbFirst = rb_str_new(data, length);
|
1072
|
+
rb_ary_push(rbAry, rbFirst);
|
1073
|
+
while(mysql_session_track_get_next(wrapper->client, NUM2INT(type), &data, &length) == 0) {
|
1074
|
+
VALUE rbNext = rb_str_new(data, length);
|
1075
|
+
rb_ary_push(rbAry, rbNext);
|
1076
|
+
}
|
1077
|
+
return rbAry;
|
1078
|
+
#else
|
1079
|
+
return Qnil;
|
1080
|
+
#endif
|
1081
|
+
}
|
1082
|
+
|
1014
1083
|
/* call-seq:
|
1015
1084
|
* client.affected_rows
|
1016
1085
|
*
|
@@ -1174,7 +1243,7 @@ static VALUE rb_mysql_client_store_result(VALUE self)
|
|
1174
1243
|
}
|
1175
1244
|
|
1176
1245
|
// Duplicate the options hash and put the copy in the Result object
|
1177
|
-
current = rb_hash_dup(
|
1246
|
+
current = rb_hash_dup(rb_ivar_get(self, intern_current_query_options));
|
1178
1247
|
(void)RB_GC_GUARD(current);
|
1179
1248
|
Check_Type(current, T_HASH);
|
1180
1249
|
resultObj = rb_mysql_result_to_obj(self, wrapper->encoding, current, result, Qnil);
|
@@ -1260,7 +1329,7 @@ static VALUE set_read_timeout(VALUE self, VALUE value) {
|
|
1260
1329
|
/* Set the instance variable here even though _mysql_client_options
|
1261
1330
|
might not succeed, because the timeout is used in other ways
|
1262
1331
|
elsewhere */
|
1263
|
-
|
1332
|
+
rb_ivar_set(self, intern_read_timeout, value);
|
1264
1333
|
return _mysql_client_options(self, MYSQL_OPT_READ_TIMEOUT, value);
|
1265
1334
|
}
|
1266
1335
|
|
@@ -1336,6 +1405,14 @@ static VALUE set_init_command(VALUE self, VALUE value) {
|
|
1336
1405
|
return _mysql_client_options(self, MYSQL_INIT_COMMAND, value);
|
1337
1406
|
}
|
1338
1407
|
|
1408
|
+
static VALUE set_default_auth(VALUE self, VALUE value) {
|
1409
|
+
#ifdef HAVE_MYSQL_DEFAULT_AUTH
|
1410
|
+
return _mysql_client_options(self, MYSQL_DEFAULT_AUTH, value);
|
1411
|
+
#else
|
1412
|
+
rb_raise(cMysql2Error, "pluggable authentication is not available, you may need a newer MySQL client library");
|
1413
|
+
#endif
|
1414
|
+
}
|
1415
|
+
|
1339
1416
|
static VALUE set_enable_cleartext_plugin(VALUE self, VALUE value) {
|
1340
1417
|
#ifdef HAVE_CONST_MYSQL_ENABLE_CLEARTEXT_PLUGIN
|
1341
1418
|
return _mysql_client_options(self, MYSQL_ENABLE_CLEARTEXT_PLUGIN, value);
|
@@ -1397,6 +1474,7 @@ void init_mysql2_client() {
|
|
1397
1474
|
mMysql2 = rb_define_module("Mysql2"); Teach RDoc about Mysql2 constant.
|
1398
1475
|
#endif
|
1399
1476
|
cMysql2Client = rb_define_class_under(mMysql2, "Client", rb_cObject);
|
1477
|
+
rb_global_variable(&cMysql2Client);
|
1400
1478
|
|
1401
1479
|
rb_define_alloc_func(cMysql2Client, allocate);
|
1402
1480
|
|
@@ -1427,6 +1505,7 @@ void init_mysql2_client() {
|
|
1427
1505
|
rb_define_method(cMysql2Client, "query_info_string", rb_mysql_info, 0);
|
1428
1506
|
rb_define_method(cMysql2Client, "ssl_cipher", rb_mysql_get_ssl_cipher, 0);
|
1429
1507
|
rb_define_method(cMysql2Client, "encoding", rb_mysql_client_encoding, 0);
|
1508
|
+
rb_define_method(cMysql2Client, "session_track", rb_mysql_client_session_track, 1);
|
1430
1509
|
|
1431
1510
|
rb_define_private_method(cMysql2Client, "connect_timeout=", set_connect_timeout, 1);
|
1432
1511
|
rb_define_private_method(cMysql2Client, "read_timeout=", set_read_timeout, 1);
|
@@ -1437,6 +1516,7 @@ void init_mysql2_client() {
|
|
1437
1516
|
rb_define_private_method(cMysql2Client, "default_file=", set_read_default_file, 1);
|
1438
1517
|
rb_define_private_method(cMysql2Client, "default_group=", set_read_default_group, 1);
|
1439
1518
|
rb_define_private_method(cMysql2Client, "init_command=", set_init_command, 1);
|
1519
|
+
rb_define_private_method(cMysql2Client, "default_auth=", set_default_auth, 1);
|
1440
1520
|
rb_define_private_method(cMysql2Client, "ssl_set", set_ssl_options, 5);
|
1441
1521
|
rb_define_private_method(cMysql2Client, "ssl_mode=", rb_set_ssl_mode_option, 1);
|
1442
1522
|
rb_define_private_method(cMysql2Client, "enable_cleartext_plugin=", set_enable_cleartext_plugin, 1);
|
@@ -1461,6 +1541,8 @@ void init_mysql2_client() {
|
|
1461
1541
|
intern_merge = rb_intern("merge");
|
1462
1542
|
intern_merge_bang = rb_intern("merge!");
|
1463
1543
|
intern_new_with_args = rb_intern("new_with_args");
|
1544
|
+
intern_current_query_options = rb_intern("@current_query_options");
|
1545
|
+
intern_read_timeout = rb_intern("@read_timeout");
|
1464
1546
|
|
1465
1547
|
#ifdef CLIENT_LONG_PASSWORD
|
1466
1548
|
rb_const_set(cMysql2Client, rb_intern("LONG_PASSWORD"),
|
@@ -1596,16 +1678,32 @@ void init_mysql2_client() {
|
|
1596
1678
|
INT2NUM(0));
|
1597
1679
|
#endif
|
1598
1680
|
|
1681
|
+
#ifdef CLIENT_SESSION_TRACK
|
1682
|
+
rb_const_set(cMysql2Client, rb_intern("SESSION_TRACK"), INT2NUM(CLIENT_SESSION_TRACK));
|
1683
|
+
/* From mysql_com.h -- but stable from at least 5.7.4 through 8.0.20 */
|
1684
|
+
rb_const_set(cMysql2Client, rb_intern("SESSION_TRACK_SYSTEM_VARIABLES"), INT2NUM(SESSION_TRACK_SYSTEM_VARIABLES));
|
1685
|
+
rb_const_set(cMysql2Client, rb_intern("SESSION_TRACK_SCHEMA"), INT2NUM(SESSION_TRACK_SCHEMA));
|
1686
|
+
rb_const_set(cMysql2Client, rb_intern("SESSION_TRACK_STATE_CHANGE"), INT2NUM(SESSION_TRACK_STATE_CHANGE));
|
1687
|
+
rb_const_set(cMysql2Client, rb_intern("SESSION_TRACK_GTIDS"), INT2NUM(SESSION_TRACK_GTIDS));
|
1688
|
+
rb_const_set(cMysql2Client, rb_intern("SESSION_TRACK_TRANSACTION_CHARACTERISTICS"), INT2NUM(SESSION_TRACK_TRANSACTION_CHARACTERISTICS));
|
1689
|
+
rb_const_set(cMysql2Client, rb_intern("SESSION_TRACK_TRANSACTION_STATE"), INT2NUM(SESSION_TRACK_TRANSACTION_STATE));
|
1690
|
+
#endif
|
1691
|
+
|
1599
1692
|
#if defined(FULL_SSL_MODE_SUPPORT) // MySQL 5.7.11 and above
|
1600
1693
|
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_DISABLED"), INT2NUM(SSL_MODE_DISABLED));
|
1601
1694
|
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_PREFERRED"), INT2NUM(SSL_MODE_PREFERRED));
|
1602
1695
|
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_REQUIRED"), INT2NUM(SSL_MODE_REQUIRED));
|
1603
1696
|
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_VERIFY_CA"), INT2NUM(SSL_MODE_VERIFY_CA));
|
1604
1697
|
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_VERIFY_IDENTITY"), INT2NUM(SSL_MODE_VERIFY_IDENTITY));
|
1605
|
-
#
|
1698
|
+
#else
|
1699
|
+
#ifdef HAVE_CONST_MYSQL_OPT_SSL_VERIFY_SERVER_CERT // MySQL 5.7.3 - 5.7.10 & MariaDB 10.x and later
|
1700
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_VERIFY_IDENTITY"), INT2NUM(SSL_MODE_VERIFY_IDENTITY));
|
1701
|
+
#endif
|
1702
|
+
#ifdef HAVE_CONST_MYSQL_OPT_SSL_ENFORCE // MySQL 5.7.3 - 5.7.10 & MariaDB 10.x and later
|
1606
1703
|
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_DISABLED"), INT2NUM(SSL_MODE_DISABLED));
|
1607
1704
|
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_REQUIRED"), INT2NUM(SSL_MODE_REQUIRED));
|
1608
1705
|
#endif
|
1706
|
+
#endif
|
1609
1707
|
|
1610
1708
|
#ifndef HAVE_CONST_SSL_MODE_DISABLED
|
1611
1709
|
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_DISABLED"), INT2NUM(0));
|