mysql2 0.3.10 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1 -230
  3. data/LICENSE +21 -0
  4. data/README.md +405 -80
  5. data/ext/mysql2/client.c +1110 -335
  6. data/ext/mysql2/client.h +18 -32
  7. data/ext/mysql2/extconf.rb +228 -37
  8. data/ext/mysql2/infile.c +122 -0
  9. data/ext/mysql2/infile.h +1 -0
  10. data/ext/mysql2/mysql2_ext.c +3 -1
  11. data/ext/mysql2/mysql2_ext.h +18 -16
  12. data/ext/mysql2/mysql_enc_name_to_ruby.h +172 -0
  13. data/ext/mysql2/mysql_enc_to_ruby.h +310 -0
  14. data/ext/mysql2/result.c +671 -226
  15. data/ext/mysql2/result.h +15 -6
  16. data/ext/mysql2/statement.c +604 -0
  17. data/ext/mysql2/statement.h +17 -0
  18. data/ext/mysql2/wait_for_single_fd.h +2 -1
  19. data/lib/mysql2/client.rb +125 -212
  20. data/lib/mysql2/console.rb +5 -0
  21. data/lib/mysql2/em.rb +24 -8
  22. data/lib/mysql2/error.rb +93 -8
  23. data/lib/mysql2/field.rb +3 -0
  24. data/lib/mysql2/result.rb +2 -0
  25. data/lib/mysql2/statement.rb +11 -0
  26. data/lib/mysql2/version.rb +1 -1
  27. data/lib/mysql2.rb +70 -5
  28. data/support/5072E1F5.asc +432 -0
  29. data/support/libmysql.def +219 -0
  30. data/support/mysql_enc_to_ruby.rb +86 -0
  31. data/support/ruby_enc_to_mysql.rb +63 -0
  32. metadata +45 -214
  33. data/.gitignore +0 -12
  34. data/.rspec +0 -3
  35. data/.rvmrc +0 -1
  36. data/.travis.yml +0 -7
  37. data/Gemfile +0 -3
  38. data/MIT-LICENSE +0 -20
  39. data/Rakefile +0 -5
  40. data/benchmark/active_record.rb +0 -51
  41. data/benchmark/active_record_threaded.rb +0 -42
  42. data/benchmark/allocations.rb +0 -33
  43. data/benchmark/escape.rb +0 -36
  44. data/benchmark/query_with_mysql_casting.rb +0 -80
  45. data/benchmark/query_without_mysql_casting.rb +0 -56
  46. data/benchmark/sequel.rb +0 -37
  47. data/benchmark/setup_db.rb +0 -119
  48. data/benchmark/threaded.rb +0 -44
  49. data/examples/eventmachine.rb +0 -21
  50. data/examples/threaded.rb +0 -20
  51. data/mysql2.gemspec +0 -29
  52. data/spec/em/em_spec.rb +0 -50
  53. data/spec/mysql2/client_spec.rb +0 -465
  54. data/spec/mysql2/error_spec.rb +0 -69
  55. data/spec/mysql2/result_spec.rb +0 -388
  56. data/spec/rcov.opts +0 -3
  57. data/spec/spec_helper.rb +0 -67
  58. data/tasks/benchmarks.rake +0 -20
  59. data/tasks/compile.rake +0 -71
  60. data/tasks/rspec.rake +0 -16
  61. data/tasks/vendor_mysql.rake +0 -40
data/README.md CHANGED
@@ -1,24 +1,113 @@
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
- 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.
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
+
12
+ The API consists of three classes:
8
13
 
9
- The API consists of two classes:
14
+ `Mysql2::Client` - your connection to the database.
10
15
 
11
- Mysql2::Client - your connection to the database
16
+ `Mysql2::Result` - returned from issuing a #query on the connection. It includes Enumerable.
12
17
 
