lib/sequel/adapters/shared/mysql.rb in sequel-3.0.0 vs lib/sequel/adapters/shared/mysql.rb in sequel-3.1.0

- old
+ new

@@ -1,6 +1,6 @@ -Sequel.require 'adapters/utils/unsupported' +Sequel.require %w'unsupported savepoint_transactions', 'adapters/utils' module Sequel class Database # Keep default column_references_sql for add_foreign_key support alias default_column_references_sql column_references_sql @@ -12,10 +12,12 @@ end # Methods shared by Database instances that connect to MySQL, # currently supported by the native and JDBC adapters. module DatabaseMethods + include Sequel::Database::SavepointTransactions + AUTO_INCREMENT = 'AUTO_INCREMENT'.freeze CAST_TYPES = {String=>:CHAR, Integer=>:SIGNED, Time=>:DATETIME, DateTime=>:DATETIME, Numeric=>:DECIMAL, BigDecimal=>:DECIMAL, File=>:BINARY} PRIMARY = 'PRIMARY'.freeze # MySQL's cast rules are restrictive in that you can't just cast to any possible @@ -31,21 +33,26 @@ # Return a hash containing index information. Hash keys are index name symbols. # Values are subhashes with two keys, :columns and :unique. The value of :columns # is an array of symbols of column names. The value of :unique is true or false # depending on if the index is unique. + # + # Does not include the primary key index or indexes on partial keys. def indexes(table) indexes = {} + remove_indexes = [] m = output_identifier_meth im = input_identifier_meth metadata_dataset.with_sql("SHOW INDEX FROM ?", SQL::Identifier.new(im.call(table))).each do |r| name = r[:Key_name] next if name == PRIMARY - i = indexes[m.call(name)] ||= {:columns=>[], :unique=>r[:Non_unique] != 1} + name = m.call(name) + remove_indexes << name if r[:Sub_part] + i = indexes[name] ||= {:columns=>[], :unique=>r[:Non_unique] != 1} i[:columns] << m.call(r[:Column_name]) end - indexes + indexes.reject{|k,v| remove_indexes.include?(k)} end # Get version of MySQL server, used for determined capabilities. def server_version m = /(\d+)\.(\d+)\.(\d+)/.match(get(SQL::Function.new(:version))) @@ -64,11 +71,11 @@ # Changes the database in use by issuing a USE statement. I would be # very careful if I used this. def use(db_name) disconnect @opts[:database] = db_name if self << "USE #{db_name}" - @schemas = nil + @schemas = {} self end private @@ -103,10 +110,17 @@ # Use MySQL specific AUTO_INCREMENT text. def auto_increment_sql AUTO_INCREMENT end + # MySQL doesn't allow default values on text columns, so ignore if it the + # generic text type is used + def column_definition_sql(column) + column.delete(:default) if column[:type] == File || (column[:type] == String && column[:text] == true) + super + end + # Handle MySQL specific syntax for column references def column_references_sql(column) "#{", FOREIGN KEY (#{quote_identifier(column[:name])})" unless column[:type] == :check}#{super(column)}" end @@ -236,15 +250,10 @@ # MySQL allows HAVING clause on ungrouped datasets. def having(*cond, &block) _filter(:having, *cond, &block) end - # MySQL doesn't use the SQL standard DEFAULT VALUES. - def insert_default_values_sql - "INSERT INTO #{source_list(@opts[:from])} () VALUES ()" - end - # Transforms an CROSS JOIN to an INNER JOIN if the expr is not nil. # Raises an error on use of :full_outer type, since MySQL doesn't support it. def join_table(type, table, expr=nil, table_alias={}) type = :inner if (type == :cross) && !expr.nil? raise(Sequel::Error, "MySQL doesn't support FULL OUTER JOIN") if type == :full_outer @@ -310,11 +319,11 @@ if update_cols = opts[:on_duplicate_key_update] update_cols = columns if update_cols.empty? update_string = update_cols.map{|c| "#{quote_identifier(c)}=VALUES(#{quote_identifier(c)})"}.join(COMMA_SEPARATOR) end values = values.map {|r| literal(Array(r))}.join(COMMA_SEPARATOR) - ["INSERT#{' IGNORE' if opts[:insert_ignore]} INTO #{source_list(@opts[:from])} (#{identifier_list(columns)}) VALUES #{values}#{" ON DUPLICATE KEY UPDATE #{update_string}" if update_string}"] + ["#{insert_sql_base}#{source_list(@opts[:from])} (#{identifier_list(columns)}) VALUES #{values}#{" ON DUPLICATE KEY UPDATE #{update_string}" if update_string}"] end # MySQL uses the nonstandard ` (backtick) for quoting identifiers. def quoted_identifier(c) "`#{c}`" @@ -363,9 +372,19 @@ sql << " LIMIT #{opts[:limit]}" if opts[:limit] sql end private + + # MySQL supports INSERT IGNORE INTO + def insert_sql_base + "INSERT #{'IGNORE ' if opts[:insert_ignore]}INTO " + end + + # MySQL doesn't use the SQL standard DEFAULT VALUES. + def insert_default_values_sql + "#{insert_sql_base}#{source_list(@opts[:from])} () VALUES ()" + end # Use MySQL Timestamp format def literal_datetime(v) v.strftime(TIMESTAMP_FORMAT) end