sequel 3.44.0 → 3.45.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. data/CHANGELOG +44 -0
  2. data/Rakefile +12 -4
  3. data/doc/reflection.rdoc +3 -3
  4. data/doc/release_notes/3.45.0.txt +179 -0
  5. data/doc/schema_modification.rdoc +1 -1
  6. data/doc/transactions.rdoc +23 -0
  7. data/lib/sequel/adapters/db2.rb +1 -0
  8. data/lib/sequel/adapters/ibmdb.rb +19 -3
  9. data/lib/sequel/adapters/jdbc.rb +15 -0
  10. data/lib/sequel/adapters/jdbc/derby.rb +1 -5
  11. data/lib/sequel/adapters/jdbc/h2.rb +1 -0
  12. data/lib/sequel/adapters/jdbc/hsqldb.rb +2 -1
  13. data/lib/sequel/adapters/jdbc/jtds.rb +5 -0
  14. data/lib/sequel/adapters/jdbc/mysql.rb +5 -0
  15. data/lib/sequel/adapters/jdbc/oracle.rb +7 -1
  16. data/lib/sequel/adapters/jdbc/sqlite.rb +1 -1
  17. data/lib/sequel/adapters/jdbc/transactions.rb +28 -1
  18. data/lib/sequel/adapters/mysql.rb +4 -0
  19. data/lib/sequel/adapters/mysql2.rb +5 -1
  20. data/lib/sequel/adapters/oracle.rb +18 -0
  21. data/lib/sequel/adapters/postgres.rb +11 -1
  22. data/lib/sequel/adapters/shared/access.rb +14 -2
  23. data/lib/sequel/adapters/shared/cubrid.rb +1 -11
  24. data/lib/sequel/adapters/shared/db2.rb +11 -6
  25. data/lib/sequel/adapters/shared/mssql.rb +10 -10
  26. data/lib/sequel/adapters/shared/mysql.rb +11 -1
  27. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +17 -1
  28. data/lib/sequel/adapters/shared/oracle.rb +16 -15
  29. data/lib/sequel/adapters/shared/postgres.rb +91 -59
  30. data/lib/sequel/adapters/shared/sqlite.rb +1 -4
  31. data/lib/sequel/adapters/tinytds.rb +15 -0
  32. data/lib/sequel/connection_pool/threaded.rb +1 -1
  33. data/lib/sequel/core.rb +10 -0
  34. data/lib/sequel/database/connecting.rb +2 -0
  35. data/lib/sequel/database/misc.rb +46 -4
  36. data/lib/sequel/database/query.rb +33 -14
  37. data/lib/sequel/database/schema_methods.rb +0 -5
  38. data/lib/sequel/dataset/misc.rb +9 -0
  39. data/lib/sequel/dataset/mutation.rb +9 -7
  40. data/lib/sequel/dataset/sql.rb +13 -0
  41. data/lib/sequel/exceptions.rb +3 -0
  42. data/lib/sequel/extensions/connection_validator.rb +1 -1
  43. data/lib/sequel/extensions/date_arithmetic.rb +0 -8
  44. data/lib/sequel/extensions/eval_inspect.rb +2 -0
  45. data/lib/sequel/extensions/named_timezones.rb +18 -2
  46. data/lib/sequel/extensions/pg_array.rb +5 -1
  47. data/lib/sequel/extensions/pg_array_ops.rb +2 -0
  48. data/lib/sequel/extensions/pg_hstore.rb +2 -0
  49. data/lib/sequel/extensions/pg_hstore_ops.rb +2 -0
  50. data/lib/sequel/extensions/pg_json.rb +3 -1
  51. data/lib/sequel/extensions/pg_range.rb +2 -0
  52. data/lib/sequel/extensions/pg_range_ops.rb +2 -0
  53. data/lib/sequel/extensions/pg_row.rb +2 -0
  54. data/lib/sequel/extensions/pg_row_ops.rb +2 -0
  55. data/lib/sequel/extensions/query.rb +18 -22
  56. data/lib/sequel/model/associations.rb +3 -4
  57. data/lib/sequel/model/base.rb +2 -0
  58. data/lib/sequel/plugins/force_encoding.rb +2 -0
  59. data/lib/sequel/plugins/json_serializer.rb +155 -39
  60. data/lib/sequel/plugins/serialization.rb +14 -2
  61. data/lib/sequel/plugins/unlimited_update.rb +31 -0
  62. data/lib/sequel/plugins/validation_class_methods.rb +6 -4
  63. data/lib/sequel/plugins/xml_serializer.rb +133 -30
  64. data/lib/sequel/sql.rb +2 -0
  65. data/lib/sequel/timezones.rb +4 -0
  66. data/lib/sequel/version.rb +1 -1
  67. data/spec/adapters/mysql_spec.rb +0 -11
  68. data/spec/adapters/postgres_spec.rb +86 -54
  69. data/spec/adapters/spec_helper.rb +6 -0
  70. data/spec/core/connection_pool_spec.rb +16 -0
  71. data/spec/core/database_spec.rb +77 -1
  72. data/spec/core/dataset_spec.rb +30 -15
  73. data/spec/core/expression_filters_spec.rb +55 -13
  74. data/spec/core/mock_adapter_spec.rb +4 -0
  75. data/spec/core/schema_spec.rb +0 -2
  76. data/spec/core/spec_helper.rb +5 -0
  77. data/spec/core_extensions_spec.rb +33 -28
  78. data/spec/extensions/constraint_validations_spec.rb +2 -2
  79. data/spec/extensions/core_refinements_spec.rb +12 -12
  80. data/spec/extensions/json_serializer_spec.rb +137 -31
  81. data/spec/extensions/named_timezones_spec.rb +10 -0
  82. data/spec/extensions/pg_auto_parameterize_spec.rb +5 -0
  83. data/spec/extensions/pg_json_spec.rb +14 -0
  84. data/spec/extensions/pg_row_spec.rb +11 -0
  85. data/spec/extensions/pretty_table_spec.rb +2 -2
  86. data/spec/extensions/query_spec.rb +11 -8
  87. data/spec/extensions/serialization_spec.rb +20 -0
  88. data/spec/extensions/spec_helper.rb +8 -2
  89. data/spec/extensions/sql_expr_spec.rb +1 -1
  90. data/spec/extensions/unlimited_update_spec.rb +20 -0
  91. data/spec/extensions/xml_serializer_spec.rb +68 -16
  92. data/spec/integration/dataset_test.rb +28 -0
  93. data/spec/integration/spec_helper.rb +6 -0
  94. data/spec/integration/transaction_test.rb +39 -0
  95. data/spec/model/model_spec.rb +1 -1
  96. data/spec/sequel_coverage.rb +15 -0
  97. metadata +8 -3
