ruby-mysql2 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.org.md ADDED
@@ -0,0 +1,676 @@
1
+ # Mysql2 - A modern, simple and very fast MySQL library for Ruby - binding to libmysql
2
+
3
+ GitHub Actions
4
+ [![GitHub Actions Status: Build](https://github.com/brianmario/mysql2/actions/workflows/build.yml/badge.svg)](https://github.com/brianmario/mysql2/actions/workflows/build.yml)
5
+ [![GitHub Actions Status: Container](https://github.com/brianmario/mysql2/actions/workflows/container.yml/badge.svg)](https://github.com/brianmario/mysql2/actions/workflows/container.yml)
6
+ Travis CI
7
+ [![Travis CI Status](https://travis-ci.org/brianmario/mysql2.png)](https://travis-ci.org/brianmario/mysql2)
8
+ Appveyor CI
9
+ [![Appveyor CI Status](https://ci.appveyor.com/api/projects/status/github/sodabrew/mysql2)](https://ci.appveyor.com/project/sodabrew/mysql2)
10
+
11
+ The Mysql2 gem is meant to serve the extremely common use-case of connecting, querying and iterating on results.
12
+ Some database libraries out there serve as direct 1:1 mappings of the already complex C APIs available.
13
+ This one is not.
14
+
15
+ It also forces the use of UTF-8 [or binary] for the connection and uses encoding-aware MySQL API calls where it can.
16
+
17
+ The API consists of three classes:
18
+
19
+ `Mysql2::Client` - your connection to the database.
20
+
21
+ `Mysql2::Result` - returned from issuing a #query on the connection. It includes Enumerable.
22
+
23
+ `Mysql2::Statement` - returned from issuing a #prepare on the connection. Execute the statement to get a Result.
24
+
25
+ ## Installing
26
+
27
+ ### General Instructions
28
+
29
+ ``` sh
30
+ gem install mysql2
31
+ ```
32
+
33
+ This gem links against MySQL's `libmysqlclient` library or `Connector/C`
34
+ library, and compatible alternatives such as MariaDB.
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.
38
+
39
+ By default, the mysql2 gem will try to find a copy of MySQL in this order:
40
+
41
+ * Option `--with-mysql-dir`, if provided (see below).
42
+ * Option `--with-mysql-config`, if provided (see below).
43
+ * Several typical paths for `mysql_config` (default for the majority of users).
44
+ * The directory `/usr/local`.
45
+
46
+ ### Configuration options
47
+
48
+ Use these options by `gem install mysql2 -- [--optionA] [--optionB=argument]`.
49
+
50
+ * `--with-mysql-dir[=/path/to/mysqldir]` -
51
+ Specify the directory where MySQL is installed. The mysql2 gem will not use
52
+ `mysql_config`, but will instead look at `mysqldir/lib` and `mysqldir/include`
53
+ for the library and header files.
54
+ This option is mutually exclusive with `--with-mysql-config`.
55
+
56
+ * `--with-mysql-config[=/path/to/mysql_config]` -
57
+ Specify a path to the `mysql_config` binary provided by your copy of MySQL. The
58
+ mysql2 gem will ask this `mysql_config` binary about the compiler and linker
59
+ arguments needed.
60
+ This option is mutually exclusive with `--with-mysql-dir`.
61
+
62
+ * `--with-mysql-rpath=/path/to/mysql/lib` / `--without-mysql-rpath` -
63
+ Override the runtime path used to find the MySQL libraries.
64
+ This may be needed if you deploy to a system where these libraries
65
+ are located somewhere different than on your build system.
66
+ This overrides any rpath calculated by default or by the options above.
67
+
68
+ * `--with-sanitize[=address,cfi,integer,memory,thread,undefined]` -
69
+ Enable sanitizers for Clang / GCC. If no argument is given, try to enable
70
+ all sanitizers or fail if none are available. If a command-separated list of
71
+ specific sanitizers is given, configure will fail unless they all are available.
72
+ Note that the some sanitizers may incur a performance penalty, and the Address
73
+ Sanitizer may require a runtime library.
74
+ To see line numbers in backtraces, declare these environment variables
75
+ (adjust the llvm-symbolizer path as needed for your system):
76
+
77
+ ``` sh
78
+ export ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer-3.4
79
+ export ASAN_OPTIONS=symbolize=1
80
+ ```
81
+
82
+ ### Linux and other Unixes
83
+
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.
89
+
90
+ ### Mac OS X
91
+
92
+ You may use MacPorts, Homebrew, or a native MySQL installer package. The most
93
+ common paths will be automatically searched. If you want to select a specific
94
+ MySQL directory, use the `--with-mysql-dir` or `--with-mysql-config` options above.
95
+
96
+ If you have not done so already, you will need to install the XCode select tools by running
97
+ `xcode-select --install`.
98
+
99
+ ### Windows
100
+
101
+ Make sure that you have Ruby and the DevKit compilers installed. We recommend
102
+ the [Ruby Installer](http://rubyinstaller.org) distribution.
103
+
104
+ By default, the mysql2 gem will download and use MySQL Connector/C from
105
+ mysql.com. If you prefer to use a local installation of Connector/C, add the
106
+ flag `--with-mysql-dir=c:/mysql-connector-c-x-y-z` (_this path may use forward slashes_).
107
+
108
+ By default, the `libmysql.dll` library will be copied into the mysql2 gem
109
+ directory. To prevent this, add the flag `--no-vendor-libmysql`. The mysql2 gem
110
+ will search for `libmysql.dll` in the following paths, in order:
111
+
112
+ * Environment variable `RUBY_MYSQL2_LIBMYSQL_DLL=C:\path\to\libmysql.dll`
113
+ (_note the Windows-style backslashes_).
114
+ * In the mysql2 gem's own directory `vendor/libmysql.dll`
115
+ * In the system's default library search paths.
116
+
117
+ ## Usage
118
+
119
+ Connect to a database:
120
+
121
+ ``` ruby
122
+ # this takes a hash of options, almost all of which map directly
123
+ # to the familiar database.yml in rails
124
+ # See http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Mysql2Adapter.html
125
+ client = Mysql2::Client.new(:host => "localhost", :username => "root")
126
+ ```
127
+
128
+ Then query it:
129
+
130
+ ``` ruby
131
+ results = client.query("SELECT * FROM users WHERE group='githubbers'")
132
+ ```
133
+
134
+ Need to escape something first?
135
+
136
+ ``` ruby
137
+ escaped = client.escape("gi'thu\"bbe\0r's")
138
+ results = client.query("SELECT * FROM users WHERE group='#{escaped}'")
139
+ ```
140
+
141
+ You can get a count of your results with `results.count`.
142
+
143
+ Finally, iterate over the results:
144
+
145
+ ``` ruby
146
+ results.each do |row|
147
+ # conveniently, row is a hash
148
+ # the keys are the fields, as you'd expect
149
+ # the values are pre-built ruby primitives mapped from their corresponding field types in MySQL
150
+ puts row["id"] # row["id"].is_a? Integer
151
+ if row["dne"] # non-existent hash entry is nil
152
+ puts row["dne"]
153
+ end
154
+ end
155
+ ```
156
+
157
+ Or, you might just keep it simple:
158
+
159
+ ``` ruby
160
+ client.query("SELECT * FROM users WHERE group='githubbers'").each do |row|
161
+ # do something with row, it's ready to rock
162
+ end
163
+ ```
164
+
165
+ How about with symbolized keys?
166
+
167
+ ``` ruby
168
+ client.query("SELECT * FROM users WHERE group='githubbers'", :symbolize_keys => true).each do |row|
169
+ # do something with row, it's ready to rock
170
+ end
171
+ ```
172
+
173
+ You can get the headers, columns, and the field types in the order that they were returned
174
+ by the query like this:
175
+
176
+ ``` ruby
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
179
+ results.each(:as => :array) do |row|
180
+ # Each row is an array, ordered the same as the query results
181
+ # An otter's den is called a "holt" or "couch"
182
+ end
183
+ ```
184
+
185
+ Prepared statements are supported, as well. In a prepared statement, use a `?`
186
+ in place of each value and then execute the statement to retrieve a result set.
187
+ Pass your arguments to the execute method in the same number and order as the
188
+ question marks in the statement. Query options can be passed as keyword arguments
189
+ to the execute method.
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
+
194
+ ``` ruby
195
+ statement = @client.prepare("SELECT * FROM users WHERE login_count = ?")
196
+ result1 = statement.execute(1)
197
+ result2 = statement.execute(2)
198
+
199
+ statement = @client.prepare("SELECT * FROM users WHERE last_login >= ? AND location LIKE ?")
200
+ result = statement.execute(1, "CA")
201
+
202
+ statement = @client.prepare("SELECT * FROM users WHERE last_login >= ? AND location LIKE ?")
203
+ result = statement.execute(1, "CA", :as => :array)
204
+ ```
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
+
223
+ ## Connection options
224
+
225
+ You may set the following connection options in Mysql2::Client.new(...):
226
+
227
+ ``` ruby
228
+ Mysql2::Client.new(
229
+ :host,
230
+ :username,
231
+ :password,
232
+ :port,
233
+ :database,
234
+ :socket = '/path/to/mysql.sock',
235
+ :flags = REMEMBER_OPTIONS | LONG_PASSWORD | LONG_FLAG | TRANSACTIONS | PROTOCOL_41 | SECURE_CONNECTION | MULTI_STATEMENTS,
236
+ :encoding = 'utf8',
237
+ :read_timeout = seconds,
238
+ :write_timeout = seconds,
239
+ :connect_timeout = seconds,
240
+ :connect_attrs = {:program_name => $PROGRAM_NAME, ...},
241
+ :reconnect = true/false,
242
+ :local_infile = true/false,
243
+ :secure_auth = true/false,
244
+ :ssl_mode = :disabled / :preferred / :required / :verify_ca / :verify_identity,
245
+ :default_file = '/path/to/my.cfg',
246
+ :default_group = 'my.cfg section',
247
+ :default_auth = 'authentication_windows_client'
248
+ :init_command => sql
249
+ )
250
+ ```
251
+
252
+ ### Connecting to MySQL on localhost and elsewhere
253
+
254
+ The underlying MySQL client library uses the `:host` parameter to determine the
255
+ type of connection to make, with special interpretation you should be aware of:
256
+
257
+ * An empty value or `"localhost"` will attempt a local connection:
258
+ * On Unix, connect to the default local socket path. (To set a custom socket
259
+ path, use the `:socket` parameter).
260
+ * On Windows, connect using a shared-memory connection, if enabled, or TCP.
261
+ * A value of `"."` on Windows specifies a named-pipe connection.
262
+ * An IPv4 or IPv6 address will result in a TCP connection.
263
+ * Any other value will be looked up as a hostname for a TCP connection.
264
+
265
+ ### SSL options
266
+
267
+ Setting any of the following options will enable an SSL connection, but only if
268
+ your MySQL client library and server have been compiled with SSL support.
269
+ MySQL client library defaults will be used for any parameters that are left out
270
+ or set to nil. Relative paths are allowed, and may be required by managed
271
+ hosting providers such as Heroku. Set `:sslverify => true` to require that the
272
+ server presents a valid certificate.
273
+
274
+ ``` ruby
275
+ Mysql2::Client.new(
276
+ # ...options as above...,
277
+ :sslkey => '/path/to/client-key.pem',
278
+ :sslcert => '/path/to/client-cert.pem',
279
+ :sslca => '/path/to/ca-cert.pem',
280
+ :sslcapath => '/path/to/cacerts',
281
+ :sslcipher => 'DHE-RSA-AES256-SHA',
282
+ :sslverify => true,
283
+ )
284
+ ```
285
+
286
+ ### Secure auth
287
+
288
+ Starting with MySQL 5.6.5, secure_auth is enabled by default on servers (it was disabled by default prior to this).
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.
290
+ The MySQL 5.6.5 client library may also refuse to attempt a connection if provided an older format password.
291
+ To bypass this restriction in the client, pass the option `:secure_auth => false` to Mysql2::Client.new().
292
+
293
+ ### Flags option parsing
294
+
295
+ The `:flags` parameter accepts an integer, a string, or an array. The integer
296
+ form allows the client to assemble flags from constants defined under
297
+ `Mysql2::Client` such as `Mysql2::Client::FOUND_ROWS`. Use a bitwise `|` (OR)
298
+ to specify several flags.
299
+
300
+ The string form will be split on whitespace and parsed as with the array form:
301
+ Plain flags are added to the default flags, while flags prefixed with `-`
302
+ (minus) are removed from the default flags.
303
+
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:
308
+
309
+ ``` yaml
310
+ development:
311
+ adapter: mysql2
312
+ encoding: utf8
313
+ database: my_db_name
314
+ username: root
315
+ password: my_password
316
+ host: 127.0.0.1
317
+ port: 3306
318
+ flags:
319
+ - -COMPRESS
320
+ - FOUND_ROWS
321
+ - MULTI_STATEMENTS
322
+ secure_auth: false
323
+ ```
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
+
336
+ ### Reading a MySQL config file
337
+
338
+ You may read configuration options from a MySQL configuration file by passing
339
+ the `:default_file` and `:default_group` parameters. For example:
340
+
341
+ ``` ruby
342
+ Mysql2::Client.new(:default_file => '/user/.my.cnf', :default_group => 'client')
343
+ ```
344
+
345
+ ### Initial command on connect and reconnect
346
+
347
+ If you specify the `:init_command` option, the SQL string you provide will be executed after the connection is established.
348
+ If `:reconnect` is set to `true`, init_command will also be executed after a successful reconnect.
349
+ It is useful if you want to provide session options which survive reconnection.
350
+
351
+ ``` ruby
352
+ Mysql2::Client.new(:init_command => "SET @@SESSION.sql_mode = 'STRICT_ALL_TABLES'")
353
+ ```
354
+
355
+ ### Multiple result sets
356
+
357
+ You can also retrieve multiple result sets. For this to work you need to
358
+ connect with flags `Mysql2::Client::MULTI_STATEMENTS`. Multiple result sets can
359
+ be used with stored procedures that return more than one result set, and for
360
+ bundling several SQL statements into a single call to `client.query`.
361
+
362
+ ``` ruby
363
+ client = Mysql2::Client.new(:host => "localhost", :username => "root", :flags => Mysql2::Client::MULTI_STATEMENTS)
364
+ result = client.query('CALL sp_customer_list( 25, 10 )')
365
+ # result now contains the first result set
366
+ while client.next_result
367
+ result = client.store_result
368
+ # result now contains the next result set
369
+ end
370
+ ```
371
+
372
+ Repeated calls to `client.next_result` will return true, false, or raise an
373
+ exception if the respective query erred. When `client.next_result` returns true,
374
+ call `client.store_result` to retrieve a result object. Exceptions are not
375
+ raised until `client.next_result` is called to find the status of the respective
376
+ query. Subsequent queries are not executed if an earlier query raised an
377
+ exception. Subsequent calls to `client.next_result` will return false.
378
+
379
+ ``` ruby
380
+ result = client.query('SELECT 1; SELECT 2; SELECT A; SELECT 3')
381
+ p result.first
382
+
383
+ while client.next_result
384
+ result = client.store_result
385
+ p result.first
386
+ end
387
+ ```
388
+
389
+ Yields:
390
+
391
+ ```ruby
392
+ {"1"=>1}
393
+ {"2"=>2}
394
+ next_result: Unknown column 'A' in 'field list' (Mysql2::Error)
395
+ ```
396
+
397
+ ## Cascading config
398
+
399
+ The default config hash is at:
400
+
401
+ ``` ruby
402
+ Mysql2::Client.default_query_options
403
+ ```
404
+
405
+ which defaults to:
406
+
407
+ ``` ruby
408
+ {:async => false, :as => :hash, :symbolize_keys => false}
409
+ ```
410
+
411
+ that can be used as so:
412
+
413
+ ``` ruby
414
+ # these are the defaults all Mysql2::Client instances inherit
415
+ Mysql2::Client.default_query_options.merge!(:as => :array)
416
+ ```
417
+
418
+ or
419
+
420
+ ``` ruby
421
+ # this will change the defaults for all future results returned by the #query method _for this connection only_
422
+ c = Mysql2::Client.new
423
+ c.query_options.merge!(:symbolize_keys => true)
424
+ ```
425
+
426
+ or
427
+
428
+ ``` ruby
429
+ # this will set the options for the Mysql2::Result instance returned from the #query method
430
+ c = Mysql2::Client.new
431
+ c.query(sql, :symbolize_keys => true)
432
+ ```
433
+
434
+ or
435
+
436
+ ``` ruby
437
+ # this will set the options for the Mysql2::Result instance returned from the #execute method
438
+ c = Mysql2::Client.new
439
+ s = c.prepare(sql)
440
+ s.execute(arg1, args2, :symbolize_keys => true)
441
+ ```
442
+
443
+ ## Result types
444
+
445
+ ### Array of Arrays
446
+
447
+ Pass the `:as => :array` option to any of the above methods of configuration
448
+
449
+ ### Array of Hashes
450
+
451
+ The default result type is set to `:hash`, but you can override a previous setting to something else with `:as => :hash`
452
+
453
+ ### Timezones
454
+
455
+ Mysql2 now supports two timezone options:
456
+
457
+ ``` ruby
458
+ :database_timezone # this is the timezone Mysql2 will assume fields are already stored as, and will use this when creating the initial Time objects in ruby
459
+ :application_timezone # this is the timezone Mysql2 will convert to before finally handing back to the caller
460
+ ```
461
+
462
+ In other words, if `:database_timezone` is set to `:utc` - Mysql2 will create the Time objects using `Time.utc(...)` from the raw value libmysql hands over initially.
463
+ Then, if `:application_timezone` is set to say - `:local` - Mysql2 will then convert the just-created UTC Time object to local time.
464
+
465
+ Both options only allow two values - `:local` or `:utc` - with the exception that `:application_timezone` can be [and defaults to] nil
466
+
467
+ ### Casting "boolean" columns
468
+
469
+ You can now tell Mysql2 to cast `tinyint(1)` fields to boolean values in Ruby with the `:cast_booleans` option.
470
+
471
+ ``` ruby
472
+ client = Mysql2::Client.new
473
+ result = client.query("SELECT * FROM table_with_boolean_field", :cast_booleans => true)
474
+ ```
475
+
476
+ Keep in mind that this works only with fields and not with computed values, e.g. this result will contain `1`, not `true`:
477
+
478
+ ``` ruby
479
+ client = Mysql2::Client.new
480
+ result = client.query("SELECT true", :cast_booleans => true)
481
+ ```
482
+
483
+ 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).
484
+
485
+ ### Skipping casting
486
+
487
+ 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.)
488
+
489
+ ``` ruby
490
+ client = Mysql2::Client.new
491
+ result = client.query("SELECT * FROM table", :cast => false)
492
+ ```
493
+
494
+ Here are the results from the `query_without_mysql_casting.rb` script in the benchmarks folder:
495
+
496
+ ``` sh
497
+ user system total real
498
+ Mysql2 (cast: true) 0.340000 0.000000 0.340000 ( 0.405018)
499
+ Mysql2 (cast: false) 0.160000 0.010000 0.170000 ( 0.209937)
500
+ Mysql 0.080000 0.000000 0.080000 ( 0.129355)
501
+ do_mysql 0.520000 0.010000 0.530000 ( 0.574619)
502
+ ```
503
+
504
+ Although Mysql2 performs reasonably well at retrieving uncasted data, it (currently) is not as fast as the Mysql gem. In spite of this small disadvantage, Mysql2 still sports a friendlier interface and doesn't block the entire ruby process when querying.
505
+
506
+ ### Async
507
+
508
+ NOTE: Not supported on Windows.
509
+
510
+ `Mysql2::Client` takes advantage of the MySQL C API's (undocumented) non-blocking function mysql_send_query for *all* queries.
511
+ But, in order to take full advantage of it in your Ruby code, you can do:
512
+
513
+ ``` ruby
514
+ client.query("SELECT sleep(5)", :async => true)
515
+ ```
516
+
517
+ Which will return nil immediately. At this point you'll probably want to use some socket monitoring mechanism
518
+ like EventMachine or even IO.select. Once the socket becomes readable, you can do:
519
+
520
+ ``` ruby
521
+ # result will be a Mysql2::Result instance
522
+ result = client.async_result
523
+ ```
524
+
525
+ NOTE: Because of the way MySQL's query API works, this method will block until the result is ready.
526
+ So if you really need things to stay async, it's best to just monitor the socket with something like EventMachine.
527
+ If you need multiple query concurrency take a look at using a connection pool.
528
+
529
+ ### Row Caching
530
+
531
+ By default, Mysql2 will cache rows that have been created in Ruby (since this happens lazily).
532
+ This is especially helpful since it saves the cost of creating the row in Ruby if you were to iterate over the collection again.
533
+
534
+ 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.
535
+ 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.
536
+
537
+ ### Streaming
538
+
539
+ `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.
540
+
541
+ ``` ruby
542
+ result = client.query("SELECT * FROM really_big_Table", :stream => true)
543
+ ```
544
+
545
+ There are a few things that need to be kept in mind while using streaming:
546
+
547
+ * `:cache_rows` is ignored currently. (if you want to use `:cache_rows` you probably don't want to be using `:stream`)
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`)
549
+
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).
551
+
552
+ ### Lazy Everything
553
+
554
+ Well... almost ;)
555
+
556
+ 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.
557
+
558
+ Rows themselves are lazily created in ruby-land when an attempt to yield it is made via #each.
559
+ 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).
560
+ 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.
561
+ 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.
562
+
563
+ This caching behavior can be disabled by setting the `:cache_rows` option to false.
564
+
565
+ As for field values themselves, I'm workin on it - but expect that soon.
566
+
567
+ ## Compatibility
568
+
569
+ This gem is tested with the following Ruby versions on Linux and Mac OS X:
570
+
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
573
+
574
+ This gem is tested with the following MySQL and MariaDB versions:
575
+
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
579
+
580
+ ### Ruby on Rails / Active Record
581
+
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.
586
+
587
+ ### Asynchronous Active Record
588
+
589
+ Please see the [em-synchrony](https://github.com/igrigorik/em-synchrony) project for details about using EventMachine with mysql2 and Rails.
590
+
591
+ ### Sequel
592
+
593
+ Sequel includes a mysql2 adapter in all releases since 3.15 (2010-09-01).
594
+ Use the prefix "mysql2://" in your connection specification.
595
+
596
+ ### EventMachine
597
+
598
+ The mysql2 EventMachine deferrable api allows you to make async queries using EventMachine,
599
+ while specifying callbacks for success for failure. Here's a simple example:
600
+
601
+ ``` ruby
602
+ require 'mysql2/em'
603
+
604
+ EM.run do
605
+ client1 = Mysql2::EM::Client.new
606
+ defer1 = client1.query "SELECT sleep(3) as first_query"
607
+ defer1.callback do |result|
608
+ puts "Result: #{result.to_a.inspect}"
609
+ end
610
+
611
+ client2 = Mysql2::EM::Client.new
612
+ defer2 = client2.query "SELECT sleep(1) second_query"
613
+ defer2.callback do |result|
614
+ puts "Result: #{result.to_a.inspect}"
615
+ end
616
+ end
617
+ ```
618
+
619
+ ## Benchmarks and Comparison
620
+
621
+ The mysql2 gem converts MySQL field types to Ruby data types in C code, providing a serious speed benefit.
622
+
623
+ The do_mysql gem also converts MySQL fields types, but has a considerably more complex API and is still ~2x slower than mysql2.
624
+
625
+ 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.
626
+
627
+ For a comparative benchmark, the script below performs a basic "SELECT * FROM"
628
+ query on a table with 30k rows and fields of nearly every Ruby-representable
629
+ data type, then iterating over every row using an #each like method yielding a
630
+ block:
631
+
632
+ ``` sh
633
+ user system total real
634
+ Mysql2 0.750000 0.180000 0.930000 (1.821655)
635
+ do_mysql 1.650000 0.200000 1.850000 (2.811357)
636
+ Mysql 7.500000 0.210000 7.710000 (8.065871)
637
+ ```
638
+
639
+ These results are from the `query_with_mysql_casting.rb` script in the benchmarks folder.
640
+
641
+ ## Development
642
+
643
+ Use 'bundle install' to install the necessary development and testing gems:
644
+
645
+ ``` sh
646
+ bundle install
647
+ rake
648
+ ```
649
+
650
+ The tests require the "test" database to exist, and expect to connect
651
+ both as root and the running user, both with a blank password:
652
+
653
+ ``` sql
654
+ CREATE DATABASE test;
655
+ CREATE USER '<user>'@'localhost' IDENTIFIED BY '';
656
+ GRANT ALL PRIVILEGES ON test.* TO '<user>'@'localhost';
657
+ ```
658
+
659
+ You can change these defaults in the spec/configuration.yml which is generated
660
+ automatically when you run rake (or explicitly `rake spec/configuration.yml`).
661
+
662
+ For a normal installation on a Mac, you most likely do not need to do anything,
663
+ though.
664
+
665
+ ## Special Thanks
666
+
667
+ * Eric Wong - for the contribution (and the informative explanations) of some thread-safety, non-blocking I/O and cleanup patches. You rock dude
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