From 48d4d43f9236f705e2e81bc1781c8c37384886a9 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 2 Oct 2006 20:43:13 +0000 Subject: [PATCH] MySQL: introduce Mysql::Result#all_hashes to support further optimization. Closes #5581. git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@5219 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- activerecord/CHANGELOG | 2 + .../connection_adapters/mysql_adapter.rb | 51 +++++++++++++++---- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 7107d825a3..9524643113 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,7 @@ *SVN* +* MySQL: introduce Mysql::Result#all_hashes to support further optimization. #5581 [Stefan Kaes] + * save! shouldn't validate twice. #6324 [maiha, Bob Silva] * Association collections have an _ids reader method to match the existing writer for collection_select convenience (e.g. employee.task_ids). The writer method skips blank ids so you can safely do @employee.task_ids = params[:tasks] without checking every time for an empty list or blank values. #1887, #5780 [Michael Schuerig] diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index b9fb5fa6af..3b3c144274 100755 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -1,5 +1,39 @@ require 'active_record/connection_adapters/abstract_adapter' +module MysqlCompat + # add all_hashes method to standard mysql-c bindings or pure ruby version + def self.define_all_hashes_method! + raise 'Mysql not loaded' unless defined?(::Mysql::Result) + return if ::Mysql::Result.instance_methods.include?('all_hashes') + + # Ruby driver has a version string and returns null values in each_hash + # C driver >= 2.7 returns null values in each_hash + if Mysql.const_defined?(:VERSION) + if Mysql::VERSION.is_a?(String) || Mysql::VERSION >= 20700 + ::Mysql::Result.class_eval <<-'end_eval' + def all_hashes + rows = [] + each_hash { |row| rows << row } + rows + end + end_eval + end + + # adapters before 2.7 don't have a version constant + # and don't return null values in each_hash + else + ::Mysql::Result.class_eval <<-'end_eval' + def all_hashes + rows = [] + all_fields = fetch_fields.inject({}) { |fields, f| fields[f.name] = nil; fields } + each_hash { |row| rows << all_fields.dup.update(row) } + rows + end + end_eval + end + end +end + module ActiveRecord class Base # Establishes a connection to the database that's used by all Active Record objects. @@ -18,6 +52,9 @@ module ActiveRecord end end + # Define Mysql::Result.all_hashes + MysqlCompat.define_all_hashes_method! + config = config.symbolize_keys host = config[:host] port = config[:port] @@ -83,7 +120,7 @@ module ActiveRecord def initialize(connection, logger, connection_options, config) super(connection, logger) @connection_options, @config = connection_options, config - @null_values_in_each_hash = Mysql.const_defined?(:VERSION) + connect end @@ -339,21 +376,15 @@ module ActiveRecord def select(sql, name = nil) @connection.query_with_result = true result = execute(sql, name) - rows = [] - if @null_values_in_each_hash - result.each_hash { |row| rows << row } - else - all_fields = result.fetch_fields.inject({}) { |fields, f| fields[f.name] = nil; fields } - result.each_hash { |row| rows << all_fields.dup.update(row) } - end + rows = result.all_hashes result.free rows end - + def supports_views? version[0] >= 5 end - + def version @version ||= @connection.server_info.scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i } end