Permalink
Browse files

Support transactions on MSSQL

This commit supports transactions on MSSQL, which requires an
explicit TRANSACTION keyword to work.  It does this by adding private
Database methods (begin|rollback|commit)_transaction_sql, and
overridding them in the MSSQL shared adapter.  The default
transaction method uses these methods, and most of the other adapters
that override the transaction method also use these methods (the
PostgreSQL adapter being an exception).
  • Loading branch information...
1 parent 0eb2fd7 commit b9eeb3b7a4bf8318f0b379079af89e93ff1daaf1 @jeremyevans committed Sep 15, 2008
View
2 CHANGELOG
@@ -1,5 +1,7 @@
=== HEAD
+* Support transactions on MSSQL (jeremyevans)
+
* Use string literals in AS clauses on SQLite (jeremyevans) (#241)
* AlterTableGenerator#set_column_allow_null was added to SET/DROP NOT NULL for columns (divoxx)
View
14 lib/sequel_core/adapters/jdbc.rb
@@ -154,18 +154,18 @@ def transaction(server=nil)
return yield(conn) if @transactions.include?(Thread.current)
stmt = conn.createStatement
begin
- log_info(Sequel::Database::SQL_BEGIN)
- stmt.execute(Sequel::Database::SQL_BEGIN)
+ log_info(begin_transaction_sql)
+ stmt.execute(begin_transaction_sql)
@transactions << Thread.current
yield(conn)
rescue Exception => e
- log_info(Sequel::Database::SQL_ROLLBACK)
- stmt.execute(Sequel::Database::SQL_ROLLBACK)
- raise e unless Error::Rollback === e
+ log_info(rollback_transaction_sql)
+ stmt.execute(rollback_transaction_sql)
+ transaction_error(e)
ensure
unless e
- log_info(Sequel::Database::SQL_COMMIT)
- stmt.execute(Sequel::Database::SQL_COMMIT)
+ log_info(commit_transaction_sql)
+ stmt.execute(commit_transaction_sql)
end
stmt.close
@transactions.delete(Thread.current)
View
12 lib/sequel_core/adapters/mysql.rb
@@ -150,19 +150,19 @@ def server_version(server=nil)
def transaction(server=nil)
synchronize(server) do |conn|
return yield(conn) if @transactions.include?(Thread.current)
- log_info(SQL_BEGIN)
- conn.query(SQL_BEGIN)
+ log_info(begin_transaction_sql)
+ conn.query(begin_transaction_sql)
begin
@transactions << Thread.current
yield(conn)
rescue ::Exception => e
- log_info(SQL_ROLLBACK)
- conn.query(SQL_ROLLBACK)
+ log_info(rollback_transaction_sql)
+ conn.query(rollback_transaction_sql)
transaction_error(e, Mysql::Error)
ensure
unless e
- log_info(SQL_COMMIT)
- conn.query(SQL_COMMIT)
+ log_info(commit_transaction_sql)
+ conn.query(commit_transaction_sql)
end
@transactions.delete(Thread.current)
end
View
22 lib/sequel_core/adapters/shared/mssql.rb
@@ -2,16 +2,36 @@ module Sequel
module MSSQL
module DatabaseMethods
AUTO_INCREMENT = 'IDENTITY(1,1)'.freeze
+ SQL_BEGIN = "BEGIN TRANSACTION".freeze
+ SQL_COMMIT = "COMMIT TRANSACTION".freeze
+ SQL_ROLLBACK = "ROLLBACK TRANSACTION".freeze
def auto_increment_sql
AUTO_INCREMENT
end
-
+
def dataset(opts = nil)
ds = super
ds.extend(DatasetMethods)
ds
end
+
+ private
+
+ # SQL to BEGIN a transaction.
+ def begin_transaction_sql
+ SQL_BEGIN
+ end
+
+ # SQL to COMMIT a transaction.
+ def commit_transaction_sql
+ SQL_COMMIT
+ end
+
+ # SQL to ROLLBACK a transaction.
+ def rollback_transaction_sql
+ SQL_ROLLBACK
+ end
end
module DatasetMethods
View
3 lib/sequel_core/adapters/shared/mysql.rb
@@ -7,9 +7,6 @@ module DatabaseMethods
NOT_NULL = Sequel::Schema::SQL::NOT_NULL
NULL = Sequel::Schema::SQL::NULL
PRIMARY_KEY = Sequel::Schema::SQL::PRIMARY_KEY
- SQL_BEGIN = Sequel::Database::SQL_BEGIN
- SQL_COMMIT = Sequel::Database::SQL_COMMIT
- SQL_ROLLBACK = Sequel::Database::SQL_ROLLBACK
TYPES = Sequel::Schema::SQL::TYPES
UNIQUE = Sequel::Schema::SQL::UNIQUE
UNSIGNED = Sequel::Schema::SQL::UNSIGNED
View
63 lib/sequel_core/database.rb
@@ -355,27 +355,27 @@ def test_connection(server=nil)
synchronize(server){|conn|}
true
end
-
+
# A simple implementation of SQL transactions. Nested transactions are not
# supported - calling #transaction within a transaction will reuse the
# current transaction. Should be overridden for databases that support nested
# transactions.
def transaction(server=nil)
synchronize(server) do |conn|
return yield(conn) if @transactions.include?(Thread.current)
- log_info(SQL_BEGIN)
- conn.execute(SQL_BEGIN)
+ log_info(begin_transaction_sql)
+ conn.execute(begin_transaction_sql)
begin
@transactions << Thread.current
yield(conn)
rescue Exception => e
- log_info(SQL_ROLLBACK)
- conn.execute(SQL_ROLLBACK)
+ log_info(rollback_transaction_sql)
+ conn.execute(rollback_transaction_sql)
transaction_error(e)
ensure
unless e
- log_info(SQL_COMMIT)
- conn.execute(SQL_COMMIT)
+ log_info(commit_transaction_sql)
+ conn.execute(commit_transaction_sql)
end
@transactions.delete(Thread.current)
end
@@ -471,6 +471,38 @@ def uri
private
+ # SQL to BEGIN a transaction.
+ def begin_transaction_sql
+ SQL_BEGIN
+ end
+
+ # SQL to COMMIT a transaction.
+ def commit_transaction_sql
+ SQL_COMMIT
+ end
+
+ # The default options for the connection pool.
+ def connection_pool_default_options
+ {}
+ end
+
+ # SQL to ROLLBACK a transaction.
+ def rollback_transaction_sql
+ SQL_ROLLBACK
+ end
+
+ # Convert the given exception to a DatabaseError, keeping message
+ # and traceback.
+ def raise_error(exception, opts={})
+ if !opts[:classes] || exception.is_one_of?(*opts[:classes])
+ e = DatabaseError.new("#{exception.class} #{exception.message}")
+ e.set_backtrace(exception.backtrace)
+ raise e
+ else
+ raise exception
+ end
+ end
+
# Return the options for the given server by merging the generic
# options for all server with the specific options for the given
# server specified in the :servers option.
@@ -491,23 +523,6 @@ def server_opts(server)
opts
end
- # The default options for the connection pool.
- def connection_pool_default_options
- {}
- end
-
- # Convert the given exception to a DatabaseError, keeping message
- # and traceback.
- def raise_error(exception, opts={})
- if !opts[:classes] || exception.is_one_of?(*opts[:classes])
- e = DatabaseError.new("#{exception.class} #{exception.message}")
- e.set_backtrace(exception.backtrace)
- raise e
- else
- raise exception
- end
- end
-
# Raise a database error unless the exception is an Error::Rollback.
def transaction_error(e, *classes)
raise_error(e, :classes=>classes) unless Error::Rollback === e

0 comments on commit b9eeb3b

Please sign in to comment.