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