mysql2 0.4.2 → 0.5.2
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 +4 -4
- data/README.md +103 -59
- data/examples/eventmachine.rb +0 -2
- data/examples/threaded.rb +2 -4
- data/ext/mysql2/client.c +334 -94
- data/ext/mysql2/client.h +3 -51
- data/ext/mysql2/extconf.rb +45 -18
- data/ext/mysql2/mysql2_ext.c +2 -1
- data/ext/mysql2/mysql2_ext.h +8 -8
- data/ext/mysql2/mysql_enc_to_ruby.h +10 -0
- data/ext/mysql2/result.c +53 -94
- data/ext/mysql2/statement.c +191 -83
- data/ext/mysql2/statement.h +0 -2
- data/ext/mysql2/wait_for_single_fd.h +2 -1
- data/lib/mysql2/client.rb +50 -31
- data/lib/mysql2/em.rb +2 -4
- data/lib/mysql2/error.rb +49 -20
- data/lib/mysql2/result.rb +2 -0
- data/lib/mysql2/statement.rb +3 -9
- data/lib/mysql2/version.rb +1 -1
- data/lib/mysql2.rb +14 -15
- data/spec/configuration.yml.example +0 -6
- data/spec/em/em_spec.rb +6 -6
- data/spec/mysql2/client_spec.rb +372 -239
- data/spec/mysql2/error_spec.rb +4 -10
- data/spec/mysql2/result_spec.rb +132 -157
- data/spec/mysql2/statement_spec.rb +205 -177
- data/spec/spec_helper.rb +79 -61
- data/spec/ssl/gen_certs.sh +1 -1
- data/support/5072E1F5.asc +432 -0
- data/support/mysql_enc_to_ruby.rb +2 -2
- data/support/ruby_enc_to_mysql.rb +5 -5
- metadata +16 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 62ba5d2530e40ed2dcefd98c2219c95b166a7385
|
4
|
+
data.tar.gz: c17840a416a95f241cd9259c57aaacac100d17f8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50d8ecc5c61d004953d4da51b69ca0d8166c1c665757f677eedea84c62173490a6b0b1b67cec9e661397306fb0607930f6cf5b062fd8f77c2d9c2ea02b8d2d69
|
7
|
+
data.tar.gz: d62e82ffffe4e1a84d37f1a3745c58c0d5b0f88d0cc1403b93a452a0af454e6aa1a49653cb70b494b092ffa7f924ed66293c58ec0ddbe2e8497eedcf631ffd7c
|
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
|
|
@@ -74,10 +74,11 @@ To see line numbers in backtraces, declare these environment variables
|
|
74
74
|
|
75
75
|
### Linux and other Unixes
|
76
76
|
|
77
|
-
You may need to install a package such as `libmysqlclient-dev
|
78
|
-
refer to your distribution's package guide to
|
79
|
-
The most common issue we see is a user who has
|
80
|
-
|
77
|
+
You may need to install a package such as `libmysqlclient-dev`, `mysql-devel`,
|
78
|
+
or `default-libmysqlclient-dev`; refer to your distribution's package guide to
|
79
|
+
find the particular package. The most common issue we see is a user who has
|
80
|
+
the library file `libmysqlclient.so` but is missing the header file `mysql.h`
|
81
|
+
-- double check that you have the _-dev_ packages installed.
|
81
82
|
|
82
83
|
### Mac OS X
|
83
84
|
|
@@ -85,6 +86,9 @@ You may use MacPorts, Homebrew, or a native MySQL installer package. The most
|
|
85
86
|
common paths will be automatically searched. If you want to select a specific
|
86
87
|
MySQL directory, use the `--with-mysql-dir` or `--with-mysql-config` options above.
|
87
88
|
|
89
|
+
If you have not done so already, you will need to install the XCode select tools by running
|
90
|
+
`xcode-select --install`.
|
91
|
+
|
88
92
|
### Windows
|
89
93
|
Make sure that you have Ruby and the DevKit compilers installed. We recommend
|
90
94
|
the [Ruby Installer](http://rubyinstaller.org) distribution.
|
@@ -109,7 +113,7 @@ Connect to a database:
|
|
109
113
|
``` ruby
|
110
114
|
# this takes a hash of options, almost all of which map directly
|
111
115
|
# to the familiar database.yml in rails
|
112
|
-
# See http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/
|
116
|
+
# See http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Mysql2Adapter.html
|
113
117
|
client = Mysql2::Client.new(:host => "localhost", :username => "root")
|
114
118
|
```
|
115
119
|
|
@@ -135,7 +139,7 @@ results.each do |row|
|
|
135
139
|
# conveniently, row is a hash
|
136
140
|
# the keys are the fields, as you'd expect
|
137
141
|
# the values are pre-built ruby primitives mapped from their corresponding field types in MySQL
|
138
|
-
puts row["id"] # row["id"].
|
142
|
+
puts row["id"] # row["id"].is_a? Integer
|
139
143
|
if row["dne"] # non-existant hash entry is nil
|
140
144
|
puts row["dne"]
|
141
145
|
end
|
@@ -164,15 +168,19 @@ by the query like this:
|
|
164
168
|
``` ruby
|
165
169
|
headers = results.fields # <= that's an array of field names, in order
|
166
170
|
results.each(:as => :array) do |row|
|
167
|
-
# Each row is an array, ordered the same as the query results
|
168
|
-
# An otter's den is called a "holt" or "couch"
|
171
|
+
# Each row is an array, ordered the same as the query results
|
172
|
+
# An otter's den is called a "holt" or "couch"
|
169
173
|
end
|
170
174
|
```
|
171
175
|
|
172
176
|
Prepared statements are supported, as well. In a prepared statement, use a `?`
|
173
177
|
in place of each value and then execute the statement to retrieve a result set.
|
174
178
|
Pass your arguments to the execute method in the same number and order as the
|
175
|
-
question marks in the statement.
|
179
|
+
question marks in the statement. Query options can be passed as keyword arguments
|
180
|
+
to the execute method.
|
181
|
+
|
182
|
+
Be sure to read about the known limitations of prepared statements at
|
183
|
+
https://dev.mysql.com/doc/refman/5.6/en/c-api-prepared-statement-problems.html
|
176
184
|
|
177
185
|
``` ruby
|
178
186
|
statement = @client.prepare("SELECT * FROM users WHERE login_count = ?")
|
@@ -181,6 +189,9 @@ result2 = statement.execute(2)
|
|
181
189
|
|
182
190
|
statement = @client.prepare("SELECT * FROM users WHERE last_login >= ? AND location LIKE ?")
|
183
191
|
result = statement.execute(1, "CA")
|
192
|
+
|
193
|
+
statement = @client.prepare("SELECT * FROM users WHERE last_login >= ? AND location LIKE ?")
|
194
|
+
result = statement.execute(1, "CA", :as => :array)
|
184
195
|
```
|
185
196
|
|
186
197
|
## Connection options
|
@@ -200,15 +211,29 @@ Mysql2::Client.new(
|
|
200
211
|
:read_timeout = seconds,
|
201
212
|
:write_timeout = seconds,
|
202
213
|
:connect_timeout = seconds,
|
214
|
+
:connect_attrs = {:program_name => $PROGRAM_NAME, ...},
|
203
215
|
:reconnect = true/false,
|
204
216
|
:local_infile = true/false,
|
205
217
|
:secure_auth = true/false,
|
218
|
+
:ssl_mode = :disabled / :preferred / :required / :verify_ca / :verify_identity,
|
206
219
|
:default_file = '/path/to/my.cfg',
|
207
220
|
:default_group = 'my.cfg section',
|
208
221
|
:init_command => sql
|
209
222
|
)
|
210
223
|
```
|
211
224
|
|
225
|
+
### Connecting to MySQL on localhost and elsewhere
|
226
|
+
|
227
|
+
The underlying MySQL client library uses the `:host` parameter to determine the
|
228
|
+
type of connection to make, with special interpretation you should be aware of:
|
229
|
+
|
230
|
+
* An empty value or `"localhost"` will attempt a local connection:
|
231
|
+
* On Unix, connect to the default local socket path. (To set a custom socket
|
232
|
+
path, use the `:socket` parameter).
|
233
|
+
* On Windows, connect using a shared-memory connection, if enabled, or TCP.
|
234
|
+
* A value of `"."` on Windows specifies a named-pipe connection.
|
235
|
+
* An IPv4 or IPv6 address will result in a TCP connection.
|
236
|
+
* Any other value will be looked up as a hostname for a TCP connection.
|
212
237
|
|
213
238
|
### SSL options
|
214
239
|
|
@@ -231,47 +256,6 @@ Mysql2::Client.new(
|
|
231
256
|
)
|
232
257
|
```
|
233
258
|
|
234
|
-
### Multiple result sets
|
235
|
-
|
236
|
-
You can also retrieve multiple result sets. For this to work you need to
|
237
|
-
connect with flags `Mysql2::Client::MULTI_STATEMENTS`. Multiple result sets can
|
238
|
-
be used with stored procedures that return more than one result set, and for
|
239
|
-
bundling several SQL statements into a single call to `client.query`.
|
240
|
-
|
241
|
-
``` ruby
|
242
|
-
client = Mysql2::Client.new(:host => "localhost", :username => "root", :flags => Mysql2::Client::MULTI_STATEMENTS)
|
243
|
-
result = client.query('CALL sp_customer_list( 25, 10 )')
|
244
|
-
# result now contains the first result set
|
245
|
-
while client.next_result
|
246
|
-
result = client.store_result
|
247
|
-
# result now contains the next result set
|
248
|
-
end
|
249
|
-
```
|
250
|
-
|
251
|
-
Repeated calls to `client.next_result` will return true, false, or raise an
|
252
|
-
exception if the respective query erred. When `client.next_result` returns true,
|
253
|
-
call `client.store_result` to retrieve a result object. Exceptions are not
|
254
|
-
raised until `client.next_result` is called to find the status of the respective
|
255
|
-
query. Subsequent queries are not executed if an earlier query raised an
|
256
|
-
exception. Subsequent calls to `client.next_result` will return false.
|
257
|
-
|
258
|
-
``` ruby
|
259
|
-
result = client.query('SELECT 1; SELECT 2; SELECT A; SELECT 3')
|
260
|
-
p result.first
|
261
|
-
|
262
|
-
while client.next_result
|
263
|
-
result = client.store_result
|
264
|
-
p result.first
|
265
|
-
end
|
266
|
-
```
|
267
|
-
|
268
|
-
Yields:
|
269
|
-
```
|
270
|
-
{"1"=>1}
|
271
|
-
{"2"=>2}
|
272
|
-
next_result: Unknown column 'A' in 'field list' (Mysql2::Error)
|
273
|
-
```
|
274
|
-
|
275
259
|
### Secure auth
|
276
260
|
|
277
261
|
Starting wih MySQL 5.6.5, secure_auth is enabled by default on servers (it was disabled by default prior to this).
|
@@ -328,6 +312,47 @@ It is useful if you want to provide session options which survive reconnection.
|
|
328
312
|
Mysql2::Client.new(:init_command => "SET @@SESSION.sql_mode = 'STRICT_ALL_TABLES'")
|
329
313
|
```
|
330
314
|
|
315
|
+
### Multiple result sets
|
316
|
+
|
317
|
+
You can also retrieve multiple result sets. For this to work you need to
|
318
|
+
connect with flags `Mysql2::Client::MULTI_STATEMENTS`. Multiple result sets can
|
319
|
+
be used with stored procedures that return more than one result set, and for
|
320
|
+
bundling several SQL statements into a single call to `client.query`.
|
321
|
+
|
322
|
+
``` ruby
|
323
|
+
client = Mysql2::Client.new(:host => "localhost", :username => "root", :flags => Mysql2::Client::MULTI_STATEMENTS)
|
324
|
+
result = client.query('CALL sp_customer_list( 25, 10 )')
|
325
|
+
# result now contains the first result set
|
326
|
+
while client.next_result
|
327
|
+
result = client.store_result
|
328
|
+
# result now contains the next result set
|
329
|
+
end
|
330
|
+
```
|
331
|
+
|
332
|
+
Repeated calls to `client.next_result` will return true, false, or raise an
|
333
|
+
exception if the respective query erred. When `client.next_result` returns true,
|
334
|
+
call `client.store_result` to retrieve a result object. Exceptions are not
|
335
|
+
raised until `client.next_result` is called to find the status of the respective
|
336
|
+
query. Subsequent queries are not executed if an earlier query raised an
|
337
|
+
exception. Subsequent calls to `client.next_result` will return false.
|
338
|
+
|
339
|
+
``` ruby
|
340
|
+
result = client.query('SELECT 1; SELECT 2; SELECT A; SELECT 3')
|
341
|
+
p result.first
|
342
|
+
|
343
|
+
while client.next_result
|
344
|
+
result = client.store_result
|
345
|
+
p result.first
|
346
|
+
end
|
347
|
+
```
|
348
|
+
|
349
|
+
Yields:
|
350
|
+
```
|
351
|
+
{"1"=>1}
|
352
|
+
{"2"=>2}
|
353
|
+
next_result: Unknown column 'A' in 'field list' (Mysql2::Error)
|
354
|
+
```
|
355
|
+
|
331
356
|
## Cascading config
|
332
357
|
|
333
358
|
The default config hash is at:
|
@@ -365,6 +390,15 @@ c = Mysql2::Client.new
|
|
365
390
|
c.query(sql, :symbolize_keys => true)
|
366
391
|
```
|
367
392
|
|
393
|
+
or
|
394
|
+
|
395
|
+
``` ruby
|
396
|
+
# this will set the options for the Mysql2::Result instance returned from the #execute method
|
397
|
+
c = Mysql2::Client.new
|
398
|
+
s = c.prepare(sql)
|
399
|
+
s.execute(arg1, args2, :symbolize_keys => true)
|
400
|
+
```
|
401
|
+
|
368
402
|
## Result types
|
369
403
|
|
370
404
|
### Array of Arrays
|
@@ -398,6 +432,15 @@ client = Mysql2::Client.new
|
|
398
432
|
result = client.query("SELECT * FROM table_with_boolean_field", :cast_booleans => true)
|
399
433
|
```
|
400
434
|
|
435
|
+
Keep in mind that this works only with fields and not with computed values, e.g. this result will contain `1`, not `true`:
|
436
|
+
|
437
|
+
``` ruby
|
438
|
+
client = Mysql2::Client.new
|
439
|
+
result = client.query("SELECT true", :cast_booleans => true)
|
440
|
+
```
|
441
|
+
|
442
|
+
CAST function wouldn't help here as there's no way to cast to TINYINT(1). Apparently the only way to solve this is to use a stored procedure with return type set to TINYINT(1).
|
443
|
+
|
401
444
|
### Skipping casting
|
402
445
|
|
403
446
|
Mysql2 casting is fast, but not as fast as not casting data. In rare cases where typecasting is not needed, it will be faster to disable it by providing :cast => false. (Note that :cast => false overrides :cast_booleans => true.)
|
@@ -484,20 +527,21 @@ As for field values themselves, I'm workin on it - but expect that soon.
|
|
484
527
|
|
485
528
|
This gem is tested with the following Ruby versions on Linux and Mac OS X:
|
486
529
|
|
487
|
-
* Ruby MRI
|
488
|
-
*
|
489
|
-
* Rubinius 2.x
|
530
|
+
* Ruby MRI 2.0.0, 2.1.x, 2.2.x, 2.3.x, 2.4.x, 2.5.x, 2.6.x
|
531
|
+
* Rubinius 2.x and 3.x do work but may fail under some workloads
|
490
532
|
|
491
533
|
This gem is tested with the following MySQL and MariaDB versions:
|
492
534
|
|
493
|
-
* MySQL 5.5, 5.7
|
535
|
+
* MySQL 5.5, 5.6, 5.7, 8.0
|
494
536
|
* MySQL Connector/C 6.0 and 6.1 (primarily on Windows)
|
495
|
-
* MariaDB 5.5, 10.0
|
537
|
+
* MariaDB 5.5, 10.0, 10.1, 10.2, 10.3
|
496
538
|
|
497
|
-
### Active Record
|
539
|
+
### Ruby on Rails / Active Record
|
498
540
|
|
499
|
-
* mysql2 0.
|
500
|
-
* mysql2 0.
|
541
|
+
* mysql2 0.5.x works with Rails / Active Record 5.0.7, 5.1.6, and higher.
|
542
|
+
* mysql2 0.4.x works with Rails / Active Record 4.2.5 - 5.0 and higher.
|
543
|
+
* mysql2 0.3.x works with Rails / Active Record 3.1, 3.2, 4.x, 5.0.
|
544
|
+
* mysql2 0.2.x works with Rails / Active Record 2.3 - 3.0.
|
501
545
|
|
502
546
|
### Asynchronous Active Record
|
503
547
|
|
data/examples/eventmachine.rb
CHANGED
data/examples/threaded.rb
CHANGED
@@ -1,17 +1,15 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
$LOAD_PATH.unshift 'lib'
|
4
2
|
require 'mysql2'
|
5
3
|
require 'timeout'
|
6
4
|
|
7
5
|
# Should never exceed worst case 3.5 secs across all 20 threads
|
8
6
|
Timeout.timeout(3.5) do
|
9
|
-
20
|
7
|
+
Array.new(20) do
|
10
8
|
Thread.new do
|
11
9
|
overhead = rand(3)
|
12
10
|
puts ">> thread #{Thread.current.object_id} query, #{overhead} sec overhead"
|
13
11
|
# 3 second overhead per query
|
14
|
-
Mysql2::Client.new(:
|
12
|
+
Mysql2::Client.new(host: "localhost", username: "root").query("SELECT sleep(#{overhead}) as result")
|
15
13
|
puts "<< thread #{Thread.current.object_id} result, #{overhead} sec overhead"
|
16
14
|
end
|
17
15
|
end.each(&:join)
|