sequel 3.44.0 → 3.45.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.
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))}