lib/sequel/adapters/shared/mysql.rb in sequel-5.7.1 vs lib/sequel/adapters/shared/mysql.rb in sequel-5.8.0
- old
+ new
@@ -56,10 +56,11 @@
ds = metadata_dataset.
from(Sequel[:INFORMATION_SCHEMA][:KEY_COLUMN_USAGE]).
where(:TABLE_NAME=>im.call(table), :TABLE_SCHEMA=>Sequel.function(:DATABASE)).
exclude(:CONSTRAINT_NAME=>'PRIMARY').
exclude(:REFERENCED_TABLE_NAME=>nil).
+ order(:CONSTRAINT_NAME, :POSITION_IN_UNIQUE_CONSTRAINT).
select(Sequel[:CONSTRAINT_NAME].as(:name), Sequel[:COLUMN_NAME].as(:column), Sequel[:REFERENCED_TABLE_NAME].as(:table), Sequel[:REFERENCED_COLUMN_NAME].as(:key))
h = {}
ds.each do |row|
if r = h[row[:name]]
@@ -405,10 +406,11 @@
/Duplicate entry .+ for key/ => UniqueConstraintViolation,
/foreign key constraint fails/ => ForeignKeyConstraintViolation,
/cannot be null/ => NotNullConstraintViolation,
/Deadlock found when trying to get lock; try restarting transaction/ => SerializationFailure,
/CONSTRAINT .+ failed for/ => CheckConstraintViolation,
+ /\AStatement aborted because lock\(s\) could not be acquired immediately and NOWAIT is set\./ => DatabaseLockTimeout,
}.freeze
def database_error_regexps
DATABASE_ERROR_REGEXPS
end
@@ -559,14 +561,14 @@
# Dataset methods shared by datasets that use MySQL databases.
module DatasetMethods
MATCH_AGAINST = ["MATCH ".freeze, " AGAINST (".freeze, ")".freeze].freeze
MATCH_AGAINST_BOOLEAN = ["MATCH ".freeze, " AGAINST (".freeze, " IN BOOLEAN MODE)".freeze].freeze
- Dataset.def_sql_method(self, :delete, %w'delete from where order limit')
+ Dataset.def_sql_method(self, :delete, %w'with delete from where order limit')
Dataset.def_sql_method(self, :insert, %w'insert ignore into columns values on_duplicate_key_update')
Dataset.def_sql_method(self, :select, %w'with select distinct calc_found_rows columns from join where group having compounds order limit lock')
- Dataset.def_sql_method(self, :update, %w'update ignore table set where order limit')
+ Dataset.def_sql_method(self, :update, %w'with update ignore table set where order limit')
include Sequel::Dataset::Replace
include UnmodifiedIdentifiers::DatasetMethods
def complex_expression_sql_append(sql, op, args)
@@ -577,10 +579,16 @@
super(sql, op, [args[0], ds.from_self])
else
super
end
when :~, :'!~', :'~*', :'!~*', :LIKE, :'NOT LIKE', :ILIKE, :'NOT ILIKE'
+ if !db.mariadb? && db.server_version >= 80000 && [:~, :'!~'].include?(op)
+ func = Sequel.function(:REGEXP_LIKE, args[0], args[1], 'c')
+ func = ~func if op == :'!~'
+ return literal_append(sql, func)
+ end
+
sql << '('
literal_append(sql, args[0])
sql << ' '
sql << 'NOT ' if [:'NOT LIKE', :'NOT ILIKE', :'!~', :'!~*'].include?(op)
sql << ([:~, :'!~', :'~*', :'!~*'].include?(op) ? 'REGEXP' : 'LIKE')
@@ -649,11 +657,11 @@
# :extended :: Use EXPLAIN EXPTENDED instead of EXPLAIN if true.
def explain(opts=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
+ ds = db.send(:metadata_dataset).with_sql(((opts[:extended] && (db.mariadb? || db.server_version < 50700)) ? '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.
@@ -729,12 +737,20 @@
# MySQL uses the nonstandard ` (backtick) for quoting identifiers.
def quoted_identifier_append(sql, c)
sql << '`' << c.to_s.gsub('`', '``') << '`'
end
+ # MariaDB 10.2+ and MySQL 8+ support CTEs
def supports_cte?(type=:select)
- type == :select && db.mariadb? && db.server_version >= 100200
+ if db.mariadb?
+ type == :select && db.server_version >= 100200
+ else
+ case type
+ when :select, :update, :delete
+ db.server_version >= 80000
+ end
+ end
end
# MySQL does not support derived column lists
def supports_derived_column_lists?
false
@@ -764,10 +780,15 @@
# MySQL supports modifying joined datasets
def supports_modifying_joins?
true
end
+ # MySQL 8+ supports NOWAIT.
+ def supports_nowait?
+ !db.mariadb? && db.server_version >= 80000
+ end
+
# MySQL's DISTINCT ON emulation using GROUP BY does not respect the
# query's ORDER BY clause.
def supports_ordered_distinct_on?
false
end
@@ -775,18 +796,24 @@
# MySQL supports pattern matching via regular expressions
def supports_regexp?
true
end
+ # MySQL 8+ supports SKIP LOCKED.
+ def supports_skip_locked?
+ !db.mariadb? && db.server_version >= 80000
+ end
+
# Check the database setting for whether fractional timestamps
# are suppported.
def supports_timestamp_usecs?
db.supports_timestamp_usecs?
end
+ # MariaDB 10.2+ and MySQL 8+ support window functions
def supports_window_functions?
- db.mariadb? && db.server_version >= 100200
+ db.server_version >= (db.mariadb? ? 100200 : 80000)
end
# Sets up the update methods to use UPDATE IGNORE.
# Useful if you have a unique key and want to just skip
# updating rows that violate the unique key restriction.
@@ -944,11 +971,29 @@
literal_append(sql, @opts[:offset])
sql << ",18446744073709551615"
end
# Support FOR SHARE locking when using the :share lock style.
+ # Use SKIP LOCKED if skipping locked rows.
def select_lock_sql(sql)
- @opts[:lock] == :share ? (sql << ' LOCK IN SHARE MODE') : super
+ lock = @opts[:lock]
+ if lock == :share
+ if !db.mariadb? && db.server_version >= 80000
+ sql << ' FOR SHARE'
+ else
+ sql << ' LOCK IN SHARE MODE'
+ end
+ else
+ super
+ end
+
+ if lock
+ if @opts[:skip_locked]
+ sql << " SKIP LOCKED"
+ elsif @opts[:nowait]
+ sql << " NOWAIT"
+ end
+ end
end
# MySQL specific SQL_CALC_FOUND_ROWS option
def select_calc_found_rows_sql(sql)
sql << ' SQL_CALC_FOUND_ROWS' if opts[:calc_found_rows]