13
- Mysql2::Result - returned from issuing a #query on the connection. It includes Enumerable.
18
+ `Mysql2::Statement` - returned from issuing a #prepare on the connection. Execute the statement to get a Result.
14
19
 
15
20
  ## Installing
16
21
 
22
+ ### General Instructions
23
+
17
24
  ``` sh
18
25
  gem install mysql2
19
26
  ```
20
27
 
21
- You may have to specify --with-mysql-config=/some/random/path/bin/mysql_config
28
+ This gem links against MySQL's `libmysqlclient` library or `Connector/C`
29
+ library, and compatible alternatives such as MariaDB.
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.
33
+
34
+ By default, the mysql2 gem will try to find a copy of MySQL in this order:
35
+
36
+ * Option `--with-mysql-dir`, if provided (see below).
37
+ * Option `--with-mysql-config`, if provided (see below).
38
+ * Several typical paths for `mysql_config` (default for the majority of users).
39
+ * The directory `/usr/local`.
40
+
41
+ ### Configuration options
42
+
43
+ Use these options by `gem install mysql2 -- [--optionA] [--optionB=argument]`.
44
+
45
+ * `--with-mysql-dir[=/path/to/mysqldir]` -
46
+ Specify the directory where MySQL is installed. The mysql2 gem will not use
47
+ `mysql_config`, but will instead look at `mysqldir/lib` and `mysqldir/include`
48
+ for the library and header files.
49
+ This option is mutually exclusive with `--with-mysql-config`.
50
+
51
+ * `--with-mysql-config[=/path/to/mysql_config]` -
52
+ Specify a path to the `mysql_config` binary provided by your copy of MySQL. The
53
+ mysql2 gem will ask this `mysql_config` binary about the compiler and linker
54
+ arguments needed.
55
+ This option is mutually exclusive with `--with-mysql-dir`.
56
+
57
+ * `--with-mysql-rpath=/path/to/mysql/lib` / `--without-mysql-rpath` -
58
+ Override the runtime path used to find the MySQL libraries.
59
+ This may be needed if you deploy to a system where these libraries
60
+ are located somewhere different than on your build system.
61
+ This overrides any rpath calculated by default or by the options above.
62
+
63
+ * `--with-sanitize[=address,cfi,integer,memory,thread,undefined]` -
64
+ Enable sanitizers for Clang / GCC. If no argument is given, try to enable
65
+ all sanitizers or fail if none are available. If a command-separated list of
66
+ specific sanitizers is given, configure will fail unless they all are available.
67
+ Note that the some sanitizers may incur a performance penalty, and the Address
68
+ Sanitizer may require a runtime library.
69
+ To see line numbers in backtraces, declare these environment variables
70
+ (adjust the llvm-symbolizer path as needed for your system):
71
+
72
+ ``` sh
73
+ export ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer-3.4
74
+ export ASAN_OPTIONS=symbolize=1
75
+ ```
76
+
77
+ ### Linux and other Unixes
78
+
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.
84
+
85
+ ### Mac OS X
86
+
87
+ You may use MacPorts, Homebrew, or a native MySQL installer package. The most
88
+ common paths will be automatically searched. If you want to select a specific
89
+ MySQL directory, use the `--with-mysql-dir` or `--with-mysql-config` options above.
90
+
91
+ If you have not done so already, you will need to install the XCode select tools by running
92
+ `xcode-select --install`.
93
+
94
+ ### Windows
95
+
96
+ Make sure that you have Ruby and the DevKit compilers installed. We recommend
97
+ the [Ruby Installer](http://rubyinstaller.org) distribution.
98
+
99
+ By default, the mysql2 gem will download and use MySQL Connector/C from
100
+ mysql.com. If you prefer to use a local installation of Connector/C, add the
101
+ flag `--with-mysql-dir=c:/mysql-connector-c-x-y-z` (_this path may use forward slashes_).
102
+
103
+ By default, the `libmysql.dll` library will be copied into the mysql2 gem
104
+ directory. To prevent this, add the flag `--no-vendor-libmysql`. The mysql2 gem
105
+ will search for `libmysql.dll` in the following paths, in order:
106
+
107
+ * Environment variable `RUBY_MYSQL2_LIBMYSQL_DLL=C:\path\to\libmysql.dll`
108
+ (_note the Windows-style backslashes_).
109
+ * In the mysql2 gem's own directory `vendor/libmysql.dll`
110
+ * In the system's default library search paths.
22
111
 
23
112
  ## Usage
24
113
 
@@ -27,7 +116,7 @@ Connect to a database:
27
116
  ``` ruby
28
117
  # this takes a hash of options, almost all of which map directly
29
118
  # to the familiar database.yml in rails
30
- # See http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/MysqlAdapter.html
119
+ # See http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Mysql2Adapter.html
31
120
  client = Mysql2::Client.new(:host => "localhost", :username => "root")
32
121
  ```
33
122
 
@@ -53,7 +142,10 @@ results.each do |row|
53
142
  # conveniently, row is a hash
54
143
  # the keys are the fields, as you'd expect
55
144
  # 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
145
+ puts row["id"] # row["id"].is_a? Integer
146
+ if row["dne"] # non-existant hash entry is nil
147
+ puts row["dne"]
148
+ end
57
149
  end
58
150
  ```
59
151
 
@@ -68,8 +160,7 @@ end
68
160
  How about with symbolized keys?
69
161
 
70
162
  ``` 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|
163
+ client.query("SELECT * FROM users WHERE group='githubbers'", :symbolize_keys => true).each do |row|
73
164
  # do something with row, it's ready to rock
74
165
  end
75
166
  ```
@@ -80,11 +171,204 @@ by the query like this:
80
171
  ``` ruby
81
172
  headers = results.fields # <= that's an array of field names, in order
82
173
  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"
174
+ # Each row is an array, ordered the same as the query results
175
+ # An otter's den is called a "holt" or "couch"
176
+ end
177
+ ```
178
+
179
+ Prepared statements are supported, as well. In a prepared statement, use a `?`
180
+ in place of each value and then execute the statement to retrieve a result set.
181
+ Pass your arguments to the execute method in the same number and order as the
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)
187
+
188
+ ``` ruby
189
+ statement = @client.prepare("SELECT * FROM users WHERE login_count = ?")
190
+ result1 = statement.execute(1)
191
+ result2 = statement.execute(2)
192
+
193
+ statement = @client.prepare("SELECT * FROM users WHERE last_login >= ? AND location LIKE ?")
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)
198
+ ```
199
+
200
+ ## Connection options
201
+
202
+ You may set the following connection options in Mysql2::Client.new(...):
203
+
204
+ ``` ruby
205
+ Mysql2::Client.new(
206
+ :host,
207
+ :username,
208
+ :password,
209
+ :port,
210
+ :database,
211
+ :socket = '/path/to/mysql.sock',
212
+ :flags = REMEMBER_OPTIONS | LONG_PASSWORD | LONG_FLAG | TRANSACTIONS | PROTOCOL_41 | SECURE_CONNECTION | MULTI_STATEMENTS,
213
+ :encoding = 'utf8',
214
+ :read_timeout = seconds,
215
+ :write_timeout = seconds,
216
+ :connect_timeout = seconds,
217
+ :connect_attrs = {:program_name => $PROGRAM_NAME, ...},
218
+ :reconnect = true/false,
219
+ :local_infile = true/false,
220
+ :secure_auth = true/false,
221
+ :ssl_mode = :disabled / :preferred / :required / :verify_ca / :verify_identity,
222
+ :default_file = '/path/to/my.cfg',
223
+ :default_group = 'my.cfg section',
224
+ :default_auth = 'authentication_windows_client'
225
+ :init_command => sql
226
+ )
227
+ ```
228
+
229
+ ### Connecting to MySQL on localhost and elsewhere
230
+
231
+ The underlying MySQL client library uses the `:host` parameter to determine the
232
+ type of connection to make, with special interpretation you should be aware of:
233
+
234
+ * An empty value or `"localhost"` will attempt a local connection:
235
+ * On Unix, connect to the default local socket path. (To set a custom socket
236
+ path, use the `:socket` parameter).
237
+ * On Windows, connect using a shared-memory connection, if enabled, or TCP.
238
+ * A value of `"."` on Windows specifies a named-pipe connection.
239
+ * An IPv4 or IPv6 address will result in a TCP connection.
240
+ * Any other value will be looked up as a hostname for a TCP connection.
241
+
242
+ ### SSL options
243
+
244
+ Setting any of the following options will enable an SSL connection, but only if
245
+ your MySQL client library and server have been compiled with SSL support.
246
+ MySQL client library defaults will be used for any parameters that are left out
247
+ or set to nil. Relative paths are allowed, and may be required by managed
248
+ hosting providers such as Heroku. Set `:sslverify => true` to require that the
249
+ server presents a valid certificate.
250
+
251
+ ``` ruby
252
+ Mysql2::Client.new(
253
+ # ...options as above...,
254
+ :sslkey => '/path/to/client-key.pem',
255
+ :sslcert => '/path/to/client-cert.pem',
256
+ :sslca => '/path/to/ca-cert.pem',
257
+ :sslcapath => '/path/to/cacerts',
258
+ :sslcipher => 'DHE-RSA-AES256-SHA',
259
+ :sslverify => true,
260
+ )
261
+ ```
262
+
263
+ ### Secure auth
264
+
265
+ Starting wih MySQL 5.6.5, secure_auth is enabled by default on servers (it was disabled by default prior to this).
266
+ When secure_auth is enabled, the server will refuse a connection if the account password is stored in old pre-MySQL 4.1 format.
267
+ The MySQL 5.6.5 client library may also refuse to attempt a connection if provided an older format password.
268
+ To bypass this restriction in the client, pass the option `:secure_auth => false` to Mysql2::Client.new().
269
+
270
+ ### Flags option parsing
271
+
272
+ The `:flags` parameter accepts an integer, a string, or an array. The integer
273
+ form allows the client to assemble flags from constants defined under
274
+ `Mysql2::Client` such as `Mysql2::Client::FOUND_ROWS`. Use a bitwise `|` (OR)
275
+ to specify several flags.
276
+
277
+ The string form will be split on whitespace and parsed as with the array form:
278
+ Plain flags are added to the default flags, while flags prefixed with `-`
279
+ (minus) are removed from the default flags.
280
+
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:
285
+
286
+ ``` yaml
287
+ development:
288
+ adapter: mysql2
289
+ encoding: utf8
290
+ database: my_db_name
291
+ username: root
292
+ password: my_password
293
+ host: 127.0.0.1
294
+ port: 3306
295
+ flags:
296
+ - -COMPRESS
297
+ - FOUND_ROWS
298
+ - MULTI_STATEMENTS
299
+ secure_auth: false
300
+ ```
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
+
311
+ ### Reading a MySQL config file
312
+
313
+ You may read configuration options from a MySQL configuration file by passing
314
+ the `:default_file` and `:default_group` parameters. For example:
315
+
316
+ ``` ruby
317
+ Mysql2::Client.new(:default_file => '/user/.my.cnf', :default_group => 'client')
318
+ ```
319
+
320
+ ### Initial command on connect and reconnect
321
+
322
+ If you specify the `:init_command` option, the SQL string you provide will be executed after the connection is established.
323
+ If `:reconnect` is set to `true`, init_command will also be executed after a successful reconnect.
324
+ It is useful if you want to provide session options which survive reconnection.
325
+
326
+ ``` ruby
327
+ Mysql2::Client.new(:init_command => "SET @@SESSION.sql_mode = 'STRICT_ALL_TABLES'")
328
+ ```
329
+
330
+ ### Multiple result sets
331
+
332
+ You can also retrieve multiple result sets. For this to work you need to
333
+ connect with flags `Mysql2::Client::MULTI_STATEMENTS`. Multiple result sets can
334
+ be used with stored procedures that return more than one result set, and for
335
+ bundling several SQL statements into a single call to `client.query`.
336
+
337
+ ``` ruby
338
+ client = Mysql2::Client.new(:host => "localhost", :username => "root", :flags => Mysql2::Client::MULTI_STATEMENTS)
339
+ result = client.query('CALL sp_customer_list( 25, 10 )')
340
+ # result now contains the first result set
341
+ while client.next_result
342
+ result = client.store_result
343
+ # result now contains the next result set
85
344
  end
