How do you create prepared statements with the mysql2 gem?

前端 未结 7 1655
情歌与酒
情歌与酒 2021-01-04 00:50

I\'ve tried using google to answer this seemingly simple question, but to my surprise, it didn\'t help.

I have code in my rails application currently using the \'pre

相关标签:
7条回答
  • 2021-01-04 01:07

    I'm also surprised that the prepare method is missing. Surely in a common ActiveRecord and Mysql2 setup, ActiveRecord must be escaping the strings rather then using libmysql, which I find a tiny bit worrying.

    In the meantime, you can use https://github.com/brianmario/mysql2/tree/stmt

    0 讨论(0)
  • 2021-01-04 01:14

    Rails and the MySQL Active Record adaptor does not have any support for prepared statements as far as I know:

    http://patshaughnessy.net/2011/10/22/show-some-love-for-prepared-statements-in-rails-3-1

    This is because they actually don't have any use in speeding statements up and can actually slow things down due to MySQL's lack of query planning.

    0 讨论(0)
  • 2021-01-04 01:15

    UPDATE

    As Ryan Rapp pointed out correctly, mysql2 now supports prepared statements. Following snippet is extracted from the readme:

    statement = @client.prepare("SELECT * FROM users WHERE login_count = ?")
    result1 = statement.execute(1)
    result2 = statement.execute(2)
    
    statement = @client.prepare("SELECT * FROM users WHERE last_login >= ? AND location LIKE ?")
    result = statement.execute(1, "CA")
    

    Thanks Ryan!

    Original Post

    I found no such function either; neither in source nor in the documentation. Maybe the following snippet is a helpful replacement for your needs? (found in the documentation of mysql2 gem):

    escaped = client.escape("gi'thu\"bbe\0r's")
    results = client.query("SELECT * FROM users WHERE group='#{escaped}'")
    
    0 讨论(0)
  • 2021-01-04 01:16

    I swapped out to use https://github.com/tmtm/ruby-mysql instead of mysql2. I'm surprised this isn't a bigger deal-breaker for people using the mysql2 gem. I guess people who dig this deep into writing SQL have swapped to Postgresql?

    In case others are having trouble with gem install ruby-mysql followed by require "mysql" where you get a Ruby error like 'read_eof_packet': packet is not EOF (Mysql::ProtocolError) the trick is to gem uninstall ruby-mysql and instead gem install ruby-mysql-ext (or use gem 'ruby-mysql-ext' in your Gemfile) which will swap out the Ruby implementation which isn't yet Ruby 2.0 compatible (or at least, didn't work for me) for simple C bindings.

    To be clear, if you do require 'mysql' while both ruby-mysql-ext and ruby-mysql are installed, it will load the Ruby version. There may be a way to require within a specific gem, but I didn't have time to look it up.

    0 讨论(0)
  • 2021-01-04 01:19

    You may also use mysql2-cs-bind gem: https://github.com/tagomoris/mysql2-cs-bind

    0 讨论(0)
  • 2021-01-04 01:24

    Yes, mysql2 adapter doesn't support binding till the current Rails 4.0. I'm being surprised! You could tell this by the code snip from ~/.rvm/gems/ruby-2.1.1/gems/activerecord-4.1.1/lib/active_record/connection_adapters/mysql2_adapter.rb

          def exec_query(sql, name = 'SQL', binds = [])
            result = execute(sql, name)
            ActiveRecord::Result.new(result.fields, result.to_a)
          end
    
          alias exec_without_stmt exec_query
    
          # Returns an ActiveRecord::Result instance.
          def select(sql, name = nil, binds = [])                                                                                                                      
            exec_query(sql, name)
          end
    

    also this is helpful for you understanding:

    (in ~/.rvm/gems/ruby-2.1.1/gems/activerecord-4.1.1/lib/active_record/connection_adapters/abstract/database_statements.rb)

          # Returns an ActiveRecord::Result instance.
          def select_all(arel, name = nil, binds = [])
            if arel.is_a?(Relation)
              relation = arel
              arel = relation.arel                                                                                                                                     
              if !binds || binds.empty?
                binds = relation.bind_values
              end
            end
    
            select(to_sql(arel, binds), name, binds)
          end
    

    That's it! And I guess I may turn to Postgres!!

    0 讨论(0)
提交回复
热议问题