lib/sequel/adapters/shared/mysql.rb in sequel-3.12.1 vs lib/sequel/adapters/shared/mysql.rb in sequel-3.13.0
- old
+ new
@@ -28,10 +28,16 @@
# database type.
def cast_type_literal(type)
CAST_TYPES[type] || super
end
+ # Commit an existing prepared transaction with the given transaction
+ # identifier string.
+ def commit_prepared_transaction(transaction_id)
+ run("XA COMMIT #{literal(transaction_id)}")
+ end
+
# MySQL uses the :mysql database type
def database_type
:mysql
end
@@ -50,10 +56,16 @@
i[:columns] << m.call(r[:Column_name])
end
indexes.reject{|k,v| remove_indexes.include?(k)}
end
+ # Rollback an existing prepared transaction with the given transaction
+ # identifier string.
+ def rollback_prepared_transaction(transaction_id)
+ run("XA ROLLBACK #{literal(transaction_id)}")
+ end
+
# Get version of MySQL server, used for determined capabilities.
def server_version
m = /(\d+)\.(\d+)\.(\d+)/.match(get(SQL::Function.new(:version)))
@server_version ||= (m[1].to_i * 10000) + (m[2].to_i * 100) + m[3].to_i
end
@@ -65,15 +77,25 @@
def tables(opts={})
m = output_identifier_meth
metadata_dataset.with_sql('SHOW TABLES').server(opts[:server]).map{|r| m.call(r.values.first)}
end
+ # MySQL supports prepared transactions (two-phase commit) using XA
+ def supports_prepared_transactions?
+ true
+ end
+
# MySQL supports savepoints
def supports_savepoints?
true
end
+ # MySQL supports transaction isolation levels
+ def supports_transaction_isolation_levels?
+ true
+ end
+
# 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}"
@@ -115,17 +137,45 @@
# Use MySQL specific AUTO_INCREMENT text.
def auto_increment_sql
AUTO_INCREMENT
end
+ # MySQL needs to set transaction isolation before begining a transaction
+ def begin_new_transaction(conn, opts)
+ set_transaction_isolation(conn, opts)
+ log_connection_execute(conn, begin_transaction_sql)
+ end
+
+ # Use XA START to start a new prepared transaction if the :prepare
+ # option is given.
+ def begin_transaction(conn, opts={})
+ if s = opts[:prepare]
+ log_connection_execute(conn, "XA START #{literal(s)}")
+ conn
+ else
+ super
+ end
+ 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
+ # Prepare the XA transaction for a two-phase commit if the
+ # :prepare option is given.
+ def commit_transaction(conn, opts={})
+ if s = opts[:prepare]
+ log_connection_execute(conn, "XA END #{literal(s)}")
+ log_connection_execute(conn, "XA PREPARE #{literal(s)}")
+ else
+ super
+ end
+ end
+
# Use MySQL specific syntax for engine type and character encoding
def create_table_sql(name, generator, options = {})
engine = options.fetch(:engine, Sequel::MySQL.default_engine)
charset = options.fetch(:charset, Sequel::MySQL.default_charset)
collate = options.fetch(:collate, Sequel::MySQL.default_collate)
@@ -160,10 +210,21 @@
"UNIQUE " if index[:unique]
end
"CREATE #{index_type}INDEX #{index_name}#{using} ON #{quote_schema_table(table_name)} #{literal(index[:columns])}"
end
+ # Rollback the currently open XA transaction
+ def rollback_transaction(conn, opts={})
+ if s = opts[:prepare]
+ log_connection_execute(conn, "XA END #{literal(s)}")
+ log_connection_execute(conn, "XA PREPARE #{literal(s)}")
+ log_connection_execute(conn, "XA ROLLBACK #{literal(s)}")
+ else
+ super
+ end
+ end
+
# MySQL treats integer primary keys as autoincrementing.
def schema_autoincrementing_primary_key?(schema)
super and schema[:db_type] =~ /int/io
end
@@ -238,9 +299,11 @@
if args.length > 1
"CONCAT(#{args.collect{|a| literal(a)}.join(', ')})"
else
literal(args.at(0))
end
+ when :'B~'
+ "CAST(~#{literal(args.at(0))} AS SIGNED INTEGER)"
else
super(op, args)
end
end