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