mysql2 0.3.8 → 0.4.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1 -220
  3. data/LICENSE +21 -0
  4. data/README.md +370 -79
  5. data/examples/eventmachine.rb +1 -1
  6. data/examples/threaded.rb +4 -6
  7. data/ext/mysql2/client.c +1017 -305
  8. data/ext/mysql2/client.h +35 -11
  9. data/ext/mysql2/extconf.rb +222 -34
  10. data/ext/mysql2/infile.c +122 -0
  11. data/ext/mysql2/infile.h +1 -0
  12. data/ext/mysql2/mysql2_ext.c +1 -0
  13. data/ext/mysql2/mysql2_ext.h +12 -14
  14. data/ext/mysql2/mysql_enc_name_to_ruby.h +168 -0
  15. data/ext/mysql2/mysql_enc_to_ruby.h +249 -0
  16. data/ext/mysql2/result.c +664 -166
  17. data/ext/mysql2/result.h +16 -6
  18. data/ext/mysql2/statement.c +595 -0
  19. data/ext/mysql2/statement.h +19 -0
  20. data/lib/mysql2/client.rb +118 -211
  21. data/lib/mysql2/console.rb +5 -0
  22. data/lib/mysql2/em.rb +23 -5
  23. data/lib/mysql2/error.rb +62 -6
  24. data/lib/mysql2/field.rb +3 -0
  25. data/lib/mysql2/statement.rb +17 -0
  26. data/lib/mysql2/version.rb +1 -1
  27. data/lib/mysql2.rb +66 -3
  28. data/spec/configuration.yml.example +11 -0
  29. data/spec/em/em_spec.rb +96 -10
  30. data/spec/my.cnf.example +9 -0
  31. data/spec/mysql2/client_spec.rb +779 -205
  32. data/spec/mysql2/error_spec.rb +58 -45
  33. data/spec/mysql2/result_spec.rb +316 -159
  34. data/spec/mysql2/statement_spec.rb +776 -0
  35. data/spec/spec_helper.rb +97 -56
  36. data/spec/ssl/ca-cert.pem +17 -0
  37. data/spec/ssl/ca-key.pem +27 -0
  38. data/spec/ssl/ca.cnf +22 -0
  39. data/spec/ssl/cert.cnf +22 -0
  40. data/spec/ssl/client-cert.pem +17 -0
  41. data/spec/ssl/client-key.pem +27 -0
  42. data/spec/ssl/client-req.pem +15 -0
  43. data/spec/ssl/gen_certs.sh +48 -0
  44. data/spec/ssl/pkcs8-client-key.pem +28 -0
  45. data/spec/ssl/pkcs8-server-key.pem +28 -0
  46. data/spec/ssl/server-cert.pem +17 -0
  47. data/spec/ssl/server-key.pem +27 -0
  48. data/spec/ssl/server-req.pem +15 -0
  49. data/spec/test_data +1 -0
  50. data/support/5072E1F5.asc +432 -0
  51. data/support/libmysql.def +219 -0
  52. data/support/mysql_enc_to_ruby.rb +81 -0
  53. data/support/ruby_enc_to_mysql.rb +61 -0
  54. metadata +77 -196
  55. data/.gitignore +0 -12
  56. data/.rspec +0 -3
  57. data/.rvmrc +0 -1
  58. data/.travis.yml +0 -7
  59. data/Gemfile +0 -3
  60. data/MIT-LICENSE +0 -20
  61. data/Rakefile +0 -5
  62. data/benchmark/active_record.rb +0 -51
  63. data/benchmark/active_record_threaded.rb +0 -42
  64. data/benchmark/allocations.rb +0 -33
  65. data/benchmark/escape.rb +0 -36
  66. data/benchmark/query_with_mysql_casting.rb +0 -80
  67. data/benchmark/query_without_mysql_casting.rb +0 -56
  68. data/benchmark/sequel.rb +0 -37
  69. data/benchmark/setup_db.rb +0 -119
  70. data/benchmark/threaded.rb +0 -44
  71. data/mysql2.gemspec +0 -29
  72. data/tasks/benchmarks.rake +0 -20
  73. data/tasks/compile.rake +0 -71
  74. data/tasks/rspec.rake +0 -16
  75. data/tasks/vendor_mysql.rake +0 -40