86
345
  ```
87
346
 
347
+ Repeated calls to `client.next_result` will return true, false, or raise an
348
+ exception if the respective query erred. When `client.next_result` returns true,
349
+ call `client.store_result` to retrieve a result object. Exceptions are not
350
+ raised until `client.next_result` is called to find the status of the respective
351
+ query. Subsequent queries are not executed if an earlier query raised an
352
+ exception. Subsequent calls to `client.next_result` will return false.
353
+
354
+ ``` ruby
355
+ result = client.query('SELECT 1; SELECT 2; SELECT A; SELECT 3')
356
+ p result.first
357
+
358
+ while client.next_result
359
+ result = client.store_result
360
+ p result.first
361
+ end
362
+ ```
363
+
364
+ Yields:
365
+
366
+ ```ruby
367
+ {"1"=>1}
368
+ {"2"=>2}
369
+ next_result: Unknown column 'A' in 'field list' (Mysql2::Error)
370
+ ```
371
+
88
372
  ## Cascading config
89
373
 
90
374
  The default config hash is at:
@@ -122,6 +406,15 @@ c = Mysql2::Client.new
122
406
  c.query(sql, :symbolize_keys => true)
123
407
  ```
124
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
+
125
418
  ## Result types
126
419
 
127
420
  ### Array of Arrays
