Add prepared statements support for Mysql2Adapter - #23461
Conversation
|
r? @chancancode (@rails-bot has picked a reviewer for you, use r? to override) |
63b18e6 to
22858f6
Compare
There was a problem hiding this comment.
This seems unrelated to prepared statement support
07e428d to
c962972
Compare
|
This will need to handle nodes which we consider to be unpreparable, similar to what we do in PG and SQLite. We can probably just move that logic up to the abstract adapter now. |
|
Do you means #23515? |
a370e7c to
c021804
Compare
8980117 to
d7f30c2
Compare
|
I've just pushed mysql2 0.4.3 with important prepared statement fixes from @kamipo! |
428f612 to
86b2576
Compare
|
Rebase time 😊 |
There was a problem hiding this comment.
In mysql2 0.4.3, result.fields causes segv when num of rows is zero.
This issue was fixed on master by brianmario/mysql2#741.
@sodabrew Could you release mysql2 0.4.4?
There was a problem hiding this comment.
Done! mysql2 0.4.4 is now on Rubygems.org.
|
I've just posted mysql2 0.4.4 with additional prepared statement fixes from @kamipo! |
|
Thanks @sodabrew !! 😍 |
86b2576 to
c2c5708
Compare
|
Rebased on master! |
c2c5708 to
bc7fe67
Compare
There was a problem hiding this comment.
stmt.execute calls result.each in the internal.
https://github.com/brianmario/mysql2/blob/0.4.4/ext/mysql2/statement.c#L384
Need to set query_options before stmt.execute.
There was a problem hiding this comment.
But how returning a hash instead of array in the result would be affected by the result.each call?
There was a problem hiding this comment.
result.each (rb_mysql_result_each) passes @query_options to fetch_row_func (rb_mysql_result_fetch_row_stmt or rb_mysql_result_fetch_row).
https://github.com/brianmario/mysql2/blob/0.4.4/ext/mysql2/result.c#L871-L883
https://github.com/brianmario/mysql2/blob/0.4.4/ext/mysql2/result.c#L929-L944
fetch_row_func handles args->asArray.
https://github.com/brianmario/mysql2/blob/0.4.4/ext/mysql2/result.c#L510-L514
https://github.com/brianmario/mysql2/blob/0.4.4/ext/mysql2/result.c#L725-L729
There was a problem hiding this comment.
I see now. Thanks for the explanation!
|
Changing to 5.0 since prepared statements are disabled by default. |
There was a problem hiding this comment.
We can remove this method here in a different PR. This abstract class can be removed too since we only have one concrete class.
14dd46f to
3f6574e
Compare
| require 'active_record/connection_adapters/mysql/database_statements' | ||
|
|
||
| gem 'mysql2', '>= 0.3.18', '< 0.5' | ||
| gem 'mysql2', '~> 0.4.4' |
There was a problem hiding this comment.
Do we need to bump mysql2 minimum version? 0.4.x is only required if prepared_statements: true.
There was a problem hiding this comment.
Unfortunately, mysql2 0.4.3 was broken without prepared statements.
I would like to skip this version.
…adapter Add prepared statements support for `Mysql2Adapter`
[ci skip]
|
Hurray! |
- Rename max to statement_limit - Remove magic number 1000 from everywhere - Defined StatementPool::DEFAULT_STATEMENT_LIMIT and started using it everywhere
- Rename max to statement_limit - Remove magic number 1000 from everywhere - Defined StatementPool::DEFAULT_STATEMENT_LIMIT and started using it everywhere Signed-off-by: Jeremy Daer <jeremydaer@gmail.com>
Since #23461, all adapters supports prepared statements, so that clears the prepared statements cache is no longer database specific. Actually, I struggled to identify the cause of random CI failure in #23461, that was missing `@statements.clear` in `clear_cache!`. This extracts `clear_cache!` to ensure the common concerns in the abstract adapter.
Revert "Revert "Merge pull request rails#39613 from kamipo/where_with_custom_operator"" This reverts commit da02291. ```ruby posts = Post.order(:id) posts.where("id >": 9).pluck(:id) # => [10, 11] posts.where("id >=": 9).pluck(:id) # => [9, 10, 11] posts.where("id <": 3).pluck(:id) # => [1, 2] posts.where("id <=": 3).pluck(:id) # => [1, 2, 3] ``` From type casting and table/column name resolution's point of view, `where("created_at >=": time)` is better alternative than `where("created_at >= ?", time)`. ```ruby class Post < ActiveRecord::Base attribute :created_at, :datetime, precision: 3 end time = Time.now.utc # => 2020-06-24 10:11:12.123456 UTC Post.create!(created_at: time) # => #<Post id: 1, created_at: "2020-06-24 10:11:12.123000"> # SELECT `posts`.* FROM `posts` WHERE (created_at >= '2020-06-24 10:11:12.123456') Post.where("created_at >= ?", time) # => [] # SELECT `posts`.* FROM `posts` WHERE `posts`.`created_at` >= '2020-06-24 10:11:12.123000' Post.where("created_at >=": time) # => [#<Post id: 1, created_at: "2020-06-24 10:11:12.123000">] ``` As a main contributor of the predicate builder area, I'd recommend to people use the hash syntax, the hash syntax also have other useful effects (making boundable queries, unscopeable queries, hash-like relation merging friendly, automatic other table references detection). * Making boundable queries While working on rails#23461, I realized that Active Record doesn't generate boundable queries perfectly, so I've been improving generated queries to be boundable for a long time. e.g. rails#26117 7d53993 rails#39219 Now, `where` with the hash syntax will generate boundable queries perfectly. I also want to generate boundable queries with a comparison operator in a third party gem, but currently there is no other way than calling `predicate_builder` directly. kufu/activerecord-bitemporal#62 * Unscopeable queries, Hash-like relation merging friendly Unscopeable, and Hash-like merging friendly queries are relying on where clause is an array of attr with value, and attr name is normalized as a string (i.e. using `User.arel_table[:name]` is not preferable for `unscope` and `merge`). Example: ```ruby id = User.arel_table[:id] users = User.where(id.gt(1).and(id.lteq(10))) # no-op due to `id.gt(1).and(id.lteq(10))` is not an attr with value users.unscope(:id) ``` * Automatic other table references detection It works only for the hash syntax. ee7f666
Reopen #22415.
Currently mysql2 adapter does not support prepared statements. And mysql adapter has been removed. This means that Active Record does not support prepared statements for MySQL now.
We need to support prepared statements for MySQL. But mysql2 gem still have GC issue in prepared statements. brianmario/mysql2#694
I made default to
@prepared_statements = falseinMysql2Adapterfor does not affect default behavior. I think it is still safety.