data/README.md CHANGED
@@ -1,24 +1,109 @@
1
- # Mysql2 - A modern, simple and very fast Mysql library for Ruby - binding to libmysql
1
+ # Mysql2 - A modern, simple and very fast MySQL library for Ruby - binding to libmysql
2
+
3
+ Travis CI [![Travis CI Status](https://travis-ci.org/brianmario/mysql2.png)](https://travis-ci.org/brianmario/mysql2)
4
+ Appveyor CI [![Appveyor CI Status](https://ci.appveyor.com/api/projects/status/github/sodabrew/mysql2)](https://ci.appveyor.com/project/sodabrew/mysql2)
2
5
 
3
6
  The Mysql2 gem is meant to serve the extremely common use-case of connecting, querying and iterating on results.
4
- Some database libraries out there serve as direct 1:1 mappings of the already complex C API's available.
7
+ Some database libraries out there serve as direct 1:1 mappings of the already complex C APIs available.
5
8
  This one is not.
6
9
 
7
10
  It also forces the use of UTF-8 [or binary] for the connection [and all strings in 1.9, unless Encoding.default_internal is set then it'll convert from UTF-8 to that encoding] and uses encoding-aware MySQL API calls where it can.
8
11
 
9
- The API consists of two classes:
12
+ The API consists of three classes:
10
13
 
11
- Mysql2::Client - your connection to the database
14
+ `Mysql2::Client` - your connection to the database.
12
15
 
13
- Mysql2::Result - returned from issuing a #query on the connection. It includes Enumerable.
16
+ `Mysql2::Result` - returned from issuing a #query on the connection. It includes Enumerable.
14
17
 
15
- ## Installing
18
+ `Mysql2::Statement` - returned from issuing a #prepare on the connection. Execute the statement to get a Result.
16
19
 
20
+ ## Installing
21
+ ### General Instructions
17
22
  ``` sh
18
23
  gem install mysql2
19
24
  ```
20
25
 
21
- You may have to specify --with-mysql-config=/some/random/path/bin/mysql_config
26
+ This gem links against MySQL's `libmysqlclient` library or `Connector/C`
27
+ library, and compatible alternatives such as MariaDB.
28
+ You may need to install a package such as `libmysqlclient-dev`, `mysql-devel`,
29
+ or other appropriate package for your system. See below for system-specific
30
+ instructions.
31
+
32
+ By default, the mysql2 gem will try to find a copy of MySQL in this order:
33
+
34
+ * Option `--with-mysql-dir`, if provided (see below).
35
+ * Option `--with-mysql-config`, if provided (see below).
36
+ * Several typical paths for `mysql_config` (default for the majority of users).
37
+ * The directory `/usr/local`.
38
+
39
+ ### Configuration options
40
+
41
+ Use these options by `gem install mysql2 -- [--optionA] [--optionB=argument]`.
42
+
43
+ * `--with-mysql-dir[=/path/to/mysqldir]` -
44
+ Specify the directory where MySQL is installed. The mysql2 gem will not use
45
+ `mysql_config`, but will instead look at `mysqldir/lib` and `mysqldir/include`
46
+ for the library and header files.
47
+ This option is mutually exclusive with `--with-mysql-config`.
48
+
49
+ * `--with-mysql-config[=/path/to/mysql_config]` -
50
+ Specify a path to the `mysql_config` binary provided by your copy of MySQL. The
51
+ mysql2 gem will ask this `mysql_config` binary about the compiler and linker
52
+ arguments needed.
53
+ This option is mutually exclusive with `--with-mysql-dir`.
54
+
55
+ * `--with-mysql-rpath=/path/to/mysql/lib` / `--without-mysql-rpath` -
56
+ Override the runtime path used to find the MySQL libraries.
57
+ This may be needed if you deploy to a system where these libraries
58
+ are located somewhere different than on your build system.
59
+ This overrides any rpath calculated by default or by the options above.
60
+
61
+ * `--with-sanitize[=address,cfi,integer,memory,thread,undefined]` -
62
+ Enable sanitizers for Clang / GCC. If no argument is given, try to enable
63
+ all sanitizers or fail if none are available. If a command-separated list of
64
+ specific sanitizers is given, configure will fail unless they all are available.
65
+ Note that the some sanitizers may incur a performance penalty, and the Address
66
+ Sanitizer may require a runtime library.
67
+ To see line numbers in backtraces, declare these environment variables
68
+ (adjust the llvm-symbolizer path as needed for your system):
69
+
70
+ ``` sh
71
+ export ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer-3.4
72
+ export ASAN_OPTIONS=symbolize=1
73
+ ```
74
+
75
+ ### Linux and other Unixes
76
+
77
+ You may need to install a package such as `libmysqlclient-dev` or `mysql-devel`;
78
+ refer to your distribution's package guide to find the particular package.
79
+ The most common issue we see is a user who has the library file `libmysqlclient.so` but is
80
+ missing the header file `mysql.h` -- double check that you have the _-dev_ packages installed.
81
+
82
+ ### Mac OS X
83
+
84
+ You may use MacPorts, Homebrew, or a native MySQL installer package. The most
85
+ common paths will be automatically searched. If you want to select a specific
86
+ MySQL directory, use the `--with-mysql-dir` or `--with-mysql-config` options above.
87
+
88
+ If you have not done so already, you will need to install the XCode select tools by running
89
+ `xcode-select --install`.
90
+
91
+ ### Windows
92
+ Make sure that you have Ruby and the DevKit compilers installed. We recommend
93
+ the [Ruby Installer](http://rubyinstaller.org) distribution.
94
+
95
+ By default, the mysql2 gem will download and use MySQL Connector/C from
96
+ mysql.com. If you prefer to use a local installation of Connector/C, add the
97
+ flag `--with-mysql-dir=c:/mysql-connector-c-x-y-z` (_this path may use forward slashes_).
98
+
99
+ By default, the `libmysql.dll` library will be copied into the mysql2 gem
100
+ directory. To prevent this, add the flag `--no-vendor-libmysql`. The mysql2 gem
101
+ will search for `libmysql.dll` in the following paths, in order:
102
+
103
+ * Environment variable `RUBY_MYSQL2_LIBMYSQL_DLL=C:\path\to\libmysql.dll`
104
+ (_note the Windows-style backslashes_).
105
+ * In the mysql2 gem's own directory `vendor/libmysql.dll`
106
+ * In the system's default library search paths.
22
107
 
23
108
  ## Usage
24
109
 
@@ -27,7 +112,7 @@ Connect to a database:
27
112
  ``` ruby
28
113
  # this takes a hash of options, almost all of which map directly
29
114
  # to the familiar database.yml in rails
30
- # See http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/MysqlAdapter.html
115
+ # See http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Mysql2Adapter.html
31
116
  client = Mysql2::Client.new(:host => "localhost", :username => "root")
32
117
  ```
33
118
 
@@ -53,7 +138,10 @@ results.each do |row|
53
138
  # conveniently, row is a hash
54
139
  # the keys are the fields, as you'd expect
55
140
  # the values are pre-built ruby primitives mapped from their corresponding field types in MySQL
56
- # Here's an otter: http://farm1.static.flickr.com/130/398077070_b8795d0ef3_b.jpg
141
+ puts row["id"] # row["id"].class == Fixnum
142
+ if row["dne"] # non-existant hash entry is nil
143
+ puts row["dne"]
144
+ end
57
145
  end
58
146
  ```
59
147
 
@@ -68,8 +156,7 @@ end
68
156
  How about with symbolized keys?
69
157
 
70
158
  ``` ruby
71
- # NOTE: the :symbolize_keys and future options will likely move to the #query method soon
72
- client.query("SELECT * FROM users WHERE group='githubbers'").each(:symbolize_keys => true) do |row|
159
+ client.query("SELECT * FROM users WHERE group='githubbers'", :symbolize_keys => true) do |row|
73
160
  # do something with row, it's ready to rock
74
161
  end
75
162
  ```
@@ -80,11 +167,183 @@ by the query like this:
80
167
  ``` ruby
81
168
  headers = results.fields # <= that's an array of field names, in order
82
169
  results.each(:as => :array) do |row|
83
- # Each row is an array, ordered the same as the query results
84
- # An otter's den is called a "holt" or "couch"
170
+ # Each row is an array, ordered the same as the query results
171
+ # An otter's den is called a "holt" or "couch"
172
+ end
173
+ ```
174
+
175
+ Prepared statements are supported, as well. In a prepared statement, use a `?`
176
+ in place of each value and then execute the statement to retrieve a result set.
177
+ Pass your arguments to the execute method in the same number and order as the
178
+ question marks in the statement.
179
+
180
+ ``` ruby
181
+ statement = @client.prepare("SELECT * FROM users WHERE login_count = ?")
182
+ result1 = statement.execute(1)
183
+ result2 = statement.execute(2)
184
+
185
+ statement = @client.prepare("SELECT * FROM users WHERE last_login >= ? AND location LIKE ?")
186
+ result = statement.execute(1, "CA")
187
+ ```
188
+
189
+ ## Connection options
190
+
191
+ You may set the following connection options in Mysql2::Client.new(...):
192
+
193
+ ``` ruby
194
+ Mysql2::Client.new(
195
+ :host,
196
+ :username,
197
+ :password,
198
+ :port,
199
+ :database,
200
+ :socket = '/path/to/mysql.sock',
201
+ :flags = REMEMBER_OPTIONS | LONG_PASSWORD | LONG_FLAG | TRANSACTIONS | PROTOCOL_41 | SECURE_CONNECTION | MULTI_STATEMENTS,
202
+ :encoding = 'utf8',
203
+ :read_timeout = seconds,
204
+ :write_timeout = seconds,
205
+ :connect_timeout = seconds,
206
+ :reconnect = true/false,
207
+ :local_infile = true/false,
208
+ :secure_auth = true/false,
209
+ :ssl_mode = :disabled / :preferred / :required / :verify_ca / :verify_identity,
210
+ :default_file = '/path/to/my.cfg',
211
+ :default_group = 'my.cfg section',
212
+ :init_command => sql
213
+ )
214
+ ```
215
+
216
+ ### Connecting to MySQL on localhost and elsewhere
217
+
218
+ The underlying MySQL client library uses the `:host` parameter to determine the
219
+ type of connection to make, with special interpretation you should be aware of:
220
+
221
+ * An empty value or `"localhost"` will attempt a local connection:
222
+ * On Unix, connect to the default local socket path. (To set a custom socket
223
+ path, use the `:socket` parameter).
224
+ * On Windows, connect using a shared-memory connection, if enabled, or TCP.
225
+ * A value of `"."` on Windows specifies a named-pipe connection.
226
+ * An IPv4 or IPv6 address will result in a TCP connection.
227
+ * Any other value will be looked up as a hostname for a TCP connection.
228
+
229
+ ### SSL options
230
+
231
+ Setting any of the following options will enable an SSL connection, but only if
232
+ your MySQL client library and server have been compiled with SSL support.
233
+ MySQL client library defaults will be used for any parameters that are left out
234
+ or set to nil. Relative paths are allowed, and may be required by managed
235
+ hosting providers such as Heroku. Set `:sslverify => true` to require that the
236
+ server presents a valid certificate.
237
+
238
+ ``` ruby
239
+ Mysql2::Client.new(
240
+ # ...options as above...,
241
+ :sslkey => '/path/to/client-key.pem',
242
+ :sslcert => '/path/to/client-cert.pem',
243
+ :sslca => '/path/to/ca-cert.pem',
244
+ :sslcapath => '/path/to/cacerts',
245
+ :sslcipher => 'DHE-RSA-AES256-SHA',
246
+ :sslverify => true,
247
+ )
248
+ ```
249
+
250
+ ### Secure auth
251
+
252
+ Starting wih MySQL 5.6.5, secure_auth is enabled by default on servers (it was disabled by default prior to this).
253
+ When secure_auth is enabled, the server will refuse a connection if the account password is stored in old pre-MySQL 4.1 format.
254
+ The MySQL 5.6.5 client library may also refuse to attempt a connection if provided an older format password.
255
+ To bypass this restriction in the client, pass the option `:secure_auth => false` to Mysql2::Client.new().
256
+
257
+ ### Flags option parsing
258
+
259
+ The `:flags` parameter accepts an integer, a string, or an array. The integer
260
+ form allows the client to assemble flags from constants defined under
261
+ `Mysql2::Client` such as `Mysql2::Client::FOUND_ROWS`. Use a bitwise `|` (OR)
262
+ to specify several flags.
263
+
264
+ The string form will be split on whitespace and parsed as with the array form:
265
+ Plain flags are added to the default flags, while flags prefixed with `-`
266
+ (minus) are removed from the default flags.
267
+
268
+ This allows easier use with ActiveRecord's database.yml, avoiding the need for magic flag numbers.
269
+ For example, to disable protocol compression, and enable multiple statements and result sets:
270
+
271
+ ``` yaml
272
+ development:
273
+ adapter: mysql2
274
+ encoding: utf8
275
+ database: my_db_name
276
+ username: root
277
+ password: my_password
278
+ host: 127.0.0.1
279
+ port: 3306
280
+ flags:
281
+ - -COMPRESS
282
+ - FOUND_ROWS
283
+ - MULTI_STATEMENTS
284
+ secure_auth: false
285
+ ```
286
+
287
+ ### Reading a MySQL config file
288
+
289
+ You may read configuration options from a MySQL configuration file by passing
290
+ the `:default_file` and `:default_group` parameters. For example:
291
+
292
+ ``` ruby
293
+ Mysql2::Client.new(:default_file => '/user/.my.cnf', :default_group => 'client')
294
+ ```
295
+
296
+ ### Initial command on connect and reconnect
297
+
298
+ If you specify the `:init_command` option, the SQL string you provide will be executed after the connection is established.
299
+ If `:reconnect` is set to `true`, init_command will also be executed after a successful reconnect.
300
+ It is useful if you want to provide session options which survive reconnection.
301
+
302
+ ``` ruby
303
+ Mysql2::Client.new(:init_command => "SET @@SESSION.sql_mode = 'STRICT_ALL_TABLES'")
304
+ ```
305
+
306
+ ### Multiple result sets
307
+
308
+ You can also retrieve multiple result sets. For this to work you need to
309
+ connect with flags `Mysql2::Client::MULTI_STATEMENTS`. Multiple result sets can
310
+ be used with stored procedures that return more than one result set, and for
311
+ bundling several SQL statements into a single call to `client.query`.
312
+
313
+ ``` ruby
314
+ client = Mysql2::Client.new(:host => "localhost", :username => "root", :flags => Mysql2::Client::MULTI_STATEMENTS)
315
+ result = client.query('CALL sp_customer_list( 25, 10 )')
316
+ # result now contains the first result set
317
+ while client.next_result
318
+ result = client.store_result
319
+ # result now contains the next result set
85
320
  end
86
321
  ```
87
322
 
323
+ Repeated calls to `client.next_result` will return true, false, or raise an
324
+ exception if the respective query erred. When `client.next_result` returns true,
325
+ call `client.store_result` to retrieve a result object. Exceptions are not
326
+ raised until `client.next_result` is called to find the status of the respective
327
+ query. Subsequent queries are not executed if an earlier query raised an
328
+ exception. Subsequent calls to `client.next_result` will return false.
329
+
330
+ ``` ruby
331
+ result = client.query('SELECT 1; SELECT 2; SELECT A; SELECT 3')
332
+ p result.first
333
+
334
+ while client.next_result
335
+ result = client.store_result
336
+ p result.first
337
+ end
338
+ ```
339
+
340
+ Yields:
341
+ ```
342
+ {"1"=>1}
343
+ {"2"=>2}
344
+ next_result: Unknown column 'A' in 'field list' (Mysql2::Error)
345
+ ```
346
+
88
347
  ## Cascading config
89
348
 
90
349
  The default config hash is at:
@@ -132,11 +391,6 @@ Pass the `:as => :array` option to any of the above methods of configuration
132
391
 
133
392
  The default result type is set to :hash, but you can override a previous setting to something else with :as => :hash
134
393
 
135
- ### Others...
136
-
137
- I may add support for `:as => :csv` or even `:as => :json` to allow for *much* more efficient generation of those data types from result sets.
138
- If you'd like to see either of these (or others), open an issue and start bugging me about it ;)
139
-
140
394
  ### Timezones
141
395
 
142
396
  Mysql2 now supports two timezone options:
@@ -160,9 +414,18 @@ client = Mysql2::Client.new
160
414
  result = client.query("SELECT * FROM table_with_boolean_field", :cast_booleans => true)
161
415
  ```
162
416
 
417
+ Keep in mind that this works only with fields and not with computed values, e.g. this result will contain `1`, not `true`:
418
+
419
+ ``` ruby
420
+ client = Mysql2::Client.new
421
+ result = client.query("SELECT true", :cast_booleans => true)
422
+ ```
423
+
424
+ 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).
425
+
163
426
  ### Skipping casting
164
427
 
165
- 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.
428
+ 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.)
166
429
 
167
430
  ``` ruby
168
431
  client = Mysql2::Client.new
@@ -212,23 +475,66 @@ This is especially helpful since it saves the cost of creating the row in Ruby i
212
475
  If you only plan on using each row once, then it's much more efficient to disable this behavior by setting the `:cache_rows` option to false.
213
476
  This would be helpful if you wanted to iterate over the results in a streaming manner. Meaning the GC would cleanup rows you don't need anymore as you're iterating over the result set.
214
477
 
215
- ## ActiveRecord
478
+ ### Streaming
479
+
480
+ `Mysql2::Client` can optionally only fetch rows from the server on demand by setting `:stream => true`. This is handy when handling very large result sets which might not fit in memory on the client.
481
+
482
+ ``` ruby
483
+ result = client.query("SELECT * FROM really_big_Table", :stream => true)
484
+ ```
485
+
486
+ There are a few things that need to be kept in mind while using streaming:
487
+
488
+ * `:cache_rows` is ignored currently. (if you want to use `:cache_rows` you probably don't want to be using `:stream`)
489
+ * 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
+
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.
492
+
493
+ ### Lazy Everything
494
+
495
+ Well... almost ;)
496
+
497
+ Field name strings/symbols are shared across all the rows so only one object is ever created to represent the field name for an entire dataset.
498
+
499
+ Rows themselves are lazily created in ruby-land when an attempt to yield it is made via #each.
500
+ For example, if you were to yield 4 rows from a 100 row dataset, only 4 hashes will be created. The rest will sit and wait in C-land until you want them (or when the GC goes to cleanup your `Mysql2::Result` instance).
501
+ Now say you were to iterate over that same collection again, this time yielding 15 rows - the 4 previous rows that had already been turned into ruby hashes would be pulled from an internal cache, then 11 more would be created and stored in that cache.
502
+ Once the entire dataset has been converted into ruby objects, Mysql2::Result will free the Mysql C result object as it's no longer needed.
503
+
504
+ This caching behavior can be disabled by setting the `:cache_rows` option to false.
505
+
506
+ As for field values themselves, I'm workin on it - but expect that soon.
507
+
508
+ ## Compatibility
509
+
510
+ This gem is tested with the following Ruby versions on Linux and Mac OS X:
511
+
512
+ * Ruby MRI 1.8.7, 1.9.3, 2.0.0, 2.1.x, 2.2.x, 2.3.x, 2.4.x
513
+ * Ruby Enterprise Edition (based on MRI 1.8.7)
514
+ * Rubinius 2.x and 3.x do work but may fail under some workloads
216
515
 
217
- To use the ActiveRecord driver (with or without rails), all you should need to do is have this gem installed and set the adapter in your database.yml to "mysql2".
218
- That was easy right? :)
516
+ This gem is tested with the following MySQL and MariaDB versions:
219
517
 
220
- NOTE: as of 0.3.0, and ActiveRecord 3.1 - the ActiveRecord adapter has been pulled out of this gem and into ActiveRecord itself. If you need to use mysql2 with
221
- Rails versions < 3.1 make sure and specify `gem "mysql2", "~> 0.2.7"` in your Gemfile
518
+ * MySQL 5.5, 5.6, 5.7, 8.0
519
+ * MySQL Connector/C 6.0 and 6.1 (primarily on Windows)
520
+ * MariaDB 5.5, 10.0, 10.1
222
521
 
223
- ## Asynchronous ActiveRecord
522
+ ### Ruby on Rails / Active Record
523
+
524
+ * mysql2 0.4.x works with Rails / Active Record 4.2.5 - 5.0 and higher.
525
+ * mysql2 0.3.x works with Rails / Active Record 3.1, 3.2, 4.x, 5.0.
526
+ * mysql2 0.2.x works with Rails / Active Record 2.3 - 3.0.
527
+
528
+ ### Asynchronous Active Record
224
529
 
225
530
  Please see the [em-synchrony](https://github.com/igrigorik/em-synchrony) project for details about using EventMachine with mysql2 and Rails.
226
531
 
227
- ## Sequel
532
+ ### Sequel
228
533
 
229
- The Sequel adapter was pulled out into Sequel core (will be part of the next release) and can be used by specifying the "mysql2://" prefix to your connection specification.
534
+ Sequel includes a mysql2 adapter in all releases since 3.15 (2010-09-01).
535
+ Use the prefix "mysql2://" in your connection specification.
230
536
 
231
- ## EventMachine
537
+ ### EventMachine
232
538
 
233
539
  The mysql2 EventMachine deferrable api allows you to make async queries using EventMachine,
234
540
  while specifying callbacks for success for failure. Here's a simple example:
@@ -251,65 +557,30 @@ EM.run do
251
557
  end
252
558
  ```
253
559
 
254
- ## Lazy Everything
255
-
256
- Well... almost ;)
257
-
258
- Field name strings/symbols are shared across all the rows so only one object is ever created to represent the field name for an entire dataset.
259
-
260
- Rows themselves are lazily created in ruby-land when an attempt to yield it is made via #each.
261
- For example, if you were to yield 4 rows from a 100 row dataset, only 4 hashes will be created. The rest will sit and wait in C-land until you want them (or when the GC goes to cleanup your `Mysql2::Result` instance).
262
- Now say you were to iterate over that same collection again, this time yielding 15 rows - the 4 previous rows that had already been turned into ruby hashes would be pulled from an internal cache, then 11 more would be created and stored in that cache.
263
- Once the entire dataset has been converted into ruby objects, Mysql2::Result will free the Mysql C result object as it's no longer needed.
264
-
265
- This caching behavior can be disabled by setting the :cache_rows option to false.
266
-
267
- As for field values themselves, I'm workin on it - but expect that soon.
268
-
269
- ## Compatibility
270
-
271
- The specs pass on my system (SL 10.6.3, x86_64) in these rubies:
272
-
273
- * 1.8.7-p249
274
- * ree-1.8.7-2010.01
275
- * 1.9.1-p378
276
- * ruby-trunk
277
- * rbx-head - broken at the moment, working with the rbx team for a solution
278
-
279
- The ActiveRecord driver should work on 2.3.5 and 3.0
280
-
281
- ## Yeah... but why?
282
-
283
- Someone: Dude, the Mysql gem works fiiiiiine.
284
-
285
- Me: It sure does, but it only hands you nil and strings for field values. Leaving you to convert
286
- them into proper Ruby types in Ruby-land - which is slow as balls.
287
-
560
+ ## Benchmarks and Comparison
288
561
 
289
- Someone: OK fine, but do_mysql can already give me back values with Ruby objects mapped to MySQL types.
562
+ The mysql2 gem converts MySQL field types to Ruby data types in C code, providing a serious speed benefit.
290
563
 
291
- Me: Yep, but it's API is considerably more complex *and* can be ~2x slower.
564
+ The do_mysql gem also converts MySQL fields types, but has a considerably more complex API and is still ~2x slower than mysql2.
292
565
 
293
- ## Benchmarks
566
+ The mysql gem returns only nil or string data types, leaving you to convert field values to Ruby types in Ruby-land, which is much slower than mysql2's C code.
294
567
 
295
- Performing a basic "SELECT * FROM" query on a table with 30k rows and fields of nearly every Ruby-representable data type,
296
- then iterating over every row using an #each like method yielding a block:
297
-
298
- These results are from the `query_with_mysql_casting.rb` script in the benchmarks folder
568
+ For a comparative benchmark, the script below performs a basic "SELECT * FROM"
569
+ query on a table with 30k rows and fields of nearly every Ruby-representable
570
+ data type, then iterating over every row using an #each like method yielding a
571
+ block:
299
572
 
300
573
  ``` sh
301
- user system total real
302
- Mysql2
303
- 0.750000 0.180000 0.930000 ( 1.821655)
304
- do_mysql
305
- 1.650000 0.200000 1.850000 ( 2.811357)
306
- Mysql
307
- 7.500000 0.210000 7.710000 ( 8.065871)
574
+ user system total real
575
+ Mysql2 0.750000 0.180000 0.930000 (1.821655)
576
+ do_mysql 1.650000 0.200000 1.850000 (2.811357)
577
+ Mysql 7.500000 0.210000 7.710000 (8.065871)
308
578
  ```
309
579
 
580
+ These results are from the `query_with_mysql_casting.rb` script in the benchmarks folder.
581
+
310
582
  ## Development
311
583
 
312
- To run the tests, you can use RVM and Bundler to create a pristine environment for mysql2 development/hacking.
313
584
  Use 'bundle install' to install the necessary development and testing gems:
314
585
 
315
586
  ``` sh
@@ -317,9 +588,29 @@ bundle install
317
588
  rake
318
589
  ```
319
590
 
591
+ The tests require the "test" database to exist, and expect to connect
592
+ both as root and the running user, both with a blank password:
593
+
594
+ ``` sql
595
+ CREATE DATABASE test;
596
+ CREATE USER '<user>'@'localhost' IDENTIFIED BY '';
597
+ GRANT ALL PRIVILEGES ON test.* TO '<user>'@'localhost';
598
+ ```
599
+
600
+ You can change these defaults in the spec/configuration.yml which is generated
601
+ automatically when you run rake (or explicitly `rake spec/configuration.yml`).
602
+
603
+ For a normal installation on a Mac, you most likely do not need to do anything,
604
+ though.
605
+
320
606
  ## Special Thanks
321
607
 
322
608
  * Eric Wong - for the contribution (and the informative explanations) of some thread-safety, non-blocking I/O and cleanup patches. You rock dude
323
- * Yury Korolev (http://github.com/yury) - for TONS of help testing the ActiveRecord adapter
609
+ * Yury Korolev (http://github.com/yury) - for TONS of help testing the Active Record adapter
324
610
  * Aaron Patterson (http://github.com/tenderlove) - tons of contributions, suggestions and general badassness
325
- * Mike Perham (http://github.com/mperham) - Async ActiveRecord adapter (uses Fibers and EventMachine)
611
+ * Mike Perham (http://github.com/mperham) - Async Active Record adapter (uses Fibers and EventMachine)
612
+ * Aaron Stone (http://github.com/sodabrew) - additional client settings, local files, microsecond time, maintenance support
613
+ * Kouhei Ueno (https://github.com/nyaxt) - for the original work on Prepared Statements way back in 2012
614
+ * John Cant (http://github.com/johncant) - polishing and updating Prepared Statements support
615
+ * Justin Case (http://github.com/justincase) - polishing and updating Prepared Statements support and getting it merged
616
+ * Tamir Duberstein (http://github.com/tamird) - for help with timeouts and all around updates and cleanups
@@ -18,4 +18,4 @@ EM.run do
18
18
  defer2.callback do |result|
19
19
  puts "Result: #{result.to_a.inspect}"
20
20
  end
21
- end
21
+ end
data/examples/threaded.rb CHANGED
@@ -4,17 +4,15 @@ $LOAD_PATH.unshift 'lib'
4
4
  require 'mysql2'
5
5
  require 'timeout'
6
6
 
7
- threads = []
8
7
  # Should never exceed worst case 3.5 secs across all 20 threads
9
8
  Timeout.timeout(3.5) do
10
- 20.times do
11
- threads << Thread.new do
9
+ 20.times.map do
10
+ Thread.new do
12
11
  overhead = rand(3)
13
12
  puts ">> thread #{Thread.current.object_id} query, #{overhead} sec overhead"
14
13
  # 3 second overhead per query
15
14
  Mysql2::Client.new(:host => "localhost", :username => "root").query("SELECT sleep(#{overhead}) as result")
16
15
  puts "<< thread #{Thread.current.object_id} result, #{overhead} sec overhead"
17
16
  end
18
- end
19
- threads.each{|t| t.join }
20
- end
17
+ end.each(&:join)
18
+ end