@@ -132,11 +425,6 @@ Pass the `:as => :array` option to any of the above methods of configuration
132
425
 
133
426
  The default result type is set to :hash, but you can override a previous setting to something else with :as => :hash
134
427
 
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
428
  ### Timezones
141
429
 
142
430
  Mysql2 now supports two timezone options:
@@ -160,9 +448,18 @@ client = Mysql2::Client.new
160
448
  result = client.query("SELECT * FROM table_with_boolean_field", :cast_booleans => true)
161
449
  ```
162
450
 
451
+ Keep in mind that this works only with fields and not with computed values, e.g. this result will contain `1`, not `true`:
452
+
453
+ ``` ruby
454
+ client = Mysql2::Client.new
455
+ result = client.query("SELECT true", :cast_booleans => true)
456
+ ```
457
+
458
+ 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).
459
+
163
460
  ### Skipping casting
164
461
 
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.
462
+ 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
463
 
167
464
  ``` ruby
168
465
  client = Mysql2::Client.new
@@ -212,23 +509,66 @@ This is especially helpful since it saves the cost of creating the row in Ruby i
212
509
  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
510
  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
511
 
215
- ## ActiveRecord
512
+ ### Streaming
513
+
514
+ `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.
515
+
516
+ ``` ruby
517
+ result = client.query("SELECT * FROM really_big_Table", :stream => true)
518
+ ```
519
+
520
+ There are a few things that need to be kept in mind while using streaming:
521
+
522
+ * `:cache_rows` is ignored currently. (if you want to use `:cache_rows` you probably don't want to be using `:stream`)
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`)
524
+
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).
526
+
527
+ ### Lazy Everything
528
+
529
+ Well... almost ;)
530
+
531
+ 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.
532
+
533
+ Rows themselves are lazily created in ruby-land when an attempt to yield it is made via #each.
534
+ 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).
535
+ 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.
536
+ 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.
537
+
538
+ This caching behavior can be disabled by setting the `:cache_rows` option to false.
539
+
540
+ As for field values themselves, I'm workin on it - but expect that soon.
541
+
542
+ ## Compatibility
543
+
544
+ This gem is tested with the following Ruby versions on Linux and Mac OS X:
545
+
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
548
+
549
+ This gem is tested with the following MySQL and MariaDB versions:
216
550
 
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? :)
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
219
554
 
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
555
+ ### Ruby on Rails / Active Record
222
556
 
