1383: def transaction(*arguments)
1384: isolation_level = nil
1385: records = []
1386: unless_open_mode = false
1387: arguments.flatten.each do |argument|
1388: if argument.kind_of? FlexiRecord::IsolationLevel
1389: isolation_level_argument = argument
1390: elsif argument.respond_to? :to_sym
1391: isolation_level_argument = FlexiRecord::IsolationLevel.by_symbol(argument)
1392: end
1393: if argument.nil?
1394:
1395: elsif argument == :unless_open
1396: unless_open_mode = true
1397: elsif isolation_level_argument
1398: unless isolation_level.nil?
1399: raise ArgumentError, "Multiple isolation levels given."
1400: end
1401: isolation_level = isolation_level_argument
1402: elsif argument.kind_of? Symbol
1403: raise ArgumentError, "Unknown symbol #{argument.inspect} given as argument to transaction method."
1404: else
1405: records << argument
1406: end
1407: end
1408: if unless_open_mode and not records.empty?
1409: raise ArgumentError, "No records may be specified, if a transaction is started 'unless_open'."
1410: end
1411: synchronize do
1412: if unless_open_mode and transaction?
1413: return yield
1414: end
1415: backup = records.collect { |record| record.dup }
1416: old_stacklevel = @transaction_stacklevel
1417: success = true
1418: begin
1419: if @transaction_stacklevel == 0
1420: @isolation_level = isolation_level
1421: if isolation_level
1422: execute("BEGIN TRANSACTION ISOLATION LEVEL #{isolation_level}")
1423: else
1424: execute('BEGIN TRANSACTION')
1425: end
1426: else
1427: execute('SAVEPOINT "FlexiRecord_' << @transaction_stacklevel.to_s << '"')
1428: end
1429: @transaction_stacklevel += 1
1430: return yield
1431: rescue StandardError
1432: success = false
1433: raise $!
1434: ensure
1435: @transaction_stacklevel = old_stacklevel
1436: if success
1437: if old_stacklevel == 0
1438: execute('COMMIT TRANSACTION')
1439: else
1440: execute('RELEASE SAVEPOINT "FlexiRecord_' << @transaction_stacklevel.to_s << '"')
1441: end
1442: else
1443: if old_stacklevel == 0
1444: @isolation_level = 0
1445: execute('ROLLBACK TRANSACTION')
1446: else
1447: execute('ROLLBACK TO SAVEPOINT "FlexiRecord_' << @transaction_stacklevel.to_s << '"')
1448: execute('RELEASE SAVEPOINT "FlexiRecord_' << @transaction_stacklevel.to_s << '"')
1449: end
1450: backup.each_index do |record_index|
1451: records[record_index].replace(backup[record_index])
1452: end
1453: end
1454: end
1455: end
1456: end