Module: ArJdbc::MySQL
- Included in:
- ActiveRecord::ConnectionAdapters::MysqlAdapter
- Defined in:
- lib/arjdbc/mysql/adapter.rb,
lib/arjdbc/mysql/explain_support.rb
Defined Under Namespace
Modules: Column, ExplainSupport
Constant Summary collapse
- ColumnExtensions =
:nodoc: backwards-compatibility
Column
- NATIVE_DATABASE_TYPES =
{ :primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY", :string => { :name => "varchar", :limit => 255 }, :text => { :name => "text" }, :integer => { :name => "int", :limit => 4 }, :float => { :name => "float" }, :decimal => { :name => "decimal" }, :datetime => { :name => "datetime" }, :timestamp => { :name => "datetime" }, :time => { :name => "time" }, :date => { :name => "date" }, :binary => { :name => "blob" }, :boolean => { :name => "tinyint", :limit => 1 } }
- ADAPTER_NAME =
'MySQL'.freeze
Class Method Summary collapse
- .arel2_visitors(config) ⇒ Object
- .column_selector ⇒ Object
- .extended(adapter) ⇒ Object
- .jdbc_connection_class ⇒ Object
Instance Method Summary collapse
-
#adapter_name ⇒ Object
:nodoc:.
- #add_column(table_name, column_name, type, options = {}) ⇒ Object
- #add_column_position!(sql, options) ⇒ Object
-
#add_limit_offset!(sql, options) ⇒ Object
:nodoc:.
- #case_sensitive_equality_operator ⇒ Object
- #case_sensitive_modifier(node) ⇒ Object
-
#change_column(table_name, column_name, type, options = {}) ⇒ Object
:nodoc:.
-
#change_column_default(table_name, column_name, default) ⇒ Object
:nodoc:.
- #change_column_null(table_name, column_name, null, default = nil) ⇒ Object
- #charset ⇒ Object
- #collation ⇒ Object
- #configure_connection ⇒ Object
-
#create_database(name, options = {}) ⇒ Object
:nodoc:.
- #create_savepoint ⇒ Object
-
#create_table(name, options = {}) ⇒ Object
:nodoc:.
- #current_database ⇒ Object
-
#disable_referential_integrity ⇒ Object
:nodoc:.
-
#drop_database(name) ⇒ Object
:nodoc:.
-
#exec_insert(sql, name, binds) ⇒ Object
(also: #exec_update, #exec_delete)
DATABASE STATEMENTS ======================================.
-
#indexes(table_name, name = nil) ⇒ Object
based on: github.com/rails/rails/blob/3-1-stable/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb#L647 Returns an array of indexes for the given table.
-
#jdbc_columns(table_name, name = nil) ⇒ Object
:nodoc:.
- #join_to_update(update, select) ⇒ Object
- #limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key) ⇒ Object
- #modify_types(types) ⇒ Object
- #native_database_types ⇒ Object
-
#pk_and_sequence_for(table) ⇒ Object
based on: github.com/rails/rails/blob/3-1-stable/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb#L756 Required for passing rails column caching tests Returns a table’s primary key and belonging sequence.
-
#primary_key(table) ⇒ Object
Returns just a table’s primary key.
-
#quote(value, column = nil) ⇒ Object
QUOTING ==================================================.
-
#quote_column_name(name) ⇒ Object
:nodoc:.
-
#quote_table_name(name) ⇒ Object
:nodoc:.
-
#recreate_database(name, options = {}) ⇒ Object
:nodoc:.
- #release_savepoint ⇒ Object
-
#remove_index!(table_name, index_name) ⇒ Object
:nodoc:.
-
#rename_column(table_name, column_name, new_column_name) ⇒ Object
:nodoc:.
- #rename_table(name, new_name) ⇒ Object
- #rollback_to_savepoint ⇒ Object
- #show_variable(var) ⇒ Object
-
#structure_dump ⇒ Object
SCHEMA STATEMENTS ========================================.
-
#supports_bulk_alter? ⇒ Boolean
:nodoc:.
-
#supports_index_sort_order? ⇒ Boolean
Technically MySQL allows to create indexes with the sort order syntax but at the moment (5.5) it doesn’t yet implement them.
-
#supports_migrations? ⇒ Boolean
Returns true, since this connection adapter supports migrations.
-
#supports_primary_key? ⇒ Boolean
:nodoc:.
-
#supports_savepoints? ⇒ Boolean
:nodoc:.
-
#supports_transaction_isolation? ⇒ Boolean
MySQL 4 technically support transaction isolation, but it is affected by a bug where the transaction level gets persisted for the whole session:.
-
#supports_views? ⇒ Boolean
:nodoc:.
- #type_to_sql(type, limit = nil, precision = nil, scale = nil) ⇒ Object
-
#update_sql(sql, name = nil) ⇒ Object
Make it public just like native MySQL adapter does.
Class Method Details
.arel2_visitors(config) ⇒ Object
131 132 133 134 135 136 137 |
# File 'lib/arjdbc/mysql/adapter.rb', line 131 def self.arel2_visitors(config) { 'mysql' => ::Arel::Visitors::MySQL, 'mysql2' => ::Arel::Visitors::MySQL, 'jdbcmysql' => ::Arel::Visitors::MySQL } end |
.column_selector ⇒ Object
16 17 18 |
# File 'lib/arjdbc/mysql/adapter.rb', line 16 def self.column_selector [ /mysql/i, lambda { |_,column| column.extend(::ArJdbc::MySQL::Column) } ] end |
.extended(adapter) ⇒ Object
8 9 10 |
# File 'lib/arjdbc/mysql/adapter.rb', line 8 def self.extended(adapter) adapter.configure_connection end |
.jdbc_connection_class ⇒ Object
20 21 22 |
# File 'lib/arjdbc/mysql/adapter.rb', line 20 def self.jdbc_connection_class ::ActiveRecord::ConnectionAdapters::MySQLJdbcConnection end |
Instance Method Details
#adapter_name ⇒ Object
:nodoc:
127 128 129 |
# File 'lib/arjdbc/mysql/adapter.rb', line 127 def adapter_name #:nodoc: ADAPTER_NAME end |
#add_column(table_name, column_name, type, options = {}) ⇒ Object
348 349 350 351 352 353 |
# File 'lib/arjdbc/mysql/adapter.rb', line 348 def add_column(table_name, column_name, type, = {}) add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD #{quote_column_name(column_name)} #{type_to_sql(type, [:limit], [:precision], [:scale])}" (add_column_sql, ) add_column_position!(add_column_sql, ) execute(add_column_sql) end |
#add_column_position!(sql, options) ⇒ Object
481 482 483 484 485 486 487 |
# File 'lib/arjdbc/mysql/adapter.rb', line 481 def add_column_position!(sql, ) if [:first] sql << " FIRST" elsif [:after] sql << " AFTER #{quote_column_name([:after])}" end end |
#add_limit_offset!(sql, options) ⇒ Object
:nodoc:
401 402 403 404 405 406 407 408 409 410 411 |
# File 'lib/arjdbc/mysql/adapter.rb', line 401 def add_limit_offset!(sql, ) #:nodoc: limit, offset = [:limit], [:offset] if limit && offset sql << " LIMIT #{offset.to_i}, #{sanitize_limit(limit)}" elsif limit sql << " LIMIT #{sanitize_limit(limit)}" elsif offset sql << " OFFSET #{offset.to_i}" end sql end |
#case_sensitive_equality_operator ⇒ Object
139 140 141 |
# File 'lib/arjdbc/mysql/adapter.rb', line 139 def case_sensitive_equality_operator "= BINARY" end |
#case_sensitive_modifier(node) ⇒ Object
143 144 145 |
# File 'lib/arjdbc/mysql/adapter.rb', line 143 def case_sensitive_modifier(node) Arel::Nodes::Bin.new(node) end |
#change_column(table_name, column_name, type, options = {}) ⇒ Object
:nodoc:
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 |
# File 'lib/arjdbc/mysql/adapter.rb', line 370 def change_column(table_name, column_name, type, = {}) #:nodoc: column = column_for(table_name, column_name) unless () [:default] = column.default end unless .has_key?(:null) [:null] = column.null end 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, [:limit], [:precision], [:scale])}" (change_column_sql, ) add_column_position!(change_column_sql, ) execute(change_column_sql) end |
#change_column_default(table_name, column_name, default) ⇒ Object
:nodoc:
355 356 357 358 |
# File 'lib/arjdbc/mysql/adapter.rb', line 355 def change_column_default(table_name, column_name, default) #:nodoc: column = column_for(table_name, column_name) change_column table_name, column_name, column.sql_type, :default => default end |
#change_column_null(table_name, column_name, null, default = nil) ⇒ Object
360 361 362 363 364 365 366 367 368 |
# File 'lib/arjdbc/mysql/adapter.rb', line 360 def change_column_null(table_name, column_name, null, default = nil) column = column_for(table_name, column_name) unless null || default.nil? execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL") end change_column table_name, column_name, column.sql_type, :null => null end |
#charset ⇒ Object
442 443 444 |
# File 'lib/arjdbc/mysql/adapter.rb', line 442 def charset show_variable("character_set_database") end |
#collation ⇒ Object
446 447 448 |
# File 'lib/arjdbc/mysql/adapter.rb', line 446 def collation show_variable("collation_database") end |
#configure_connection ⇒ Object
12 13 14 |
# File 'lib/arjdbc/mysql/adapter.rb', line 12 def configure_connection execute("SET SQL_AUTO_IS_NULL=0") end |
#create_database(name, options = {}) ⇒ Object
:nodoc:
319 320 321 322 323 324 325 |
# File 'lib/arjdbc/mysql/adapter.rb', line 319 def create_database(name, = {}) #:nodoc: if [:collation] execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{[:charset] || 'utf8'}` COLLATE `#{[:collation]}`" else execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{[:charset] || 'utf8'}`" end end |
#create_savepoint ⇒ Object
209 210 211 |
# File 'lib/arjdbc/mysql/adapter.rb', line 209 def create_savepoint execute("SAVEPOINT #{current_savepoint_name}") end |
#create_table(name, options = {}) ⇒ Object
:nodoc:
335 336 337 |
# File 'lib/arjdbc/mysql/adapter.rb', line 335 def create_table(name, = {}) #:nodoc: super(name, {:options => "ENGINE=InnoDB DEFAULT CHARSET=utf8"}.merge()) end |
#current_database ⇒ Object
331 332 333 |
# File 'lib/arjdbc/mysql/adapter.rb', line 331 def current_database select_one("SELECT DATABASE() as db")["db"] end |
#disable_referential_integrity ⇒ Object
:nodoc:
221 222 223 224 225 226 227 228 229 |
# File 'lib/arjdbc/mysql/adapter.rb', line 221 def disable_referential_integrity # :nodoc: fk_checks = select_value("SELECT @@FOREIGN_KEY_CHECKS") begin update("SET FOREIGN_KEY_CHECKS = 0") yield ensure update("SET FOREIGN_KEY_CHECKS = #{fk_checks}") end end |
#drop_database(name) ⇒ Object
:nodoc:
327 328 329 |
# File 'lib/arjdbc/mysql/adapter.rb', line 327 def drop_database(name) #:nodoc: execute "DROP DATABASE IF EXISTS `#{name}`" end |
#exec_insert(sql, name, binds) ⇒ Object Also known as: exec_update, exec_delete
DATABASE STATEMENTS ======================================
233 234 235 |
# File 'lib/arjdbc/mysql/adapter.rb', line 233 def exec_insert(sql, name, binds) execute sql, name, binds end |
#indexes(table_name, name = nil) ⇒ Object
based on: github.com/rails/rails/blob/3-1-stable/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb#L647 Returns an array of indexes for the given table.
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 |
# File 'lib/arjdbc/mysql/adapter.rb', line 282 def indexes(table_name, name = nil)#:nodoc: indexes = [] current_index = nil result = execute("SHOW KEYS FROM #{quote_table_name(table_name)}", name) result.each do |row| key_name = row["Key_name"] if current_index != key_name next if key_name == "PRIMARY" # skip the primary key current_index = key_name indexes << ::ActiveRecord::ConnectionAdapters::IndexDefinition.new( row["Table"], key_name, row["Non_unique"] == 0, [], []) end indexes.last.columns << row["Column_name"] indexes.last.lengths << row["Sub_part"] end indexes end |
#jdbc_columns(table_name, name = nil) ⇒ Object
:nodoc:
301 302 303 304 305 306 |
# File 'lib/arjdbc/mysql/adapter.rb', line 301 def jdbc_columns(table_name, name = nil)#:nodoc: sql = "SHOW FIELDS FROM #{quote_table_name(table_name)}" execute(sql, 'SCHEMA').map do |field| ::ActiveRecord::ConnectionAdapters::MysqlColumn.new(field["Field"], field["Default"], field["Type"], field["Null"] == "YES") end end |
#join_to_update(update, select) ⇒ Object
In the simple case, MySQL allows us to place JOINs directly into the UPDATE query. However, this does not allow for LIMIT, OFFSET and ORDER. To support these, we must use a subquery. However, MySQL is too stupid to create a temporary table for this automatically, so we have to give it some prompting in the form of a subsubquery. Ugh!
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 |
# File 'lib/arjdbc/mysql/adapter.rb', line 420 def join_to_update(update, select) #:nodoc: if select.limit || select.offset || select.orders.any? subsubselect = select.clone subsubselect.projections = [update.key] subselect = Arel::SelectManager.new(select.engine) subselect.project Arel.sql(update.key.name) subselect.from subsubselect.as('__active_record_temp') update.where update.key.in(subselect) else update.table select.source update.wheres = select.constraints end end |
#limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key) ⇒ Object
147 148 149 |
# File 'lib/arjdbc/mysql/adapter.rb', line 147 def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key) where_sql end |
#modify_types(types) ⇒ Object
116 117 118 119 120 121 122 123 |
# File 'lib/arjdbc/mysql/adapter.rb', line 116 def modify_types(types) types[:primary_key] = "int(11) DEFAULT NULL auto_increment PRIMARY KEY" types[:integer] = { :name => 'int', :limit => 4 } types[:decimal] = { :name => "decimal" } types[:timestamp] = { :name => "datetime" } types[:datetime][:limit] = nil types end |
#native_database_types ⇒ Object
112 113 114 |
# File 'lib/arjdbc/mysql/adapter.rb', line 112 def native_database_types NATIVE_DATABASE_TYPES end |
#pk_and_sequence_for(table) ⇒ Object
based on: github.com/rails/rails/blob/3-1-stable/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb#L756 Required for passing rails column caching tests Returns a table’s primary key and belonging sequence.
270 271 272 273 274 275 276 277 |
# File 'lib/arjdbc/mysql/adapter.rb', line 270 def pk_and_sequence_for(table) #:nodoc: keys = [] result = execute("SHOW INDEX FROM #{quote_table_name(table)} WHERE Key_name = 'PRIMARY'", 'SCHEMA') result.each do |h| keys << h["Column_name"] end keys.length == 1 ? [keys.first, nil] : nil end |
#primary_key(table) ⇒ Object
Returns just a table’s primary key
309 310 311 312 |
# File 'lib/arjdbc/mysql/adapter.rb', line 309 def primary_key(table) pk_and_sequence = pk_and_sequence_for(table) pk_and_sequence && pk_and_sequence.first end |
#quote(value, column = nil) ⇒ Object
QUOTING ==================================================
153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/arjdbc/mysql/adapter.rb', line 153 def quote(value, column = nil) return value.quoted_id if value.respond_to?(:quoted_id) return value.to_s if column && column.type == :primary_key if value.kind_of?(String) && column && column.type == :binary && column.class.respond_to?(:string_to_binary) "x'#{column.class.string_to_binary(value).unpack("H*")[0]}'" elsif value.kind_of?(BigDecimal) value.to_s("F") else super end end |
#quote_column_name(name) ⇒ Object
:nodoc:
166 167 168 |
# File 'lib/arjdbc/mysql/adapter.rb', line 166 def quote_column_name(name) # :nodoc: "`#{name.to_s.gsub('`', '``')}`" end |
#quote_table_name(name) ⇒ Object
:nodoc:
170 171 172 |
# File 'lib/arjdbc/mysql/adapter.rb', line 170 def quote_table_name(name) # :nodoc: quote_column_name(name).gsub('.', '`.`') end |
#recreate_database(name, options = {}) ⇒ Object
:nodoc:
314 315 316 317 |
# File 'lib/arjdbc/mysql/adapter.rb', line 314 def recreate_database(name, = {}) #:nodoc: drop_database(name) create_database(name, ) end |
#release_savepoint ⇒ Object
217 218 219 |
# File 'lib/arjdbc/mysql/adapter.rb', line 217 def release_savepoint execute("RELEASE SAVEPOINT #{current_savepoint_name}") end |
#remove_index!(table_name, index_name) ⇒ Object
:nodoc:
343 344 345 346 |
# File 'lib/arjdbc/mysql/adapter.rb', line 343 def remove_index!(table_name, index_name) #:nodoc: # missing table_name quoting in AR-2.3 execute "DROP INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}" end |
#rename_column(table_name, column_name, new_column_name) ⇒ Object
:nodoc:
387 388 389 390 391 392 393 394 395 396 397 398 399 |
# File 'lib/arjdbc/mysql/adapter.rb', line 387 def rename_column(table_name, column_name, new_column_name) #:nodoc: = {} if column = columns(table_name).find { |c| c.name == column_name.to_s } [:default] = column.default [:null] = column.null else raise ActiveRecord::ActiveRecordError, "No such column: #{table_name}.#{column_name}" end current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"] rename_column_sql = "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}" (rename_column_sql, ) execute(rename_column_sql) end |
#rename_table(name, new_name) ⇒ Object
339 340 341 |
# File 'lib/arjdbc/mysql/adapter.rb', line 339 def rename_table(name, new_name) execute "RENAME TABLE #{quote_table_name(name)} TO #{quote_table_name(new_name)}" end |
#rollback_to_savepoint ⇒ Object
213 214 215 |
# File 'lib/arjdbc/mysql/adapter.rb', line 213 def rollback_to_savepoint execute("ROLLBACK TO SAVEPOINT #{current_savepoint_name}") end |
#show_variable(var) ⇒ Object
436 437 438 439 440 |
# File 'lib/arjdbc/mysql/adapter.rb', line 436 def show_variable(var) res = execute("show variables like '#{var}'") result_row = res.detect {|row| row["Variable_name"] == var } result_row && result_row["Value"] end |
#structure_dump ⇒ Object
SCHEMA STATEMENTS ========================================
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/arjdbc/mysql/adapter.rb', line 246 def structure_dump #:nodoc: if supports_views? sql = "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'" else sql = "SHOW TABLES" end select_all(sql).inject("") do |structure, table| table.delete('Table_type') hash = show_create_table(table.to_a.first.last) if(table = hash["Create Table"]) structure += table + ";\n\n" elsif(view = hash["Create View"]) structure += view + ";\n\n" end end end |
#supports_bulk_alter? ⇒ Boolean
:nodoc:
183 184 185 |
# File 'lib/arjdbc/mysql/adapter.rb', line 183 def supports_bulk_alter? # :nodoc: true end |
#supports_index_sort_order? ⇒ Boolean
Technically MySQL allows to create indexes with the sort order syntax but at the moment (5.5) it doesn’t yet implement them
189 190 191 |
# File 'lib/arjdbc/mysql/adapter.rb', line 189 def supports_index_sort_order? # :nodoc: true end |
#supports_migrations? ⇒ Boolean
Returns true, since this connection adapter supports migrations.
175 176 177 |
# File 'lib/arjdbc/mysql/adapter.rb', line 175 def supports_migrations? true end |
#supports_primary_key? ⇒ Boolean
:nodoc:
179 180 181 |
# File 'lib/arjdbc/mysql/adapter.rb', line 179 def supports_primary_key? # :nodoc: true end |
#supports_savepoints? ⇒ Boolean
:nodoc:
205 206 207 |
# File 'lib/arjdbc/mysql/adapter.rb', line 205 def supports_savepoints? # :nodoc: true end |
#supports_transaction_isolation? ⇒ Boolean
MySQL 4 technically support transaction isolation, but it is affected by a bug where the transaction level gets persisted for the whole session:
197 198 199 |
# File 'lib/arjdbc/mysql/adapter.rb', line 197 def supports_transaction_isolation? # :nodoc: version[0] && version[0] >= 5 end |
#supports_views? ⇒ Boolean
:nodoc:
201 202 203 |
# File 'lib/arjdbc/mysql/adapter.rb', line 201 def supports_views? # :nodoc: version[0] && version[0] >= 5 end |
#type_to_sql(type, limit = nil, precision = nil, scale = nil) ⇒ Object
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 |
# File 'lib/arjdbc/mysql/adapter.rb', line 450 def type_to_sql(type, limit = nil, precision = nil, scale = nil) case type.to_s when 'binary' case limit when 0..0xfff; "varbinary(#{limit})" when nil; "blob" when 0x1000..0xffffffff; "blob(#{limit})" else raise(ActiveRecordError, "No binary type has character length #{limit}") end when 'integer' case limit when 1; 'tinyint' when 2; 'smallint' when 3; 'mediumint' when nil, 4, 11; 'int(11)' # compatibility with MySQL default when 5..8; 'bigint' else raise(ActiveRecordError, "No integer type has byte size #{limit}") end when 'text' case limit when 0..0xff; 'tinytext' when nil, 0x100..0xffff; 'text' when 0x10000..0xffffff; 'mediumtext' when 0x1000000..0xffffffff; 'longtext' else raise(ActiveRecordError, "No text type has character length #{limit}") end else super end end |
#update_sql(sql, name = nil) ⇒ Object
Make it public just like native MySQL adapter does.
240 241 242 |
# File 'lib/arjdbc/mysql/adapter.rb', line 240 def update_sql(sql, name = nil) # :nodoc: super end |