rails / rails
- Source
- Commits
- Network (803)
- Downloads (60)
- Wiki (4)
- Graphs
-
Tree:
a375465
David Heinemeier Hansson (author)
Fri Apr 25 14:33:00 -0700 2008
| db045dbb » | dhh | 2004-11-23 | 1 | require 'active_record/connection_adapters/abstract_adapter' | |
| 19c99acf » | jeremy | 2006-11-20 | 2 | require 'set' | |
| 67adc0b5 » | jeremy | 2005-07-03 | 3 | ||
| 0aa0c84c » | dhh | 2007-01-26 | 4 | module MysqlCompat #:nodoc: | |
| 48d4d43f » | jeremy | 2006-10-02 | 5 | # add all_hashes method to standard mysql-c bindings or pure ruby version | |
| 6 | def self.define_all_hashes_method! | ||||
| 8949ce09 » | jeremy | 2006-10-20 | 7 | raise 'Mysql not loaded' unless defined?(::Mysql) | |
| 8 | |||||
| be3a4c3d » | jeremy | 2006-11-15 | 9 | target = defined?(Mysql::Result) ? Mysql::Result : MysqlRes | |
| 10 | return if target.instance_methods.include?('all_hashes') | ||||
| 48d4d43f » | jeremy | 2006-10-02 | 11 | ||
| 12 | # Ruby driver has a version string and returns null values in each_hash | ||||
| 13 | # C driver >= 2.7 returns null values in each_hash | ||||
| be3a4c3d » | jeremy | 2006-11-15 | 14 | if Mysql.const_defined?(:VERSION) && (Mysql::VERSION.is_a?(String) || Mysql::VERSION >= 20700) | |
| 15 | target.class_eval <<-'end_eval' | ||||
| 16 | def all_hashes | ||||
| 17 | rows = [] | ||||
| 18 | each_hash { |row| rows << row } | ||||
| 19 | rows | ||||
| 48d4d43f » | jeremy | 2006-10-02 | 20 | end | |
| be3a4c3d » | jeremy | 2006-11-15 | 21 | end_eval | |
| 48d4d43f » | jeremy | 2006-10-02 | 22 | ||
| 23 | # adapters before 2.7 don't have a version constant | ||||
| 24 | # and don't return null values in each_hash | ||||
| 25 | else | ||||
| be3a4c3d » | jeremy | 2006-11-15 | 26 | target.class_eval <<-'end_eval' | |
| 48d4d43f » | jeremy | 2006-10-02 | 27 | def all_hashes | |
| 28 | rows = [] | ||||
| 29 | all_fields = fetch_fields.inject({}) { |fields, f| fields[f.name] = nil; fields } | ||||
| 30 | each_hash { |row| rows << all_fields.dup.update(row) } | ||||
| 31 | rows | ||||
| 32 | end | ||||
| 33 | end_eval | ||||
| 34 | end | ||||
| be3a4c3d » | jeremy | 2006-11-15 | 35 | ||
| d41ea51d » | jeremy | 2007-09-29 | 36 | unless target.instance_methods.include?('all_hashes') || | |
| 37 | target.instance_methods.include?(:all_hashes) | ||||
| be3a4c3d » | jeremy | 2006-11-15 | 38 | raise "Failed to defined #{target.name}#all_hashes method. Mysql::VERSION = #{Mysql::VERSION.inspect}" | |
| 39 | end | ||||
| 48d4d43f » | jeremy | 2006-10-02 | 40 | end | |
| 41 | end | ||||
| 42 | |||||
| db045dbb » | dhh | 2004-11-23 | 43 | module ActiveRecord | |
| 44 | class Base | ||||
| be3a4c3d » | jeremy | 2006-11-15 | 45 | def self.require_mysql | |
| 46 | # Include the MySQL driver if one hasn't already been loaded | ||||
| baad1c4c » | jeremy | 2005-11-21 | 47 | unless defined? Mysql | |
| db045dbb » | dhh | 2004-11-23 | 48 | begin | |
| 49 | require_library_or_gem 'mysql' | ||||
| 50 | rescue LoadError => cannot_require_mysql | ||||
| be3a4c3d » | jeremy | 2006-11-15 | 51 | # Use the bundled Ruby/MySQL driver if no driver is already in place | |
| 67adc0b5 » | jeremy | 2005-07-03 | 52 | begin | |
| 0d5a7d1d » | dhh | 2007-09-20 | 53 | ActiveRecord::Base.logger.info( | |
| 54 | "WARNING: You're using the Ruby-based MySQL library that ships with Rails. This library is not suited for production. " + | ||||
| 55 | "Please install the C-based MySQL library instead (gem install mysql)." | ||||
| 56 | ) if ActiveRecord::Base.logger | ||||
| 57 | |||||
| db045dbb » | dhh | 2004-11-23 | 58 | require 'active_record/vendor/mysql' | |
| 59 | rescue LoadError | ||||
| 60 | raise cannot_require_mysql | ||||
| 61 | end | ||||
| 62 | end | ||||
| 63 | end | ||||
| baad1c4c » | jeremy | 2005-11-21 | 64 | ||
| 48d4d43f » | jeremy | 2006-10-02 | 65 | # Define Mysql::Result.all_hashes | |
| 66 | MysqlCompat.define_all_hashes_method! | ||||
| be3a4c3d » | jeremy | 2006-11-15 | 67 | end | |
| 48d4d43f » | jeremy | 2006-10-02 | 68 | ||
| be3a4c3d » | jeremy | 2006-11-15 | 69 | # Establishes a connection to the database that's used by all Active Record objects. | |
| 70 | def self.mysql_connection(config) # :nodoc: | ||||
| f98ec352 » | jeremy | 2005-09-30 | 71 | config = config.symbolize_keys | |
| db045dbb » | dhh | 2004-11-23 | 72 | host = config[:host] | |
| 73 | port = config[:port] | ||||
| 74 | socket = config[:socket] | ||||
| 75 | username = config[:username] ? config[:username].to_s : 'root' | ||||
| 76 | password = config[:password].to_s | ||||
| 67adc0b5 » | jeremy | 2005-07-03 | 77 | ||
| db045dbb » | dhh | 2004-11-23 | 78 | if config.has_key?(:database) | |
| 79 | database = config[:database] | ||||
| 80 | else | ||||
| 81 | raise ArgumentError, "No database specified. Missing argument: database." | ||||
| 82 | end | ||||
| 67adc0b5 » | jeremy | 2005-07-03 | 83 | ||
| be3a4c3d » | jeremy | 2006-11-15 | 84 | require_mysql | |
| ba309a3e » | dhh | 2005-02-20 | 85 | mysql = Mysql.init | |
| 86 | mysql.ssl_set(config[:sslkey], config[:sslcert], config[:sslca], config[:sslcapath], config[:sslcipher]) if config[:sslkey] | ||||
| be3a4c3d » | jeremy | 2006-11-15 | 87 | ||
| e8f664dd » | jeremy | 2005-11-22 | 88 | ConnectionAdapters::MysqlAdapter.new(mysql, logger, [host, username, password, database, port, socket], config) | |
| db045dbb » | dhh | 2004-11-23 | 89 | end | |
| 90 | end | ||||
| 67adc0b5 » | jeremy | 2005-07-03 | 91 | ||
| db045dbb » | dhh | 2004-11-23 | 92 | module ConnectionAdapters | |
| ea654654 » | jamis | 2005-09-25 | 93 | class MysqlColumn < Column #:nodoc: | |
| c7c3f73f » | jeremy | 2007-10-06 | 94 | def extract_default(default) | |
| 95 | if type == :binary || type == :text | ||||
| 96 | if default.blank? | ||||
| e59978aa » | jeremy | 2008-01-30 | 97 | nil | |
| c7c3f73f » | jeremy | 2007-10-06 | 98 | else | |
| 99 | raise ArgumentError, "#{type} columns cannot have a default value: #{default.inspect}" | ||||
| 100 | end | ||||
| 101 | elsif missing_default_forged_as_empty_string?(default) | ||||
| 102 | nil | ||||
| 103 | else | ||||
| 104 | super | ||||
| 105 | end | ||||
| 19c99acf » | jeremy | 2006-11-20 | 106 | end | |
| 107 | |||||
| ea654654 » | jamis | 2005-09-25 | 108 | private | |
| 109 | def simplified_type(field_type) | ||||
| d7123105 » | jamis | 2006-03-17 | 110 | return :boolean if MysqlAdapter.emulate_booleans && field_type.downcase.index("tinyint(1)") | |
| 75de3cbb » | dhh | 2006-03-25 | 111 | return :string if field_type =~ /enum/i | |
| ea654654 » | jamis | 2005-09-25 | 112 | super | |
| 113 | end | ||||
| 19c99acf » | jeremy | 2006-11-20 | 114 | ||
| c1abe443 » | NZKoz | 2008-03-01 | 115 | def extract_limit(sql_type) | |
| 116 | if sql_type =~ /blob|text/i | ||||
| 117 | case sql_type | ||||
| 118 | when /tiny/i | ||||
| 119 | 255 | ||||
| 120 | when /medium/i | ||||
| 121 | 16777215 | ||||
| 122 | when /long/i | ||||
| 123 | 2147483647 # mysql only allows 2^31-1, not 2^32-1, somewhat inconsistently with the tiny/medium/normal cases | ||||
| 124 | else | ||||
| 125 | super # we could return 65535 here, but we leave it undecorated by default | ||||
| 126 | end | ||||
| 127 | else | ||||
| 128 | super | ||||
| 129 | end | ||||
| 130 | end | ||||
| 131 | |||||
| 19c99acf » | jeremy | 2006-11-20 | 132 | # MySQL misreports NOT NULL column default when none is given. | |
| 133 | # We can't detect this for columns which may have a legitimate '' | ||||
| 269ad971 » | jeremy | 2007-01-28 | 134 | # default (string) but we can for others (integer, datetime, boolean, | |
| 135 | # and the rest). | ||||
| 19c99acf » | jeremy | 2006-11-20 | 136 | # | |
| 137 | # Test whether the column has default '', is not null, and is not | ||||
| 138 | # a type allowing default ''. | ||||
| c7c3f73f » | jeremy | 2007-10-06 | 139 | def missing_default_forged_as_empty_string?(default) | |
| 140 | type != :string && !null && default == '' | ||||
| 269ad971 » | jeremy | 2007-01-28 | 141 | end | |
| ea654654 » | jamis | 2005-09-25 | 142 | end | |
| 143 | |||||
| 1dc0b2a9 » | dhh | 2005-02-23 | 144 | # The MySQL adapter will work with both Ruby/MySQL, which is a Ruby-based MySQL adapter that comes bundled with Active Record, and with | |
| 145 | # the faster C-based MySQL/Ruby adapter (available both as a gem and from http://www.tmtm.org/en/mysql/ruby/). | ||||
| 146 | # | ||||
| 147 | # Options: | ||||
| 148 | # | ||||
| 149 | # * <tt>:host</tt> -- Defaults to localhost | ||||
| 150 | # * <tt>:port</tt> -- Defaults to 3306 | ||||
| 151 | # * <tt>:socket</tt> -- Defaults to /tmp/mysql.sock | ||||
| 152 | # * <tt>:username</tt> -- Defaults to root | ||||
| 153 | # * <tt>:password</tt> -- Defaults to nothing | ||||
| 154 | # * <tt>:database</tt> -- The name of the database. No default, must be provided. | ||||
| 6bdcc0cf » | Marcel Molina | 2007-05-05 | 155 | # * <tt>:encoding</tt> -- (Optional) Sets the client encoding by executing "SET NAMES <encoding>" after connection | |
| 1dc0b2a9 » | dhh | 2005-02-23 | 156 | # * <tt>:sslkey</tt> -- Necessary to use MySQL with an SSL connection | |
| 157 | # * <tt>:sslcert</tt> -- Necessary to use MySQL with an SSL connection | ||||
| 158 | # * <tt>:sslcapath</tt> -- Necessary to use MySQL with an SSL connection | ||||
| 159 | # * <tt>:sslcipher</tt> -- Necessary to use MySQL with an SSL connection | ||||
| ea654654 » | jamis | 2005-09-25 | 160 | # | |
| 161 | # By default, the MysqlAdapter will consider all columns of type tinyint(1) | ||||
| 162 | # as boolean. If you wish to disable this emulation (which was the default | ||||
| 163 | # behavior in versions 0.13.1 and earlier) you can add the following line | ||||
| 164 | # to your environment.rb file: | ||||
| 165 | # | ||||
| 166 | # ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans = false | ||||
| 1dc0b2a9 » | dhh | 2005-02-23 | 167 | class MysqlAdapter < AbstractAdapter | |
| ea654654 » | jamis | 2005-09-25 | 168 | @@emulate_booleans = true | |
| 169 | cattr_accessor :emulate_booleans | ||||
| 170 | |||||
| 67adc0b5 » | jeremy | 2005-07-03 | 171 | LOST_CONNECTION_ERROR_MESSAGES = [ | |
| f3845822 » | dhh | 2005-02-20 | 172 | "Server shutdown in progress", | |
| 67adc0b5 » | jeremy | 2005-07-03 | 173 | "Broken pipe", | |
| 174 | "Lost connection to MySQL server during query", | ||||
| ac2b2131 » | jeremy | 2008-02-03 | 175 | "MySQL server has gone away" ] | |
| 176 | |||||
| 177 | QUOTED_TRUE, QUOTED_FALSE = '1', '0' | ||||
| b3df9598 » | dhh | 2005-09-25 | 178 | ||
| 39b71bb8 » | jeremy | 2005-12-09 | 179 | def initialize(connection, logger, connection_options, config) | |
| b3df9598 » | dhh | 2005-09-25 | 180 | super(connection, logger) | |
| 39b71bb8 » | jeremy | 2005-12-09 | 181 | @connection_options, @config = connection_options, config | |
| ac2b2131 » | jeremy | 2008-02-03 | 182 | @quoted_column_names, @quoted_table_names = {}, {} | |
| e8f664dd » | jeremy | 2005-11-22 | 183 | connect | |
| b3df9598 » | dhh | 2005-09-25 | 184 | end | |
| 185 | |||||
| 186 | def adapter_name #:nodoc: | ||||
| 187 | 'MySQL' | ||||
| 188 | end | ||||
| 189 | |||||
| 190 | def supports_migrations? #:nodoc: | ||||
| 4160b518 » | dhh | 2005-07-04 | 191 | true | |
| 192 | end | ||||
| eac7cf0b » | dhh | 2005-03-01 | 193 | ||
| 0aa0c84c » | dhh | 2007-01-26 | 194 | def native_database_types #:nodoc: | |
| eac7cf0b » | dhh | 2005-03-01 | 195 | { | |
| ef214ecc » | dhh | 2005-03-10 | 196 | :primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY", | |
| 65786805 » | dhh | 2005-03-10 | 197 | :string => { :name => "varchar", :limit => 255 }, | |
| 198 | :text => { :name => "text" }, | ||||
| 199 | :integer => { :name => "int", :limit => 11 }, | ||||
| 200 | :float => { :name => "float" }, | ||||
| 2a12b568 » | jeremy | 2006-07-08 | 201 | :decimal => { :name => "decimal" }, | |
| 65786805 » | dhh | 2005-03-10 | 202 | :datetime => { :name => "datetime" }, | |
| 203 | :timestamp => { :name => "datetime" }, | ||||
| 76879f25 » | jeremy | 2005-10-23 | 204 | :time => { :name => "time" }, | |
| 65786805 » | dhh | 2005-03-10 | 205 | :date => { :name => "date" }, | |
| 206 | :binary => { :name => "blob" }, | ||||
| 207 | :boolean => { :name => "tinyint", :limit => 1 } | ||||
| eac7cf0b » | dhh | 2005-03-01 | 208 | } | |
| 209 | end | ||||
| 210 | |||||
| 67adc0b5 » | jeremy | 2005-07-03 | 211 | ||
| b3df9598 » | dhh | 2005-09-25 | 212 | # QUOTING ================================================== | |
| 213 | |||||
| f1a184fe » | jeremy | 2005-11-21 | 214 | def quote(value, column = nil) | |
| 91ea3530 » | dhh | 2006-03-25 | 215 | if value.kind_of?(String) && column && column.type == :binary && column.class.respond_to?(:string_to_binary) | |
| f1a184fe » | jeremy | 2005-11-21 | 216 | s = column.class.string_to_binary(value).unpack("H*")[0] | |
| 217 | "x'#{s}'" | ||||
| 2a12b568 » | jeremy | 2006-07-08 | 218 | elsif value.kind_of?(BigDecimal) | |
| 219 | "'#{value.to_s("F")}'" | ||||
| f1a184fe » | jeremy | 2005-11-21 | 220 | else | |
| 221 | super | ||||
| 222 | end | ||||
| 223 | end | ||||
| 224 | |||||
| b3df9598 » | dhh | 2005-09-25 | 225 | def quote_column_name(name) #:nodoc: | |
| ac2b2131 » | jeremy | 2008-02-03 | 226 | @quoted_column_names[name] ||= "`#{name}`" | |
| eac7cf0b » | dhh | 2005-03-01 | 227 | end | |
| 228 | |||||
| 9b6207c3 » | jeremy | 2007-10-15 | 229 | def quote_table_name(name) #:nodoc: | |
| ac2b2131 » | jeremy | 2008-02-03 | 230 | @quoted_table_names[name] ||= quote_column_name(name).gsub('.', '`.`') | |
| 9b6207c3 » | jeremy | 2007-10-15 | 231 | end | |
| 232 | |||||
| b3df9598 » | dhh | 2005-09-25 | 233 | def quote_string(string) #:nodoc: | |
| e8f664dd » | jeremy | 2005-11-22 | 234 | @connection.quote(string) | |
| db045dbb » | dhh | 2004-11-23 | 235 | end | |
| 67adc0b5 » | jeremy | 2005-07-03 | 236 | ||
| b3df9598 » | dhh | 2005-09-25 | 237 | def quoted_true | |
| ac2b2131 » | jeremy | 2008-02-03 | 238 | QUOTED_TRUE | |
| b3df9598 » | dhh | 2005-09-25 | 239 | end | |
| ed2a84f9 » | jeremy | 2007-05-25 | 240 | ||
| b3df9598 » | dhh | 2005-09-25 | 241 | def quoted_false | |
| ac2b2131 » | jeremy | 2008-02-03 | 242 | QUOTED_FALSE | |
| db045dbb » | dhh | 2004-11-23 | 243 | end | |
| 67adc0b5 » | jeremy | 2005-07-03 | 244 | ||
| 49eafd8c » | jeremy | 2007-10-25 | 245 | # REFERENTIAL INTEGRITY ==================================== | |
| 246 | |||||
| 247 | def disable_referential_integrity(&block) #:nodoc: | ||||
| 248 | old = select_value("SELECT @@FOREIGN_KEY_CHECKS") | ||||
| 249 | |||||
| 250 | begin | ||||
| 251 | update("SET FOREIGN_KEY_CHECKS = 0") | ||||
| 252 | yield | ||||
| 253 | ensure | ||||
| 254 | update("SET FOREIGN_KEY_CHECKS = #{old}") | ||||
| 255 | end | ||||
| 256 | end | ||||
| 7dc45818 » | jamis | 2005-09-23 | 257 | ||
| 680e4742 » | jeremy | 2005-11-13 | 258 | # CONNECTION MANAGEMENT ==================================== | |
| 259 | |||||
| 260 | def active? | ||||
| 75d0623b » | jeremy | 2005-11-28 | 261 | if @connection.respond_to?(:stat) | |
| 262 | @connection.stat | ||||
| 263 | else | ||||
| 264 | @connection.query 'select 1' | ||||
| 265 | end | ||||
| 6c9cfd64 » | jeremy | 2005-12-03 | 266 | ||
| 267 | # mysql-ruby doesn't raise an exception when stat fails. | ||||
| 268 | if @connection.respond_to?(:errno) | ||||
| 269 | @connection.errno.zero? | ||||
| 270 | else | ||||
| 271 | true | ||||
| 272 | end | ||||
| 680e4742 » | jeremy | 2005-11-13 | 273 | rescue Mysql::Error | |
| 274 | false | ||||
| 275 | end | ||||
| 276 | |||||
| 277 | def reconnect! | ||||
| 6bd8e351 » | jeremy | 2006-02-26 | 278 | disconnect! | |
| 6c9cfd64 » | jeremy | 2005-12-03 | 279 | connect | |
| 680e4742 » | jeremy | 2005-11-13 | 280 | end | |
| ed2a84f9 » | jeremy | 2007-05-25 | 281 | ||
| 6bd8e351 » | jeremy | 2006-02-26 | 282 | def disconnect! | |
| 283 | @connection.close rescue nil | ||||
| 284 | end | ||||
| 680e4742 » | jeremy | 2005-11-13 | 285 | ||
| 286 | |||||
| b3df9598 » | dhh | 2005-09-25 | 287 | # DATABASE STATEMENTS ====================================== | |
| 7dc45818 » | jamis | 2005-09-23 | 288 | ||
| 30fb7b8c » | jeremy | 2007-09-15 | 289 | def select_rows(sql, name = nil) | |
| 290 | @connection.query_with_result = true | ||||
| 291 | result = execute(sql, name) | ||||
| 292 | rows = [] | ||||
| 293 | result.each { |row| rows << row } | ||||
| 294 | result.free | ||||
| 295 | rows | ||||
| 296 | end | ||||
| 297 | |||||
| 70840d4b » | jeremy | 2006-11-01 | 298 | def execute(sql, name = nil) #:nodoc: | |
| 680e4742 » | jeremy | 2005-11-13 | 299 | log(sql, name) { @connection.query(sql) } | |
| 96c60b0e » | jeremy | 2005-07-03 | 300 | rescue ActiveRecord::StatementInvalid => exception | |
| 680e4742 » | jeremy | 2005-11-13 | 301 | if exception.message.split(":").first =~ /Packets out of order/ | |
| 302 | raise ActiveRecord::StatementInvalid, "'Packets out of order' error was received from the database. Please update your mysql bindings (gem install mysql) and read http://dev.mysql.com/doc/mysql/en/password-hashing.html for more information. If you're on Windows, use the Instant Rails installer to get the updated mysql bindings." | ||||
| 96c60b0e » | jeremy | 2005-07-03 | 303 | else | |
| 304 | raise | ||||
| f3845822 » | dhh | 2005-02-20 | 305 | end | |
| db045dbb » | dhh | 2004-11-23 | 306 | end | |
| 67adc0b5 » | jeremy | 2005-07-03 | 307 | ||
| bfb906a9 » | jeremy | 2007-09-16 | 308 | def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc: | |
| 309 | super sql, name | ||||
| b3df9598 » | dhh | 2005-09-25 | 310 | id_value || @connection.insert_id | |
| 311 | end | ||||
| 312 | |||||
| bfb906a9 » | jeremy | 2007-09-16 | 313 | def update_sql(sql, name = nil) #:nodoc: | |
| 314 | super | ||||
| 69cb942d » | dhh | 2004-12-19 | 315 | @connection.affected_rows | |
| 316 | end | ||||
| 67adc0b5 » | jeremy | 2005-07-03 | 317 | ||
| b3df9598 » | dhh | 2005-09-25 | 318 | def begin_db_transaction #:nodoc: | |
| 96c60b0e » | jeremy | 2005-07-03 | 319 | execute "BEGIN" | |
| 320 | rescue Exception | ||||
| 321 | # Transactions aren't supported | ||||
| db045dbb » | dhh | 2004-11-23 | 322 | end | |
| 67adc0b5 » | jeremy | 2005-07-03 | 323 | ||
| b3df9598 » | dhh | 2005-09-25 | 324 | def commit_db_transaction #:nodoc: | |
| 96c60b0e » | jeremy | 2005-07-03 | 325 | execute "COMMIT" | |
| 326 | rescue Exception | ||||
| 327 | # Transactions aren't supported | ||||
| db045dbb » | dhh | 2004-11-23 | 328 | end | |
| 67adc0b5 » | jeremy | 2005-07-03 | 329 | ||
| b3df9598 » | dhh | 2005-09-25 | 330 | def rollback_db_transaction #:nodoc: | |
| 96c60b0e » | jeremy | 2005-07-03 | 331 | execute "ROLLBACK" | |
| 332 | rescue Exception | ||||
| 333 | # Transactions aren't supported | ||||
| db045dbb » | dhh | 2004-11-23 | 334 | end | |
| eac7cf0b » | dhh | 2005-03-01 | 335 | ||
| 67adc0b5 » | jeremy | 2005-07-03 | 336 | ||
| 0aa0c84c » | dhh | 2007-01-26 | 337 | def add_limit_offset!(sql, options) #:nodoc: | |
| 89733eae » | Marcel Molina | 2005-10-09 | 338 | if limit = options[:limit] | |
| 339 | unless offset = options[:offset] | ||||
| 340 | sql << " LIMIT #{limit}" | ||||
| b02776c2 » | jeremy | 2005-07-03 | 341 | else | |
| 89733eae » | Marcel Molina | 2005-10-09 | 342 | sql << " LIMIT #{offset}, #{limit}" | |
| 96c60b0e » | jeremy | 2005-07-03 | 343 | end | |
| f2a29ca4 » | dhh | 2005-07-01 | 344 | end | |
| ee8d1100 » | dhh | 2005-03-20 | 345 | end | |
| f2a29ca4 » | dhh | 2005-07-01 | 346 | ||
| b3df9598 » | dhh | 2005-09-25 | 347 | ||
| 348 | # SCHEMA STATEMENTS ======================================== | ||||
| 349 | |||||
| 350 | def structure_dump #:nodoc: | ||||
| cee92312 » | dhh | 2006-03-15 | 351 | if supports_views? | |
| 352 | sql = "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'" | ||||
| 353 | else | ||||
| 354 | sql = "SHOW TABLES" | ||||
| 355 | end | ||||
| ed2a84f9 » | jeremy | 2007-05-25 | 356 | ||
| cee92312 » | dhh | 2006-03-15 | 357 | select_all(sql).inject("") do |structure, table| | |
| 358 | table.delete('Table_type') | ||||
| 9b6207c3 » | jeremy | 2007-10-15 | 359 | structure += select_one("SHOW CREATE TABLE #{quote_table_name(table.to_a.first.last)}")["Create Table"] + ";\n\n" | |
| b3df9598 » | dhh | 2005-09-25 | 360 | end | |
| 361 | end | ||||
| 362 | |||||
| 363 | def recreate_database(name) #:nodoc: | ||||
| db045dbb » | dhh | 2004-11-23 | 364 | drop_database(name) | |
| 365 | create_database(name) | ||||
| 366 | end | ||||
| 67adc0b5 » | jeremy | 2005-07-03 | 367 | ||
| ed2a84f9 » | jeremy | 2007-05-25 | 368 | # Create a new MySQL database with optional :charset and :collation. | |
| 369 | # Charset defaults to utf8. | ||||
| 370 | # | ||||
| 371 | # Example: | ||||
| 372 | # create_database 'charset_test', :charset => 'latin1', :collation => 'latin1_bin' | ||||
| 373 | # create_database 'matt_development' | ||||
| 374 | # create_database 'matt_development', :charset => :big5 | ||||
| 375 | def create_database(name, options = {}) | ||||
| 376 | if options[:collation] | ||||
| 377 | execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}` COLLATE `#{options[:collation]}`" | ||||
| 378 | else | ||||
| 379 | execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}`" | ||||
| 380 | end | ||||
| b3df9598 » | dhh | 2005-09-25 | 381 | end | |
| ed2a84f9 » | jeremy | 2007-05-25 | 382 | ||
| b3df9598 » | dhh | 2005-09-25 | 383 | def drop_database(name) #:nodoc: | |
| 1e2b3d8b » | Marcel Molina | 2006-01-12 | 384 | execute "DROP DATABASE IF EXISTS `#{name}`" | |
| db045dbb » | dhh | 2004-11-23 | 385 | end | |
| 67adc0b5 » | jeremy | 2005-07-03 | 386 | ||
| 0555fc90 » | dhh | 2006-03-17 | 387 | def current_database | |
| ed2a84f9 » | jeremy | 2007-05-25 | 388 | select_value 'SELECT DATABASE() as db' | |
| 389 | end | ||||
| 390 | |||||
| 391 | # Returns the database character set. | ||||
| 392 | def charset | ||||
| 393 | show_variable 'character_set_database' | ||||
| 394 | end | ||||
| 395 | |||||
| 396 | # Returns the database collation strategy. | ||||
| 397 | def collation | ||||
| 398 | show_variable 'collation_database' | ||||
| 0555fc90 » | dhh | 2006-03-17 | 399 | end | |
| b3df9598 » | dhh | 2005-09-25 | 400 | ||
| 401 | def tables(name = nil) #:nodoc: | ||||
| 402 | tables = [] | ||||
| 403 | execute("SHOW TABLES", name).each { |field| tables << field[0] } | ||||
| 404 | tables | ||||
| db045dbb » | dhh | 2004-11-23 | 405 | end | |
| b3df9598 » | dhh | 2005-09-25 | 406 | ||
| 9b6207c3 » | jeremy | 2007-10-15 | 407 | def drop_table(table_name, options = {}) | |
| 408 | super(table_name, options) | ||||
| 409 | end | ||||
| 410 | |||||
| b3df9598 » | dhh | 2005-09-25 | 411 | def indexes(table_name, name = nil)#:nodoc: | |
| 412 | indexes = [] | ||||
| 413 | current_index = nil | ||||
| 9b6207c3 » | jeremy | 2007-10-15 | 414 | execute("SHOW KEYS FROM #{quote_table_name(table_name)}", name).each do |row| | |
| b3df9598 » | dhh | 2005-09-25 | 415 | if current_index != row[2] | |
| 416 | next if row[2] == "PRIMARY" # skip the primary key | ||||
| 417 | current_index = row[2] | ||||
| 418 | indexes << IndexDefinition.new(row[0], row[2], row[1] == "0", []) | ||||
| 419 | end | ||||
| 420 | |||||
| 421 | indexes.last.columns << row[4] | ||||
| 422 | end | ||||
| 423 | indexes | ||||
| 424 | end | ||||
| 425 | |||||
| 426 | def columns(table_name, name = nil)#:nodoc: | ||||
| 9b6207c3 » | jeremy | 2007-10-15 | 427 | sql = "SHOW FIELDS FROM #{quote_table_name(table_name)}" | |
| b3df9598 » | dhh | 2005-09-25 | 428 | columns = [] | |
| 429 | execute(sql, name).each { |field| columns << MysqlColumn.new(field[0], field[4], field[1], field[2] == "YES") } | ||||
| 430 | columns | ||||
| 431 | end | ||||
| 432 | |||||
| 9b6207c3 » | jeremy | 2007-10-15 | 433 | def create_table(table_name, options = {}) #:nodoc: | |
| 434 | super(table_name, options.reverse_merge(:options => "ENGINE=InnoDB")) | ||||
| b3df9598 » | dhh | 2005-09-25 | 435 | end | |
| ed2a84f9 » | jeremy | 2007-05-25 | 436 | ||
| 9b6207c3 » | jeremy | 2007-10-15 | 437 | def rename_table(table_name, new_name) | |
| 438 | execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}" | ||||
| ed2a84f9 » | jeremy | 2007-05-25 | 439 | end | |
| b3df9598 » | dhh | 2005-09-25 | 440 | ||
| 441 | def change_column_default(table_name, column_name, default) #:nodoc: | ||||
| 9b6207c3 » | jeremy | 2007-10-15 | 442 | current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"] | |
| 0bef1682 » | dhh | 2005-07-05 | 443 | ||
| 9b6207c3 » | jeremy | 2007-10-15 | 444 | execute("ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(column_name)} #{current_type} DEFAULT #{quote(default)}") | |
| 0bef1682 » | dhh | 2005-07-05 | 445 | end | |
| eac7cf0b » | dhh | 2005-03-01 | 446 | ||
| b3df9598 » | dhh | 2005-09-25 | 447 | def change_column(table_name, column_name, type, options = {}) #:nodoc: | |
| 6019c268 » | jeremy | 2007-01-14 | 448 | unless options_include_default?(options) | |
| 85c86f09 » | jeremy | 2007-10-07 | 449 | if column = columns(table_name).find { |c| c.name == column_name.to_s } | |
| 450 | options[:default] = column.default | ||||
| 7cb1f93b » | jeremy | 2007-09-28 | 451 | else | |
| 452 | raise "No such column: #{table_name}.#{column_name}" | ||||
| 453 | end | ||||
| 9c5591da » | Marcel Molina | 2006-05-14 | 454 | end | |
| 6019c268 » | jeremy | 2007-01-14 | 455 | ||
| 9b6207c3 » | jeremy | 2007-10-15 | 456 | change_column_sql = "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}" | |
| f1880cac » | dhh | 2005-07-05 | 457 | add_column_options!(change_column_sql, options) | |
| 458 | execute(change_column_sql) | ||||
| 459 | end | ||||
| 460 | |||||
| b3df9598 » | dhh | 2005-09-25 | 461 | def rename_column(table_name, column_name, new_column_name) #:nodoc: | |
| 9b6207c3 » | jeremy | 2007-10-15 | 462 | current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"] | |
| 463 | execute "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}" | ||||
| f1880cac » | dhh | 2005-07-05 | 464 | end | |
| 465 | |||||
| a3754651 » | David Heinemeier Hansson | 2008-04-25 | 466 | # Maps logical Rails types to MySQL-specific data types. | |
| 467 | def type_to_sql(type, limit = nil, precision = nil, scale = nil) | ||||
| 468 | return super unless type.to_s == 'integer' | ||||
| 469 | |||||
| 470 | case limit | ||||
| 471 | when 0..3 | ||||
| 472 | "smallint(#{limit})" | ||||
| 473 | when 4..8 | ||||
| 474 | "int(#{limit})" | ||||
| 475 | when 9..20 | ||||
| 476 | "bigint(#{limit})" | ||||
| 477 | else | ||||
| 478 | 'int(11)' | ||||
| 479 | end | ||||
| 480 | end | ||||
| 481 | |||||
| eac7cf0b » | dhh | 2005-03-01 | 482 | ||
| ed2a84f9 » | jeremy | 2007-05-25 | 483 | # SHOW VARIABLES LIKE 'name' | |
| 484 | def show_variable(name) | ||||
| eb2e30ef » | jeremy | 2007-06-20 | 485 | variables = select_all("SHOW VARIABLES LIKE '#{name}'") | |
| 486 | variables.first['Value'] unless variables.empty? | ||||
| ed2a84f9 » | jeremy | 2007-05-25 | 487 | end | |
| 488 | |||||
| 2d208eb3 » | NZKoz | 2007-10-24 | 489 | # Returns a table's primary key and belonging sequence. | |
| 490 | def pk_and_sequence_for(table) #:nodoc: | ||||
| 491 | keys = [] | ||||
| 96557eb3 » | NZKoz | 2007-10-25 | 492 | execute("describe #{quote_table_name(table)}").each_hash do |h| | |
| 2d208eb3 » | NZKoz | 2007-10-24 | 493 | keys << h["Field"]if h["Key"] == "PRI" | |
| 494 | end | ||||
| 495 | keys.length == 1 ? [keys.first, nil] : nil | ||||
| 496 | end | ||||
| 497 | |||||
| db045dbb » | dhh | 2004-11-23 | 498 | private | |
| e8f664dd » | jeremy | 2005-11-22 | 499 | def connect | |
| 500 | encoding = @config[:encoding] | ||||
| 501 | if encoding | ||||
| 224d47e0 » | jeremy | 2005-12-13 | 502 | @connection.options(Mysql::SET_CHARSET_NAME, encoding) rescue nil | |
| e8f664dd » | jeremy | 2005-11-22 | 503 | end | |
| 0227f86e » | jeremy | 2007-01-14 | 504 | @connection.ssl_set(@config[:sslkey], @config[:sslcert], @config[:sslca], @config[:sslcapath], @config[:sslcipher]) if @config[:sslkey] | |
| e8f664dd » | jeremy | 2005-11-22 | 505 | @connection.real_connect(*@connection_options) | |
| 506 | execute("SET NAMES '#{encoding}'") if encoding | ||||
| 8f5c12e4 » | jeremy | 2007-01-28 | 507 | ||
| 508 | # By default, MySQL 'where id is null' selects the last inserted id. | ||||
| 509 | # Turn this off. http://dev.rubyonrails.org/ticket/6778 | ||||
| 510 | execute("SET SQL_AUTO_IS_NULL=0") | ||||
| e8f664dd » | jeremy | 2005-11-22 | 511 | end | |
| 512 | |||||
| db045dbb » | dhh | 2004-11-23 | 513 | def select(sql, name = nil) | |
| f3845822 » | dhh | 2005-02-20 | 514 | @connection.query_with_result = true | |
| 515 | result = execute(sql, name) | ||||
| 48d4d43f » | jeremy | 2006-10-02 | 516 | rows = result.all_hashes | |
| 96c60b0e » | jeremy | 2005-07-03 | 517 | result.free | |
| db045dbb » | dhh | 2004-11-23 | 518 | rows | |
| 519 | end | ||||
| 48d4d43f » | jeremy | 2006-10-02 | 520 | ||
| cee92312 » | dhh | 2006-03-15 | 521 | def supports_views? | |
| 522 | version[0] >= 5 | ||||
| 523 | end | ||||
| 48d4d43f » | jeremy | 2006-10-02 | 524 | ||
| cee92312 » | dhh | 2006-03-15 | 525 | def version | |
| 526 | @version ||= @connection.server_info.scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i } | ||||
| 527 | end | ||||
| db045dbb » | dhh | 2004-11-23 | 528 | end | |
| 529 | end | ||||
| c5f53ca3 » | jamis | 2005-09-25 | 530 | end | |

