sequel 5.15.0 → 5.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG +28 -0
- data/bin/sequel +4 -0
- data/doc/opening_databases.rdoc +1 -1
- data/doc/release_notes/5.16.0.txt +110 -0
- data/doc/transactions.rdoc +48 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +14 -28
- data/lib/sequel/adapters/mysql.rb +2 -6
- data/lib/sequel/adapters/shared/sqlite.rb +16 -2
- data/lib/sequel/database/transactions.rb +66 -13
- data/lib/sequel/dataset/sql.rb +12 -1
- data/lib/sequel/extensions/migration.rb +4 -3
- data/lib/sequel/model/associations.rb +15 -3
- data/lib/sequel/model/base.rb +5 -3
- data/lib/sequel/plugins/class_table_inheritance.rb +6 -4
- data/lib/sequel/plugins/nested_attributes.rb +4 -1
- data/lib/sequel/version.rb +1 -1
- data/spec/bin_spec.rb +7 -0
- data/spec/core/database_spec.rb +98 -1
- data/spec/core/expression_filters_spec.rb +13 -1
- data/spec/extensions/class_table_inheritance_spec.rb +45 -1
- data/spec/extensions/migration_spec.rb +15 -4
- data/spec/extensions/nested_attributes_spec.rb +40 -0
- data/spec/extensions/pg_array_associations_spec.rb +8 -8
- data/spec/extensions/pg_array_ops_spec.rb +5 -5
- data/spec/extensions/pg_hstore_ops_spec.rb +9 -9
- data/spec/extensions/pg_row_ops_spec.rb +2 -2
- data/spec/extensions/sql_expr_spec.rb +1 -1
- data/spec/extensions/string_agg_spec.rb +1 -1
- data/spec/integration/dataset_test.rb +1 -1
- data/spec/integration/transaction_test.rb +199 -0
- data/spec/model/associations_spec.rb +31 -0
- data/spec/model/base_spec.rb +49 -0
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 50240675066a0bd3e480a52ba3ff556b962ae3d8403fb22ee210272f2fffb023
|
4
|
+
data.tar.gz: d1c86ff37811732211b00b251c49bf7c4929ca7b18bf7c6ffeda1b8d0335482f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a5a5b35a91ff83c6a0dab3e5cb88e26d79dced018f46fa78ad8be2b4da37c602adba56f849c0591c12f976006ea6e511bb3153478e70f3824ac940772f14de6
|
7
|
+
data.tar.gz: 50f5217691ec39036999623ce8d791fc93c270876d857e30b53892def7d36e0f3c99a3c69b13f97162f45b49dd066f1a5fcbf8b9660f96a1cd5c0c5a23c9ee72
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,31 @@
|
|
1
|
+
=== 5.16.0 (2019-01-02)
|
2
|
+
|
3
|
+
* Convert integer columns to bigint columns when copying SQLite databases to other databases using bin/sequel -C (jeremyevans) (#1584)
|
4
|
+
|
5
|
+
* Use nicer error messages for missing or empty migration directories (Lavode) (#1585)
|
6
|
+
|
7
|
+
* Make alter table emulation work correctly in SQLite 3.26.0+ (jeremyevans) (#1582)
|
8
|
+
|
9
|
+
* Do not unset new one_to_one associated objects' reciprocal associations before saving associated objects in the nested_attributes plugin (jeremyevans)
|
10
|
+
|
11
|
+
* Do not validate new one_to_one associated objects twice when saving in the nested_attributes plugin (jeremyevans)
|
12
|
+
|
13
|
+
* Fix :qualify_tables option to class_table_inheritance plugin to work correctly with subclasses of subclasses (benalavi) (#1581)
|
14
|
+
|
15
|
+
* Make class_table_inheritance plugin use the schema cache instead of sending a query to get columns for tables (kenaniah) (#1580)
|
16
|
+
|
17
|
+
* Remove loading of mysqlplus in the mysql adapter (jeremyevans)
|
18
|
+
|
19
|
+
* Make mysql adapter work correctly on ruby 2.6+ (jeremyevans)
|
20
|
+
|
21
|
+
* Add Database#rollback_on_exit to rollback transactions instead of committing them when exiting the transaction block (jeremyevans)
|
22
|
+
|
23
|
+
* Enable window functions in SQLite 3.26.0+ (jeremyevans)
|
24
|
+
|
25
|
+
* Do not override existing methods when creating Sequel::Model attribute getter/setter methods (jeremyevans) (#1578)
|
26
|
+
|
27
|
+
* Use parentheses for expressions being subscripted (e.g. (array_agg(column))[1]) (jeremyevans)
|
28
|
+
|
1
29
|
=== 5.15.0 (2018-12-01)
|
2
30
|
|
3
31
|
* Add :conn_str option in the postgres adapter for PostgreSQL connection strings, if the pg driver is used (graywolf) (#1572)
|
data/bin/sequel
CHANGED
@@ -195,6 +195,10 @@ begin
|
|
195
195
|
same_db = DB.database_type==TO_DB.database_type
|
196
196
|
index_opts = {:same_db=>same_db}
|
197
197
|
index_opts[:index_names] = :namespace if !DB.global_index_namespace? && TO_DB.global_index_namespace?
|
198
|
+
if DB.database_type == :sqlite && !same_db
|
199
|
+
# SQLite integer types allows 64-bit integers
|
200
|
+
TO_DB.extension :integer64
|
201
|
+
end
|
198
202
|
|
199
203
|
puts "Databases connections successful"
|
200
204
|
schema_migration = eval(DB.dump_schema_migration(:indexes=>false, :same_db=>same_db))
|
data/doc/opening_databases.rdoc
CHANGED
@@ -233,7 +233,7 @@ jdbc-h2 :: jdbc-h2 versions greater than 1.3.175 have issues with ORDER BY not w
|
|
233
233
|
|
234
234
|
=== mysql
|
235
235
|
|
236
|
-
Requires:
|
236
|
+
Requires: mysql
|
237
237
|
|
238
238
|
The MySQL adapter does not support the pure-ruby mysql.rb driver, it requires the C-extension driver.
|
239
239
|
|
@@ -0,0 +1,110 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* Database#rollback_on_exit has been added, which allows you to
|
4
|
+
rollback transactions instead of committing them when exiting
|
5
|
+
the transaction block. Previously, the only way to rollback
|
6
|
+
a transaction from inside a transaction block was to raise
|
7
|
+
an exception. This allows you to tell Sequel to roll the
|
8
|
+
transaction back on exit, and then use return or throw to exit
|
9
|
+
the transaction block.
|
10
|
+
|
11
|
+
Database#rollback_on_exit supports savepoints, including
|
12
|
+
multiple savepoint levels, as well as canceling rollbacks:
|
13
|
+
|
14
|
+
DB.transaction do # BEGIN
|
15
|
+
DB.rollback_on_exit
|
16
|
+
end # ROLLBACK
|
17
|
+
|
18
|
+
DB.transaction do # BEGIN
|
19
|
+
DB.transaction(savepoint: true) do # SAVEPOINT
|
20
|
+
DB.rollback_on_exit(savepoint: true)
|
21
|
+
end # ROLLBACK TO SAVEPOINT
|
22
|
+
end # COMMIT
|
23
|
+
|
24
|
+
DB.transaction do # BEGIN
|
25
|
+
DB.transaction(savepoint: true) do # SAVEPOINT
|
26
|
+
DB.transaction(savepoint: true) do # SAVEPOINT
|
27
|
+
DB.rollback_on_exit(savepoint: true)
|
28
|
+
end # ROLLBACK TO SAVEPOINT
|
29
|
+
end # RELEASE SAVEPOINT
|
30
|
+
end # COMMIT
|
31
|
+
|
32
|
+
DB.transaction do # BEGIN
|
33
|
+
DB.transaction(savepoint: true) do # SAVEPOINT
|
34
|
+
DB.rollback_on_exit(savepoint: true)
|
35
|
+
end # ROLLBACK TO SAVEPOINT
|
36
|
+
end # COMMIT
|
37
|
+
|
38
|
+
DB.transaction do # BEGIN
|
39
|
+
DB.transaction(savepoint: true) do # SAVEPOINT
|
40
|
+
DB.transaction(savepoint: true) do # SAVEPOINT
|
41
|
+
DB.rollback_on_exit(savepoint: 2)
|
42
|
+
end # ROLLBACK TO SAVEPOINT
|
43
|
+
end # ROLLBACK TO SAVEPOINT
|
44
|
+
end # COMMIT
|
45
|
+
|
46
|
+
DB.transaction do # BEGIN
|
47
|
+
DB.transaction(savepoint: true) do # SAVEPOINT
|
48
|
+
DB.transaction(savepoint: true) do # SAVEPOINT
|
49
|
+
DB.rollback_on_exit(savepoint: 3)
|
50
|
+
end # ROLLBACK TO SAVEPOINT
|
51
|
+
end # ROLLBACK TO SAVEPOINT
|
52
|
+
end # ROLLBACK
|
53
|
+
|
54
|
+
DB.transaction do # BEGIN
|
55
|
+
DB.rollback_on_exit
|
56
|
+
DB.rollback_on_exit(cancel: true)
|
57
|
+
end # COMMIT
|
58
|
+
|
59
|
+
* Sequel now supports window functions on SQLite 3.26.0+. SQLite
|
60
|
+
technically supports window functions on 3.25.0+, but enabling
|
61
|
+
window function support in Sequel opens up a code path that
|
62
|
+
generates queries that cause older versions of SQLite to produce a
|
63
|
+
segmentation fault. This bug in SQLite has been fixed in 3.26.0.
|
64
|
+
|
65
|
+
= Other Improvements
|
66
|
+
|
67
|
+
* Sequel::Model no longer overrides existing methods when defining
|
68
|
+
getters and setters. Historically, it only checked for existing
|
69
|
+
method definitions for methods that could be directly expressed
|
70
|
+
(e.g. not requiring send). Sequel 5 broke the check for setter
|
71
|
+
methods that could be directly expressed. This fixes cases where
|
72
|
+
model inheritance is used and the setter methods are overridden
|
73
|
+
in a parent class.
|
74
|
+
|
75
|
+
* Alter table emulation now works correctly on SQLite 3.26.0+.
|
76
|
+
|
77
|
+
* The one_to_one association setter does not modify reciprocal
|
78
|
+
associations in cases where doing so is not necessary. This can
|
79
|
+
fix some cases where the nested_attributes plugin is used.
|
80
|
+
|
81
|
+
* The class_table_inheritance plugin can now take advantage of the
|
82
|
+
schema_caching extension to prevent database queries to determine
|
83
|
+
column information when the class is created.
|
84
|
+
|
85
|
+
* The nested_attributes plugin no longer validates one_to_one
|
86
|
+
associations twice when saving.
|
87
|
+
|
88
|
+
* The class_table_inheritance plugin :qualify_tables option now
|
89
|
+
correctly qualifies subclasses of subclasses.
|
90
|
+
|
91
|
+
* SQL expressions that are subscripted are now wrapped in parentheses.
|
92
|
+
This fixes at least subscripting a function expression on
|
93
|
+
PostgreSQL:
|
94
|
+
|
95
|
+
DB[:t].select{array_agg(column).sql_subscript(1)}
|
96
|
+
# SELECT (array_agg(column))[1] FROM t
|
97
|
+
|
98
|
+
* Sequel::Migrator now uses more descriptive error messages if a
|
99
|
+
missing or empty migration directory is given.
|
100
|
+
|
101
|
+
* bin/sequel -C when converting from SQLite to another database
|
102
|
+
type will now use 64-bit integer columns in the other database when
|
103
|
+
the SQLite column type is integer, as SQLite supports storing
|
104
|
+
64-bit values in integer columns, and most other databases only
|
105
|
+
support 32-bit values in integer columns.
|
106
|
+
|
107
|
+
= Backwards Compatibility
|
108
|
+
|
109
|
+
* The mysql adapter no longer attempts to load the mysqlplus driver,
|
110
|
+
it now only attempts to load the mysql driver.
|
data/doc/transactions.rdoc
CHANGED
@@ -36,6 +36,12 @@ If any other exception is raised, the transaction is rolled back, and the except
|
|
36
36
|
end # ROLLBACK
|
37
37
|
# ArgumentError raised
|
38
38
|
|
39
|
+
If you want the current transaction to be rolled back when the transaction block exits instead of being committed (even if an exception is not raised), use <tt>Database#rollback_on_exit</tt>
|
40
|
+
|
41
|
+
DB.transaction do # BEGIN
|
42
|
+
DB.rollback_on_exit
|
43
|
+
end # ROLLBACK
|
44
|
+
|
39
45
|
If you want Sequel::Rollback exceptions to be reraised, use the <tt>rollback: :reraise</tt> option:
|
40
46
|
|
41
47
|
DB.transaction(rollback: :reraise) do # BEGIN
|
@@ -121,6 +127,48 @@ Other exceptions, unless rescued inside the outer transaction block, will rollba
|
|
121
127
|
end # ROLLBACK
|
122
128
|
# ArgumentError raised
|
123
129
|
|
130
|
+
If you want the current savepoint to be rolled back when the savepoint block exits instead of being committed (even if an exception is not raised), use <tt>Database#rollback_on_exit(:savepoint=>true)</tt>
|
131
|
+
|
132
|
+
DB.transaction do # BEGIN
|
133
|
+
DB.transaction(savepoint: true) do # SAVEPOINT
|
134
|
+
DB.rollback_on_exit(:savepoint=>true)
|
135
|
+
end # ROLLBACK TO SAVEPOINT
|
136
|
+
end # COMMIT
|
137
|
+
|
138
|
+
DB.transaction do # BEGIN
|
139
|
+
DB.transaction(savepoint: true) do # SAVEPOINT
|
140
|
+
DB.transaction(savepoint: true) do # SAVEPOINT
|
141
|
+
DB.rollback_on_exit(:savepoint=>true)
|
142
|
+
end # ROLLBACK TO SAVEPOINT
|
143
|
+
end # RELEASE SAVEPOINT
|
144
|
+
end # COMMIT
|
145
|
+
|
146
|
+
If you want the current savepoint to be rolled back when the savepoint block exits (even if an exception is not raised), use <tt>Database#rollback_on_exit(:savepoint=>true)</tt>
|
147
|
+
|
148
|
+
DB.transaction do # BEGIN
|
149
|
+
DB.transaction(savepoint: true) do # SAVEPOINT
|
150
|
+
DB.rollback_on_exit(:savepoint=>true)
|
151
|
+
end # ROLLBACK TO SAVEPOINT
|
152
|
+
end # COMMIT
|
153
|
+
|
154
|
+
If you want the current savepoint and potentially enclosing savepoints to be rolled back when the savepoint blocks exit (even if an exception is not raised), use <tt>Database#rollback_on_exit(:savepoint=>integer)</tt>
|
155
|
+
|
156
|
+
DB.transaction do # BEGIN
|
157
|
+
DB.transaction(savepoint: true) do # SAVEPOINT
|
158
|
+
DB.transaction(savepoint: true) do # SAVEPOINT
|
159
|
+
DB.rollback_on_exit(:savepoint=>2)
|
160
|
+
end # ROLLBACK TO SAVEPOINT
|
161
|
+
end # ROLLBACK TO SAVEPOINT
|
162
|
+
end # COMMIT
|
163
|
+
|
164
|
+
DB.transaction do # BEGIN
|
165
|
+
DB.transaction(savepoint: true) do # SAVEPOINT
|
166
|
+
DB.transaction(savepoint: true) do # SAVEPOINT
|
167
|
+
DB.rollback_on_exit(:savepoint=>3)
|
168
|
+
end # ROLLBACK TO SAVEPOINT
|
169
|
+
end # ROLLBACK TO SAVEPOINT
|
170
|
+
end # ROLLBACK
|
171
|
+
|
124
172
|
== Prepared Transactions / Two-Phase Commit
|
125
173
|
|
126
174
|
Sequel supports database prepared transactions on PostgreSQL, MySQL, and H2. With prepared transactions, at the end of the transaction, the transaction is not immediately committed (it acts like a rollback). Later, you can call +commit_prepared_transaction+ to commit the transaction or +rollback_prepared_transaction+ to roll the transaction back. Prepared transactions are usually used with distributed databases to make sure all databases commit the same transaction or none of them do.
|
@@ -43,17 +43,15 @@ module Sequel
|
|
43
43
|
true
|
44
44
|
end
|
45
45
|
|
46
|
+
# JDBC savepoint object for the current savepoint for the connection.
|
47
|
+
def savepoint_obj(conn)
|
48
|
+
_trans(conn)[:savepoints][-1][:obj]
|
49
|
+
end
|
50
|
+
|
46
51
|
# Use JDBC connection's setAutoCommit to false to start transactions
|
47
52
|
def begin_transaction(conn, opts=OPTS)
|
48
|
-
if
|
49
|
-
|
50
|
-
if sps = th[:savepoint_objs]
|
51
|
-
sps << log_connection_yield('Transaction.savepoint', conn){conn.set_savepoint}
|
52
|
-
else
|
53
|
-
log_connection_yield('Transaction.begin', conn){conn.setAutoCommit(false)}
|
54
|
-
th[:savepoint_objs] = []
|
55
|
-
set_transaction_isolation(conn, opts)
|
56
|
-
end
|
53
|
+
if in_savepoint?(conn)
|
54
|
+
_trans(conn)[:savepoints][-1][:obj] = log_connection_yield('Transaction.savepoint', conn){conn.set_savepoint}
|
57
55
|
else
|
58
56
|
log_connection_yield('Transaction.begin', conn){conn.setAutoCommit(false)}
|
59
57
|
set_transaction_isolation(conn, opts)
|
@@ -62,12 +60,9 @@ module Sequel
|
|
62
60
|
|
63
61
|
# Use JDBC connection's commit method to commit transactions
|
64
62
|
def commit_transaction(conn, opts=OPTS)
|
65
|
-
if
|
66
|
-
|
67
|
-
|
68
|
-
log_connection_yield('Transaction.commit', conn){conn.commit}
|
69
|
-
elsif supports_releasing_savepoints?
|
70
|
-
log_connection_yield('Transaction.release_savepoint', conn){supports_releasing_savepoints? ? conn.release_savepoint(sps.last) : sps.last}
|
63
|
+
if in_savepoint?(conn)
|
64
|
+
if supports_releasing_savepoints?
|
65
|
+
log_connection_yield('Transaction.release_savepoint', conn){conn.release_savepoint(savepoint_obj(conn))}
|
71
66
|
end
|
72
67
|
else
|
73
68
|
log_connection_yield('Transaction.commit', conn){conn.commit}
|
@@ -77,13 +72,9 @@ module Sequel
|
|
77
72
|
# Use JDBC connection's setAutoCommit to true to enable non-transactional behavior
|
78
73
|
def remove_transaction(conn, committed)
|
79
74
|
if jdbc_level = _trans(conn)[:original_jdbc_isolation_level]
|
80
|
-
conn.setTransactionIsolation(jdbc_level)
|
75
|
+
log_connection_yield("Transaction.restore_isolation_level", conn){conn.setTransactionIsolation(jdbc_level)}
|
81
76
|
end
|
82
|
-
|
83
|
-
sps = _trans(conn)[:savepoint_objs]
|
84
|
-
conn.setAutoCommit(true) if sps.empty?
|
85
|
-
sps.pop
|
86
|
-
else
|
77
|
+
unless in_savepoint?(conn)
|
87
78
|
conn.setAutoCommit(true)
|
88
79
|
end
|
89
80
|
ensure
|
@@ -92,13 +83,8 @@ module Sequel
|
|
92
83
|
|
93
84
|
# Use JDBC connection's rollback method to rollback transactions
|
94
85
|
def rollback_transaction(conn, opts=OPTS)
|
95
|
-
if
|
96
|
-
|
97
|
-
if sps.empty?
|
98
|
-
log_connection_yield('Transaction.rollback', conn){conn.rollback}
|
99
|
-
else
|
100
|
-
log_connection_yield('Transaction.rollback_savepoint', conn){conn.rollback(sps.last)}
|
101
|
-
end
|
86
|
+
if in_savepoint?(conn)
|
87
|
+
log_connection_yield('Transaction.rollback_savepoint', conn){conn.rollback(savepoint_obj(conn))}
|
102
88
|
else
|
103
89
|
log_connection_yield('Transaction.rollback', conn){conn.rollback}
|
104
90
|
end
|
@@ -1,10 +1,6 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
|
-
|
4
|
-
require "mysqlplus"
|
5
|
-
rescue LoadError
|
6
|
-
require 'mysql'
|
7
|
-
end
|
3
|
+
require 'mysql'
|
8
4
|
raise(LoadError, "require 'mysql' did not define Mysql::CLIENT_MULTI_RESULTS!\n You are probably using the pure ruby mysql.rb driver,\n which Sequel does not support. You need to install\n the C based adapter, and make sure that the mysql.so\n file is loaded instead of the mysql.rb file.\n") unless defined?(Mysql::CLIENT_MULTI_RESULTS)
|
9
5
|
|
10
6
|
require_relative 'utils/mysql_mysql2'
|
@@ -21,7 +17,7 @@ module Sequel
|
|
21
17
|
# Hash with integer keys and callable values for converting MySQL types.
|
22
18
|
MYSQL_TYPES = {}
|
23
19
|
{
|
24
|
-
[0, 246] => ::
|
20
|
+
[0, 246] => ::Kernel.method(:BigDecimal),
|
25
21
|
[2, 3, 8, 9, 13, 247, 248] => tt.method(:integer),
|
26
22
|
[4, 5] => tt.method(:float),
|
27
23
|
[249, 250, 251, 252] => ::Sequel::SQL::Blob.method(:new)
|
@@ -177,7 +177,10 @@ module Sequel
|
|
177
177
|
# needed for drop column.
|
178
178
|
def apply_alter_table(table, ops)
|
179
179
|
fks = fetch("PRAGMA foreign_keys")
|
180
|
-
|
180
|
+
if fks
|
181
|
+
run "PRAGMA foreign_keys = 0"
|
182
|
+
run "PRAGMA legacy_alter_table = 1" if sqlite_version >= 32600
|
183
|
+
end
|
181
184
|
transaction do
|
182
185
|
if ops.length > 1 && ops.all?{|op| op[:op] == :add_constraint || op[:op] == :set_column_null}
|
183
186
|
null_ops, ops = ops.partition{|op| op[:op] == :set_column_null}
|
@@ -196,7 +199,10 @@ module Sequel
|
|
196
199
|
end
|
197
200
|
remove_cached_schema(table)
|
198
201
|
ensure
|
199
|
-
|
202
|
+
if fks
|
203
|
+
run "PRAGMA foreign_keys = 1"
|
204
|
+
run "PRAGMA legacy_alter_table = 0" if sqlite_version >= 32600
|
205
|
+
end
|
200
206
|
end
|
201
207
|
|
202
208
|
# SQLite supports limited table modification. You can add a column
|
@@ -725,6 +731,14 @@ module Sequel
|
|
725
731
|
false
|
726
732
|
end
|
727
733
|
|
734
|
+
# SQLite 3.25+ supports window functions. However, support is only enabled
|
735
|
+
# on SQLite 3.26.0+ because internal Sequel usage of window functions
|
736
|
+
# to implement eager loading of limited associations triggers
|
737
|
+
# an SQLite crash bug in versions 3.25.0-3.25.3.
|
738
|
+
def supports_window_functions?
|
739
|
+
db.sqlite_version >= 32600
|
740
|
+
end
|
741
|
+
|
728
742
|
private
|
729
743
|
|
730
744
|
# SQLite uses string literals instead of identifiers in AS clauses.
|
@@ -52,7 +52,48 @@ module Sequel
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
55
|
-
|
55
|
+
|
56
|
+
# When exiting the transaction block through methods other than an exception
|
57
|
+
# (e.g. normal exit, non-local return, or throw), set the current transaction
|
58
|
+
# to rollback instead of committing. This is designed for use in cases where
|
59
|
+
# you want to preform a non-local return but also want to rollback instead of
|
60
|
+
# committing.
|
61
|
+
# Options:
|
62
|
+
# :cancel :: Cancel the current rollback_on_exit setting, so exiting will commit instead
|
63
|
+
# of rolling back.
|
64
|
+
# :savepoint :: Rollback only the current savepoint if inside a savepoint.
|
65
|
+
# Can also be an positive integer value to rollback that number of enclosing savepoints,
|
66
|
+
# up to and including the transaction itself.
|
67
|
+
# If the database does not support savepoints, this option is ignored and the entire
|
68
|
+
# transaction is affected.
|
69
|
+
# :server :: The server/shard the transaction is being executed on.
|
70
|
+
def rollback_on_exit(opts=OPTS)
|
71
|
+
synchronize(opts[:server]) do |conn|
|
72
|
+
raise Error, "Cannot call Sequel:: Database#rollback_on_exit! unless inside a transaction" unless h = _trans(conn)
|
73
|
+
rollback = !opts[:cancel]
|
74
|
+
|
75
|
+
if supports_savepoints?
|
76
|
+
savepoints = h[:savepoints]
|
77
|
+
|
78
|
+
if level = opts[:savepoint]
|
79
|
+
level = 1 if level == true
|
80
|
+
raise Error, "invalid :savepoint option to Database#rollback_on_exit: #{level.inspect}" unless level.is_a?(Integer)
|
81
|
+
raise Error, "cannot pass nonpositive integer (#{level.inspect}) as :savepoint option to Database#rollback_on_exit" if level < 1
|
82
|
+
level.times do |i|
|
83
|
+
break unless savepoint = savepoints[-1 - i]
|
84
|
+
savepoint[:rollback_on_exit] = rollback
|
85
|
+
end
|
86
|
+
else
|
87
|
+
savepoints[0][:rollback_on_exit] = rollback
|
88
|
+
end
|
89
|
+
else
|
90
|
+
h[:rollback_on_exit] = rollback
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
nil
|
95
|
+
end
|
96
|
+
|
56
97
|
# Return true if already in a transaction given the options,
|
57
98
|
# false otherwise. Respects the :server option for selecting
|
58
99
|
# a shard.
|
@@ -164,7 +205,7 @@ module Sequel
|
|
164
205
|
end
|
165
206
|
end
|
166
207
|
|
167
|
-
if opts[:savepoint] != false && (stack = _trans(conn)[:savepoints]) && stack.last
|
208
|
+
if opts[:savepoint] != false && (stack = _trans(conn)[:savepoints]) && stack.last[:auto_savepoint]
|
168
209
|
opts[:savepoint] = true
|
169
210
|
end
|
170
211
|
|
@@ -242,10 +283,10 @@ module Sequel
|
|
242
283
|
|
243
284
|
if supports_savepoints?
|
244
285
|
if t = _trans(conn)
|
245
|
-
t[:savepoints].push(opts[:auto_savepoint])
|
286
|
+
t[:savepoints].push({:auto_savepoint=>opts[:auto_savepoint]})
|
246
287
|
return
|
247
288
|
else
|
248
|
-
hash[:savepoints] = [opts[:auto_savepoint]]
|
289
|
+
hash[:savepoints] = [{:auto_savepoint=>opts[:auto_savepoint]}]
|
249
290
|
if (prep = opts[:prepare]) && supports_prepared_transactions?
|
250
291
|
hash[:prepare] = prep
|
251
292
|
end
|
@@ -293,12 +334,8 @@ module Sequel
|
|
293
334
|
|
294
335
|
# Start a new database transaction or a new savepoint on the given connection.
|
295
336
|
def begin_transaction(conn, opts=OPTS)
|
296
|
-
if
|
297
|
-
|
298
|
-
begin_savepoint(conn, opts)
|
299
|
-
else
|
300
|
-
begin_new_transaction(conn, opts)
|
301
|
-
end
|
337
|
+
if in_savepoint?(conn)
|
338
|
+
begin_savepoint(conn, opts)
|
302
339
|
else
|
303
340
|
begin_new_transaction(conn, opts)
|
304
341
|
end
|
@@ -318,7 +355,7 @@ module Sequel
|
|
318
355
|
if exception
|
319
356
|
false
|
320
357
|
else
|
321
|
-
if
|
358
|
+
if rollback_on_transaction_exit?(conn, opts)
|
322
359
|
rollback_transaction(conn, opts)
|
323
360
|
false
|
324
361
|
else
|
@@ -359,10 +396,15 @@ module Sequel
|
|
359
396
|
[]
|
360
397
|
end
|
361
398
|
|
399
|
+
# Whether the connection is currently inside a savepoint.
|
400
|
+
def in_savepoint?(conn)
|
401
|
+
supports_savepoints? && savepoint_level(conn) > 1
|
402
|
+
end
|
403
|
+
|
362
404
|
# Retrieve the transaction hooks that should be run for the given
|
363
405
|
# connection and commit status.
|
364
406
|
def transaction_hooks(conn, committed)
|
365
|
-
|
407
|
+
unless in_savepoint?(conn)
|
366
408
|
_trans(conn)[committed ? :after_commit : :after_rollback]
|
367
409
|
end
|
368
410
|
end
|
@@ -372,7 +414,7 @@ module Sequel
|
|
372
414
|
callbacks = transaction_hooks(conn, committed)
|
373
415
|
|
374
416
|
if transaction_finished?(conn)
|
375
|
-
h =
|
417
|
+
h = _trans(conn)
|
376
418
|
rolled_back = !committed
|
377
419
|
Sequel.synchronize{h[:rolled_back] = rolled_back}
|
378
420
|
Sequel.synchronize{@transactions.delete(conn)}
|
@@ -386,6 +428,17 @@ module Sequel
|
|
386
428
|
"ROLLBACK TO SAVEPOINT autopoint_#{depth}"
|
387
429
|
end
|
388
430
|
|
431
|
+
# Whether to rollback the transaction when exiting the transaction.
|
432
|
+
def rollback_on_transaction_exit?(conn, opts)
|
433
|
+
return true if Thread.current.status == 'aborting'
|
434
|
+
h = _trans(conn)
|
435
|
+
if supports_savepoints?
|
436
|
+
h[:savepoints].last[:rollback_on_exit]
|
437
|
+
else
|
438
|
+
h[:rollback_on_exit]
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
389
442
|
# Rollback the active transaction on the connection
|
390
443
|
def rollback_transaction(conn, opts=OPTS)
|
391
444
|
if supports_savepoints?
|