223
- ## Asynchronous ActiveRecord
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.
561
+
562
+ ### Asynchronous Active Record
224
563
 
225
564
  Please see the [em-synchrony](https://github.com/igrigorik/em-synchrony) project for details about using EventMachine with mysql2 and Rails.
226
565
 
227
- ## Sequel
566
+ ### Sequel
228
567
 
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.
568
+ Sequel includes a mysql2 adapter in all releases since 3.15 (2010-09-01).
569
+ Use the prefix "mysql2://" in your connection specification.
230
570
 
231
- ## EventMachine
571
+ ### EventMachine
232
572
 
233
573
  The mysql2 EventMachine deferrable api allows you to make async queries using EventMachine,
234
574
  while specifying callbacks for success for failure. Here's a simple example:
@@ -251,65 +591,30 @@ EM.run do
251
591
  end
252
592
  ```
253
593
 
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.
594
+ ## Benchmarks and Comparison
287
595
 
596
+ The mysql2 gem converts MySQL field types to Ruby data types in C code, providing a serious speed benefit.
288
597
 
289
- Someone: OK fine, but do_mysql can already give me back values with Ruby objects mapped to MySQL types.
598
+ The do_mysql gem also converts MySQL fields types, but has a considerably more complex API and is still ~2x slower than mysql2.
290
599
 
291
- Me: Yep, but it's API is considerably more complex *and* can be ~2x slower.
600
+ 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.
292
601
 
293
- ## Benchmarks
294
-
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
602
+ For a comparative benchmark, the script below performs a basic "SELECT * FROM"
603
+ query on a table with 30k rows and fields of nearly every Ruby-representable
604
+ data type, then iterating over every row using an #each like method yielding a
605
+ block:
299
606
 
300
607
  ``` 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)