data/CHANGELOG CHANGED
@@ -1,3 +1,47 @@
1
+ === 3.45.0 (2013-03-01)
2
+
3
+ * Remove bad model typecasting of money type on PostgreSQL (jeremyevans) (#624)
4
+
5
+ * Use simplecov instead of rcov for coverage testing on 1.9+ (jeremyevans)
6
+
7
+ * Make the Database#quote_identifier method public (jeremyevans)
8
+
9
+ * Make PostgreSQL metadata parsing handle tables with the same name in multiple schemas (jeremyevans)
10
+
11
+ * Switch query extension to use a proxy instead of Object#extend (chanks, jeremyevans)
12
+
13
+ * Remove Dataset#def_mutiation_method instance method (jeremyevans)
14
+
15
+ * Make foreign key parsing on MySQL not pick up foreign keys in other databases (jeremyevans)
16
+
17
+ * Allow per-instance overrides of Postgres.force_standard_strings and .client_min_messages (jeremyevans) (#618)
18
+
19
+ * Add Sequel.tzinfo_disambiguator= to the named_timezones plugin for automatically handling TZInfo::AmbiguousTime exceptions (jeremyevans) (#616)
20
+
21
+ * Add Dataset#escape_like, for escaping LIKE metacharacters (jeremyevans) (#614)
22
+
23
+ * The LIKE operators now use an explicit ESCAPE '\' clause for similar behavior across databases (jeremyevans)
24
+
25
+ * Make Database#tables and #views accept a :qualify option on PostgreSQL to return qualified identifiers (jeremyevans)
26
+
27
+ * Make json_serializer and xml_serializer plugins secure by default (jeremyevans)
28
+
29
+ * Address JSON.parse vulnerabilities (jeremyevans)
30
+
31
+ * Fix Dataset#from_self! to no longer create a self-referential dataset (jeremyevans)
32
+
33
+ * Use SQLSTATE or database error codes if available instead of regexp parsing for more specific DatabaseErrors (jeremyevans)
34
+
35
+ * Add unlimited_update plugin to work around MySQL warning in replicated environments (jeremyevans)
36
+
37
+ * Add the :retry_on and :num_retries transaction options for automatically retrying transactions (jeremyevans)
38
+
39
+ * Raise serialization failures/deadlocks as Sequel::SerializationFailure exceptions (jeremyevans)
40
+
41
+ * Support transaction isolation levels on Oracle and DB2 (jeremyevans)
42
+
43
+ * Support transaction isolation levels when using the JDBC transaction support (jeremyevans)
44
+
1
45
  === 3.44.0 (2013-02-04)
2
46
 
3
47
  * Speedup mysql2 adapter with identifier output method fetch speed by up to 50% (jeremyevans)
data/Rakefile CHANGED
@@ -125,10 +125,18 @@ begin
125
125
 
126
126
  spec_with_cov = lambda do |name, files, d, &b|
127
127
  spec.call(name, files, d)
128
- t = spec.call("#{name}_cov", files, "#{d} with coverage")
129
- t.rcov = true
130
- t.rcov_opts = File.read("spec/rcov.opts").split("\n")
131
- b.call(t) if b
128
+ if RUBY_VERSION < '1.9'
129
+ t = spec.call("#{name}_cov", files, "#{d} with coverage")
130
+ t.rcov = true
131
+ t.rcov_opts = File.read("spec/rcov.opts").split("\n")
132
+ b.call(t) if b
133
+ else
134
+ desc "#{d} with coverage"
135
+ task "#{name}_cov" do
136
+ ENV['COVERAGE'] = '1'
137
+ Rake::Task[name].invoke
138
+ end
139
+ end
132
140
  t
133
141
  end
134
142
 
@@ -99,12 +99,12 @@ You can get an array of association symbols with Model.associations:
99
99
 
100
100
  You can get the association reflection for a single association via the Model.association_reflection. Association reflections are subclasses of hash, for ease of use and introspection (and backwards compatibility):
101
101
 
102
- Model.association_reflection(:association1) # {:name=>:association1, :type=>:many_to_one, :model=>Model, :associated_class=>OtherModel, ...}
102
+ Model.association_reflection(:association1) # {:name=>:association1, :type=>:many_to_one, :model=>Model, ...}
103
103
 
104
104
  You can get an array of all association reflections via Model.all_association_reflections:
105
105
 
106
- Model.all_association_reflections # [{:name=>:association1, :type=>:many_to_one, :model=>Model, :associated_class=>OtherModel, ...}, ...]
106
+ Model.all_association_reflections # [{:name=>:association1, :type=>:many_to_one, :model=>Model, ...}, ...]
107
107
 
108
108
  Finally, you can get a hash of association reflections via Model.association_reflections:
109
109
 
110
- Model.association_reflections # {:association1=>{:name=>:association1, :type=>:many_to_one, :model=>Model, :associated_class=>OtherModel, ...}, ...}
110
+ Model.association_reflections # {:association1=>{:name=>:association1, :type=>:many_to_one, :model=>Model, ...}, ...}
@@ -0,0 +1,179 @@
1
+ = New Features
2
+
3
+ * Database#transaction now recognizes a :retry_on option, which
4
+ should contain an exception class or array of exception classes.
5
+ If the transaction raises one of the given exceptions, Sequel
6
+ will automatically retry the transaction block. It's a bad idea to
7
+ use this option if the transaction block is not idempotent.
8
+
9
+ By default, Sequel only retries the block 5 times by default,
10
+ to protect against infinite looping. You can change the number
11
+ of retries with the :num_retries option.
12
+
13
+ Users of the :disconnect=>:retry option are encouraged to switch
14
+ to :retry_on=>Sequel::DatabaseDisconnectError.
15
+
16
+ * Dataset#escape_like has been added for escaping LIKE
17
+ metacharacters. This is designed for the case where part of
18
+ the LIKE pattern is based on user input that should not treat the
19
+ metacharacters specially.
20
+
21
+ * Serialization failures/deadlocks are now raised as
22
+ Sequel::SerializationFailure exception instances. This exception
23
+ class is a good candidate for the transaction :retry_on option.
24
+
25
+ * On PostgreSQL, you can now provide the :force_standard_strings
26
+ and :client_min_messages Database options to override the defaults
27
+ on a per-instance basis.
28
+
29
+ * On PostgreSQL, Database#tables and #views now recognizes a
30
+ :qualify option, which if true will return qualified identifiers
31
+ instead of plain symbols.
32
+
33
+ * Transaction isolation levels are now supported on Oracle, DB2,
34
+ and all jdbc subadapters using the JDBC transaction support.
35
+
36
+ * Dataset.def_mutation_method now accepts a :module option for
37
+ the module in which to define the methods (defaulting to self).
38
+
39
+ * An unlimited_update plugin has been added. It's sole purpose is to
40
+ eliminate a MySQL warning in replicated environments, since by
41
+ default Sequel::Model uses a LIMIT clause when updating on MySQL.
42
+
43
+ * The named_timezones extension now adds a
44
+ Sequel.tzinfo_disambiguator accessor to automatically handle
45
+ TZInfo::AmbiguousTime exceptions. This should be a callable object
46
+ that accepts two arguments, a DateTime instance and an array of
47
+ timezone periods, and returns the timezone period to use.
48
+
49
+ = Other Improvements
50
+
51
+ * Sequel now handles JSON securely, specifying the
52
+ :create_additions=>false option when using JSON.parse. If you
53
+ really want to get the old vulnerable behavior back, override
54
+ Sequel.parse_json.
55
+
56
+ * The json_serializer and xml_serializer plugins are now secure
57
+ by default. Before, the default behavior of these plugins
58
+ allowed for round tripping, such that:
59
+
60
+ Album.from_xml(album.to_xml) == album
61
+
62
+ Unfortunately, that requires that the deserialization allow
63
+ the setting of any column. Since the plugins also handle
64
+ associations, you could also set any column in any associated
65
+ object, even cascading to associated objects of those objects.
66
+
67
+ The new default behavior only allows deserialization to set
68
+ the same columns that mass-assignment would set, and not to
69
+ handle associated objects at all by default. The following
70
+ additional options are supported:
71
+
72
+ :fields :: The specific fields to set (this was already supported
73
+ by the json_serializer plugin).
74
+ :associations :: The specific associations to handle.
75
+ :all_columns :: The previous behavior of setting all columns.
76
+ :all_associations :: The previous behavior of setting all
77
+ associations.
78
+
79
+ Since JSON parsing no longer deserializes into arbitrary ruby
80
+ instances, from_json and array_from_json class methods have been
81
+ added to the json_serializer plugin, for deserializing into model
82
+ instances. These mirror the from_xml and array_from_xml class
83
+ methods in the xml_serializer plugin.
84
+
85
+ Note that the :all_columns and :all_associations methods were
86
+ only added to make backwards compatibility easier. It is
87
+ likely they will be removed in Sequel 4, along with the
88
+ json_create class method.
89
+
90
+ * Sequel now attempts to use database specific error codes or
91
+ SQLState codes instead of regexp parsing to determine if a more
92
+ specific DatabaseError subclass should be used. This should make
93
+ error handling faster and more robust.
94
+
95
+ * Sequel now uses ESCAPE '\' when using LIKE, for similar behavior
96
+ across databases. Previously, no ESCAPE clause was used, so
97
+ behavior differed across databases, with most not using escaping,
98
+ and PostgreSQL, MySQL, and H2 defaulting to backslash as the escape
99
+ character.
100
+
101
+ * The query extension has been reimplemented and now uses a proxy
102
+ object instead of Object#extend.
103
+
104
+ * The :pool_timeout Database option now supports fractional seconds.
105
+
106
+ * Database#quote_identifier is now a public method.
107
+
108
+ * Metadata parsing (schema, indexes, foreign_key_list) on PostgreSQL
109
+ now correctly handles the case where an unqualified table name is
110
+ used and tables with that name exist in multiple schemas. It now
111
+ picks the first matching table in the schema_search_path, instead of
112
+ failing or returning results from all tables.
113
+
114
+ * Sequel::Model instances no longer attempt to typecast the money
115
+ type on PostgreSQL, since the previous typecast didn't work
116
+ correctly, and correct typecasting is locale-dependent.
117
+
118
+ * Sequel no longer picks up foreign keys for tables in other
119
+ databases when using Database#foreign_key_list on MySQL.
120
+
121
+ * A warning when using the mysql2 3.12 beta has been eliminated.
122
+
123
+ * A warning has been eliminated when using the jdbc/oracle adapter
124
+ on JRuby 1.7.
125
+
126
+ * Sequel's ilike emulation should now work by default on databases
127
+ without specific syntax support.
128
+
129
+ * Dataset#from_self! no longer creates a self referential dataset.
130
+
131
+ * Coverage testing now uses simplecov instead of rcov on ruby 1.9+.
132
+
133
+ = Backwards Compatibility
134
+
135
+ * The switch to using JSON.parse :create_additions=>false means
136
+ that if your app expected JSON to deserialize into arbitrary
137
+ ruby objects, it is probably broken. You should update your
138
+ application code to manually convert the deserialized hashes
139
+ into the ruby objects you want.
140
+
141
+ Note that it's not just this new version of Sequel that will
142
+ cause that, older versions of Sequel will break in the same
143
+ way if you update your JSON library to a version that is not
144
+ vulnerable by default.
145
+
146
+ This potentially affects the pg_json extension and serialization
147
+ plugin if you were expecting the JSON stored in the database
148
+ to be deserialized into arbitrary ruby objects.
149
+
150
+ See the json_serializer/xml_serializer changes mentioned in
151
+ the Other Improvements section.
152
+
153
+ * The reimplemented query extension is not completely backwards
154
+ compatible. For example, inside a query block, self refers to the
155
+ proxy object instead of a dataset, and calling methods that return
156
+ rows no longer raises an exception.
157
+
158
+ * The metadata parsing methods on PostgreSQL no longer work with
159
+ unqualified tables where the table is not in the schema search
160
+ path. This makes metadata parsing consistent with how datasets
161
+ operate. For tables outside the schema search path, you must
162
+ qualify it before use now.
163
+
164
+ Additionally, using a nonexistent table name will raise an
165
+ exception instead of returning empty results in some cases.
166
+
167
+ * The Dataset#def_mutation_method instance method has been removed.
168
+ This method added mutation methods directly on the dataset instance,
169
+ which is generally not desired. Using the def_mutation_method class
170
+ method with the :module option is now the recommended approach.
171
+
172
+ * The switch to using ESCAPE for LIKE characters is backwards
173
+ incompatible on databases that don't use escaping by default,
174
+ when backslash is used in a LIKE pattern as a regular character.
175
+ Now you have to double the backslash in the pattern.
176
+
177
+ * Database#database_error_regexps private method now can return any
178
+ enumerable yielding regexp/exception class pairs, it is no longer
179
+ specified to return a hash.
@@ -532,7 +532,7 @@ keys before the tables containing the primary keys they reference.
532
532
  === <tt>drop_table?</tt>
533
533
 
534
534
  <tt>drop_table?</tt> is similar to drop_table, except that it only drops
535
- the table if the table does not already exist. On some databases, it uses
535
+ the table if the table already exists. On some databases, it uses
536
536
  <tt>IF NOT EXISTS</tt>, on others it does a separate query to check for
537
537
  existence.
538
538
 
@@ -135,3 +135,26 @@ The SQL standard supports 4 isolation levels: READ UNCOMMITTED, READ COMMITTED,
135
135
  # SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
136
136
  DB[:foo].insert(1) # INSERT
137
137
  end # COMMIT
138
+
139
+ == Automatically Restarting Transactions
140
+
141
+ Sequel offers the ability to automatically restart transactions if specific types of errors are detected. For example, if you want to automatically restart a transaction if a serialization failure is detected:
142
+
143
+ DB.transaction(:isolation => :serializable, :retry_on=>[Sequel::SerializationFailure]) do
144
+ ModelClass.find_or_create(:name=>'Foo')
145
+ end
146
+
147
+ At the serializable transaction isolation level, find_or_create may raises a Sequel::SerializationFailure exception if multiple threads simultaneously run that code. With the :retry_on option set, the transaction will be automatically retried until it succeeds.
148
+
149
+ Note that automatic retrying should not be used unless the entire transaction
150
+ block is idempotent, as otherwise it can cause non-idempotent
151
+ behavior to execute multiple times. For example, with the following code:
152
+
153
+ DB.transaction(:isolation => :serializable, :retry_on=>[Sequel::SerializationFailure]) do
154
+ logger.info 'Ensuring existence of ModelClass with name Foo'
155
+ ModelClass.find_or_create(:name=>'Foo')
156
+ end
157
+
158
+ The logger.info method will be called multiple times if there is a serialization failure.
159
+
160
+ The :num_retries option can be used to set the maxmimum number of times to retry. It is set to 5 times by default.
@@ -122,6 +122,7 @@ module Sequel
122
122
 
123
123
  def begin_transaction(conn, opts={})
124
124
  log_yield(TRANSACTION_BEGIN){DB2CLI.SQLSetConnectAttr(conn, DB2CLI::SQL_ATTR_AUTOCOMMIT, DB2CLI::SQL_AUTOCOMMIT_OFF)}
125
+ set_transaction_isolation(conn, opts)
125
126
  end
126
127
 
127
128
  def remove_transaction(conn, committed)
@@ -35,6 +35,12 @@ module Sequel
35
35
 
36
36
  # Error class for exceptions raised by the connection.
37
37
  class Error < StandardError
38
+ attr_reader :sqlstate
39
+
40
+ def initialize(message, sqlstate)
41
+ @sqlstate = sqlstate
42
+ super(message)
43
+ end
38
44
  end
39
45
 
40
46
  # Create the underlying IBM_DB connection.
@@ -69,11 +75,16 @@ module Sequel
69
75
  IBM_DB.getErrormsg(@conn, IBM_DB::DB_CONN)
70
76
  end
71
77
 
78
+ # Return the related error message for the connection.
79
+ def error_sqlstate
80
+ IBM_DB.getErrorstate(@conn, IBM_DB::DB_CONN)
81
+ end
82
+
72
83
  # Execute the given SQL on the database, and return a Statement instance
73
84
  # holding the results.
74
85
  def execute(sql)
75
86
  stmt = IBM_DB.exec(@conn, sql)
76
- raise Error, error_msg unless stmt
87
+ raise Error.new(error_msg, error_sqlstate) unless stmt
77
88
  Statement.new(stmt)
78
89
  end
79
90
 
@@ -83,7 +94,7 @@ module Sequel
83
94
  stmt = @prepared_statements[ps_name].last
84
95
  res = stmt.execute(*values)
85
96
  unless res
86
- raise Error, "Error executing statement #{ps_name}: #{error_msg}"
97
+ raise Error.new("Error executing statement #{ps_name}: #{error_msg}", error_sqlstate)
87
98
  end
88
99
  stmt
89
100
  end
@@ -98,7 +109,7 @@ module Sequel
98
109
  else
99
110
  err = error_msg
100
111
  err = "Error preparing #{ps_name} with SQL: #{sql}" if error_msg.nil? || error_msg.empty?
101
- raise Error, err
112
+ raise Error.new(err, error_sqlstate)
102
113
  end
103
114
  end
104
115
 
@@ -301,6 +312,7 @@ module Sequel
301
312
  # So starting a transaction just turns autocommit off.
302
313
  def begin_transaction(conn, opts={})
303
314
  log_yield(TRANSACTION_BEGIN){conn.autocommit = false}
315
+ set_transaction_isolation(conn, opts)
304
316
  end
305
317
 
306
318
  # This commits transaction in progress on the
@@ -313,6 +325,10 @@ module Sequel
313
325
  [Connection::Error]
314
326
  end
315
327
 
328
+ def database_exception_sqlstate(exception, opts)
329
+ exception.sqlstate
330
+ end
331
+
316
332
  # Don't convert smallint to boolean for the metadata
317
333
  # dataset, since the DB2 metadata does not use
318
334
  # boolean columns, and some smallint columns are
@@ -345,6 +345,21 @@ module Sequel
345
345
  [NativeException]
346
346
  end
347
347
 
348
+ def database_exception_sqlstate(exception, opts)
349
+ if database_exception_use_sqlstates?
350
+ while exception.respond_to?(:cause)
351
+ exception = exception.cause
352
+ return exception.getSQLState if exception.respond_to?(:getSQLState)
353
+ end
354
+ end
355
+ nil
356
+ end
357
+
358
+ # Whether the JDBC subadapter should use SQL states for exception handling, true by default.
359
+ def database_exception_use_sqlstates?
360
+ true
361
+ end
362
+
348
363
  # Raise a disconnect error if the SQL state of the cause of the exception indicates so.
349
364
  def disconnect_error?(exception, opts)
350
365
  cause = exception.respond_to?(:cause) ? exception.cause : exception
@@ -109,6 +109,7 @@ module Sequel
109
109
  /violation of foreign key constraint/ => ForeignKeyConstraintViolation,
110
110
  /The check constraint .+ was violated/ => CheckConstraintViolation,
111
111
  /cannot accept a NULL value/ => NotNullConstraintViolation,
112
+ /A lock could not be obtained due to a deadlock/ => SerializationFailure,
112
113
  }.freeze
113
114
  def database_error_regexps
114
115
  DATABASE_ERROR_REGEXPS
@@ -208,13 +209,8 @@ module Sequel
208
209
  end
209
210
  end
210
211
 
211
- # Handle Derby specific LIKE, extract, and some bitwise compliment support.
212
212
  def complex_expression_sql_append(sql, op, args)
213
213
  case op
214
- when :ILIKE
215
- super(sql, :LIKE, [SQL::Function.new(:upper, args.at(0)), SQL::Function.new(:upper, args.at(1))])
216
- when :"NOT ILIKE"
217
- super(sql, :"NOT LIKE", [SQL::Function.new(:upper, args.at(0)), SQL::Function.new(:upper, args.at(1))])
218
214
  when :%
219
215
  sql << complex_expression_arg_pairs(args){|a, b| "MOD(#{literal(a)}, #{literal(b)})"}
220
216
  when :&, :|, :^, :<<, :>>
@@ -101,6 +101,7 @@ module Sequel
101
101
  /Referential integrity constraint violation/ => ForeignKeyConstraintViolation,
102
102
  /Check constraint violation/ => CheckConstraintViolation,
103
103
  /NULL not allowed for column/ => NotNullConstraintViolation,
104
+ /Deadlock detected\. The current transaction was rolled back\./ => SerializationFailure,
104
105
  }.freeze
105
106
  def database_error_regexps
106
107
  DATABASE_ERROR_REGEXPS
@@ -57,6 +57,7 @@ module Sequel
57
57
  /integrity constraint violation: foreign key/ => ForeignKeyConstraintViolation,
58
58
  /integrity constraint violation: check constraint/ => CheckConstraintViolation,
59
59
  /integrity constraint violation: NOT NULL check constraint/ => NotNullConstraintViolation,
60
+ /serialization failure/ => SerializationFailure,
60
61
  }.freeze
61
62
  def database_error_regexps
62
63
  DATABASE_ERROR_REGEXPS
@@ -124,7 +125,7 @@ module Sequel
124
125
  def complex_expression_sql_append(sql, op, args)
125
126
  case op
126
127
  when :ILIKE, :"NOT ILIKE"
127
- super(sql, (op == :ILIKE ? :LIKE : :"NOT LIKE"), [SQL::Function.new(:ucase, args.at(0)), SQL::Function.new(:ucase, args.at(1)) ])
128
+ super(sql, (op == :ILIKE ? :LIKE : :"NOT LIKE"), args.map{|v| SQL::Function.new(:ucase, v)})
128
129
  when :&, :|, :^
129
130
  op = BITWISE_METHOD_MAP[op]
130
131
  sql << complex_expression_arg_pairs(args){|a, b| literal(SQL::Function.new(op, a, b))}