lib/sequel/adapters/shared/mysql.rb in sequel-3.33.0 vs lib/sequel/adapters/shared/mysql.rb in sequel-3.34.0
- old
+ new
@@ -49,10 +49,35 @@
# MySQL uses the :mysql database type
def database_type
:mysql
end
+ # Use the Information Schema's KEY_COLUMN_USAGE table to get
+ # basic information on foreign key columns, but include the
+ # constraint name.
+ def foreign_key_list(table, opts={})
+ m = output_identifier_meth
+ im = input_identifier_meth
+ ds = metadata_dataset.
+ from(:INFORMATION_SCHEMA__KEY_COLUMN_USAGE).
+ where(:TABLE_NAME=>im.call(table)).
+ exclude(:CONSTRAINT_NAME=>'PRIMARY').
+ exclude(:REFERENCED_TABLE_NAME=>nil).
+ select(:CONSTRAINT_NAME___name, :COLUMN_NAME___column, :REFERENCED_TABLE_NAME___table, :REFERENCED_COLUMN_NAME___key)
+
+ h = {}
+ ds.each do |row|
+ if r = h[row[:name]]
+ r[:columns] << m.call(row[:column])
+ r[:key] << m.call(row[:key])
+ else
+ h[row[:name]] = {:name=>m.call(row[:name]), :columns=>[m.call(row[:column])], :table=>m.call(row[:table]), :key=>[m.call(row[:key])]}
+ end
+ end
+ h.values
+ end
+
# Use SHOW INDEX FROM to get the index information for the
# table.
#
# By default partial indexes are not included, you can use the
# option :partial to override this.
@@ -405,18 +430,24 @@
CAST_BITCOMP_OPEN = "CAST(~".freeze
CAST_BITCOMP_CLOSE = " AS SIGNED INTEGER)".freeze
STRAIGHT_JOIN = 'STRAIGHT_JOIN'.freeze
NATURAL_LEFT_JOIN = 'NATURAL LEFT JOIN'.freeze
BACKTICK = '`'.freeze
+ BACKTICK_RE = /`/.freeze
+ DOUBLE_BACKTICK = '``'.freeze
EMPTY_COLUMNS = " ()".freeze
EMPTY_VALUES = " VALUES ()".freeze
IGNORE = " IGNORE".freeze
REPLACE = 'REPLACE'.freeze
ON_DUPLICATE_KEY_UPDATE = " ON DUPLICATE KEY UPDATE ".freeze
EQ_VALUES = '=VALUES('.freeze
EQ = '='.freeze
WITH_ROLLUP = ' WITH ROLLUP'.freeze
+ MATCH_AGAINST = ["(MATCH ".freeze, " AGAINST (".freeze, "))".freeze].freeze
+ MATCH_AGAINST_BOOLEAN = ["(MATCH ".freeze, " AGAINST (".freeze, " IN BOOLEAN MODE))".freeze].freeze
+ EXPLAIN = 'EXPLAIN '.freeze
+ EXPLAIN_EXTENDED = 'EXPLAIN EXTENDED '.freeze
# MySQL specific syntax for LIKE/REGEXP searches, as well as
# string concatenation.
def complex_expression_sql_append(sql, op, args)
case op
@@ -464,10 +495,21 @@
# # SELECT SQL_CALC_FOUND_ROWS * FROM table LIMIT 10
def calc_found_rows
clone(:calc_found_rows => true)
end
+ # Return the results of an EXPLAIN query as a string. Options:
+ # :extended :: Use EXPLAIN EXPTENDED instead of EXPLAIN if true.
+ def explain(opts={})
+ # Load the PrettyTable class, needed for explain output
+ Sequel.extension(:_pretty_table) unless defined?(Sequel::PrettyTable)
+
+ ds = db.send(:metadata_dataset).with_sql((opts[:extended] ? EXPLAIN_EXTENDED : EXPLAIN) + select_sql).naked
+ rows = ds.all
+ Sequel::PrettyTable.string(rows, ds.columns)
+ end
+
# Return a cloned dataset which will use LOCK IN SHARE MODE to lock returned rows.
def for_share
lock_style(:share)
end
@@ -477,11 +519,11 @@
end
# MySQL specific full text search syntax.
def full_text_sql(cols, terms, opts = {})
terms = terms.join(' ') if terms.is_a?(Array)
- SQL::PlaceholderLiteralString.new("MATCH ? AGAINST (?#{" IN BOOLEAN MODE" if opts[:boolean]})", [Array(cols), terms], true)
+ SQL::PlaceholderLiteralString.new((opts[:boolean] ? MATCH_AGAINST_BOOLEAN : MATCH_AGAINST), [Array(cols), terms])
end
# MySQL allows HAVING clause on ungrouped datasets.
def having(*cond, &block)
_filter(:having, *cond, &block)
@@ -550,18 +592,28 @@
[insert_sql(columns, sql)]
end
# MySQL uses the nonstandard ` (backtick) for quoting identifiers.
def quoted_identifier_append(sql, c)
- sql << BACKTICK << c.to_s << BACKTICK
+ sql << BACKTICK << c.to_s.gsub(BACKTICK_RE, DOUBLE_BACKTICK) << BACKTICK
end
+ # Execute a REPLACE statement on the database.
+ def replace(*values)
+ execute_insert(replace_sql(*values))
+ end
+
# MySQL specific syntax for REPLACE (aka UPSERT, or update if exists,
# insert if it doesn't).
def replace_sql(*values)
clone(:replace=>true).insert_sql(*values)
end
+
+ # Replace multiple rows in a single query.
+ def multi_replace(*values)
+ clone(:replace=>true).multi_insert(*values)
+ end
# MySQL can emulate DISTINCT ON with its non-standard GROUP BY implementation,
# though the rows returned cannot be made deterministic through ordering.
def supports_distinct_on?
true
@@ -728,19 +780,10 @@
# MySQL does not support the SQL WITH clause for SELECT statements
def select_clause_methods
SELECT_CLAUSE_METHODS
end
- # MySQL supports ROLLUP via nonstandard SQL syntax
- def select_group_sql(sql)
- if group = @opts[:group]
- sql << GROUP_BY
- expression_list_append(sql, group)
- sql << WITH_ROLLUP if @opts[:group_options] == :rollup
- end
- end
-
# Support FOR SHARE locking when using the :share lock style.
def select_lock_sql(sql)
@opts[:lock] == :share ? (sql << FOR_SHARE) : super
end
@@ -750,9 +793,14 @@
end
# MySQL supports the ORDER BY and LIMIT clauses for UPDATE statements
def update_clause_methods
UPDATE_CLAUSE_METHODS
+ end
+
+ # MySQL uses WITH ROLLUP syntax.
+ def uses_with_rollup?
+ true
end
end
end
end