608
+ user system total real
609
+ Mysql2 0.750000 0.180000 0.930000 (1.821655)
610
+ do_mysql 1.650000 0.200000 1.850000 (2.811357)
611
+ Mysql 7.500000 0.210000 7.710000 (8.065871)
308
612
  ```
309
613
 
614
+ These results are from the `query_with_mysql_casting.rb` script in the benchmarks folder.
615
+
310
616
  ## Development
311
617
 
312
- To run the tests, you can use RVM and Bundler to create a pristine environment for mysql2 development/hacking.
313
618
  Use 'bundle install' to install the necessary development and testing gems:
314
619
 
315
620
  ``` sh
@@ -317,9 +622,29 @@ bundle install
317
622
  rake
318
623
  ```
319
624
 
625
+ The tests require the "test" database to exist, and expect to connect
626
+ both as root and the running user, both with a blank password:
627
+
628
+ ``` sql
629
+ CREATE DATABASE test;
630
+ CREATE USER '<user>'@'localhost' IDENTIFIED BY '';
631
+ GRANT ALL PRIVILEGES ON test.* TO '<user>'@'localhost';
632
+ ```
633
+
634
+ You can change these defaults in the spec/configuration.yml which is generated
635
+ automatically when you run rake (or explicitly `rake spec/configuration.yml`).
636
+
637
+ For a normal installation on a Mac, you most likely do not need to do anything,
638
+ though.
639
+
320
640
  ## Special Thanks
321
641
 
322
642
  * 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
324
- * 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)
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