sequel 3.25.0 → 3.26.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/CHANGELOG +28 -0
  2. data/README.rdoc +3 -3
  3. data/Rakefile +17 -11
  4. data/doc/release_notes/3.26.0.txt +88 -0
  5. data/lib/sequel/adapters/ado.rb +10 -0
  6. data/lib/sequel/adapters/do.rb +12 -0
  7. data/lib/sequel/adapters/jdbc.rb +6 -6
  8. data/lib/sequel/adapters/mysql.rb +8 -2
  9. data/lib/sequel/adapters/mysql2.rb +5 -1
  10. data/lib/sequel/adapters/odbc.rb +10 -2
  11. data/lib/sequel/adapters/oracle.rb +5 -1
  12. data/lib/sequel/adapters/postgres.rb +10 -4
  13. data/lib/sequel/adapters/shared/access.rb +11 -0
  14. data/lib/sequel/adapters/shared/oracle.rb +0 -4
  15. data/lib/sequel/adapters/shared/postgres.rb +0 -12
  16. data/lib/sequel/adapters/tinytds.rb +9 -0
  17. data/lib/sequel/connection_pool.rb +1 -1
  18. data/lib/sequel/connection_pool/threaded.rb +3 -2
  19. data/lib/sequel/core.rb +1 -1
  20. data/lib/sequel/database/connecting.rb +3 -3
  21. data/lib/sequel/database/dataset.rb +1 -1
  22. data/lib/sequel/database/dataset_defaults.rb +1 -1
  23. data/lib/sequel/database/logging.rb +1 -1
  24. data/lib/sequel/database/misc.rb +23 -6
  25. data/lib/sequel/database/query.rb +16 -15
  26. data/lib/sequel/database/schema_methods.rb +21 -16
  27. data/lib/sequel/dataset/actions.rb +19 -16
  28. data/lib/sequel/dataset/features.rb +8 -2
  29. data/lib/sequel/dataset/graph.rb +1 -1
  30. data/lib/sequel/dataset/misc.rb +29 -9
  31. data/lib/sequel/dataset/mutation.rb +3 -3
  32. data/lib/sequel/dataset/prepared_statements.rb +11 -11
  33. data/lib/sequel/dataset/query.rb +28 -7
  34. data/lib/sequel/dataset/sql.rb +2 -2
  35. data/lib/sequel/extensions/migration.rb +1 -0
  36. data/lib/sequel/model.rb +5 -4
  37. data/lib/sequel/model/associations.rb +487 -328
  38. data/lib/sequel/model/base.rb +43 -26
  39. data/lib/sequel/model/exceptions.rb +2 -0
  40. data/lib/sequel/plugins/identity_map.rb +111 -4
  41. data/lib/sequel/plugins/sharding.rb +12 -20
  42. data/lib/sequel/plugins/xml_serializer.rb +2 -2
  43. data/lib/sequel/version.rb +1 -1
  44. data/spec/adapters/postgres_spec.rb +0 -6
  45. data/spec/core/connection_pool_spec.rb +6 -0
  46. data/spec/core/database_spec.rb +12 -0
  47. data/spec/core/schema_spec.rb +9 -2
  48. data/spec/extensions/identity_map_spec.rb +162 -0
  49. data/spec/extensions/many_through_many_spec.rb +3 -19
  50. data/spec/extensions/xml_serializer_spec.rb +4 -4
  51. data/spec/model/eager_loading_spec.rb +7 -21
  52. data/spec/model/record_spec.rb +23 -0
  53. metadata +36 -34
data/CHANGELOG CHANGED
@@ -1,3 +1,31 @@
1
+ === 3.26.0 (2011-08-01)
2
+
3
+ * Fix bug in default connection pool if a disconnect error is raised and the disconnection_proc also raises an error (jeremyevans)
4
+
5
+ * Disallow eager loading via eager of many_*_many associations with :eager_graph option (jeremyevans)
6
+
7
+ * Major speedup in dataset creation (jeremyevans)
8
+
9
+ * Replace internal implementation of eager_graph with much faster version (jeremyevans)
10
+
11
+ * Don't treat strings with leading zeros as octal format in the default typecasting (jeremyevans)
12
+
13
+ * Fix literalization of Date, Time, and DateTime values on Microsoft Access (jeremyevans)
14
+
15
+ * Fix handling of nil values with the pure-Java version of nokogiri in the xml_serializer plugin (jeremyevans)
16
+
17
+ * Make identity_map plugin work with standard eager loading of many_to_many and many_through_many associations (jeremyevans)
18
+
19
+ * Make create_table! only attempt to drop the table if it already exists (jeremyevans)
20
+
21
+ * Remove custom table_exists? implementations in the oracle and postgres adapters (jeremyevans)
22
+
23
+ * Handle another type of disconnection in the postgres adapter (jeremyevans)
24
+
25
+ * Handle disconnections in the ado adapter and do postgres subadapter (jeremyevans)
26
+
27
+ * Recognize disconnections when issuing BEGIN/ROLLBACK/COMMIT statements (jeremyevans) (#368)
28
+
1
29
  === 3.25.0 (2011-07-01)
2
30
 
3
31
  * Work with tiny_tds-0.4.5 in the tinytds adapter, older versions are no longer supported (jeremyevans)
data/README.rdoc CHANGED
@@ -573,7 +573,7 @@ You can execute custom code when creating, updating, or deleting records by defi
573
573
 
574
574
  Note the use of +super+ if you define your own hook methods. Almost all <tt>Sequel::Model</tt> class and instance methods (not just hook methods) can be overridden safely, but you have to make sure to call +super+ when doing so, otherwise you risk breaking things.
575
575
 
576
- For the example above, you should probably use a database trigger if you can. Hooks can be used for data integrity, but they will only enforce that integrity when you are modifying the database through model instances. If you plan on allowing any other access to the database, it's best to use database triggers for data integrity.
576
+ For the example above, you should probably use a database trigger if you can. Hooks can be used for data integrity, but they will only enforce that integrity when you are modifying the database through model instances. If you plan on allowing any other access to the database, it's best to use database triggers and constraints for data integrity.
577
577
 
578
578
  === Deleting records
579
579
 
@@ -681,9 +681,9 @@ Associations can be eagerly loaded via +eager+ and the <tt>:eager</tt> associati
681
681
  # Loads all people, their posts, their posts' tags, replies to those posts,
682
682
  # the person for each reply, the tag for each reply, and all posts and
683
683
  # replies that have that tag. Uses a total of 8 queries.
684
- Person.eager(:posts=>{:replies=>[:person, {:tags=>{:posts, :replies}}]}).all
684
+ Person.eager(:posts=>{:replies=>[:person, {:tags=>[:posts, :replies]}]}).all
685
685
 
686
- In addition to using +eager+, you can also use +eager_graph+, which will use a single query to get the object and all associated objects. This may be necessary if you want to filter or order the result set based on columns in associated tables. It works with cascading as well, the syntax is exactly the same. Note that using eager_graph to eagerly load multiple *_to_many associations will cause the result set to be a cartesian product, so you should be very careful with your filters when using it in that case.
686
+ In addition to using +eager+, you can also use +eager_graph+, which will use a single query to get the object and all associated objects. This may be necessary if you want to filter or order the result set based on columns in associated tables. It works with cascading as well, the API is very similar. Note that using +eager_graph+ to eagerly load multiple <tt>*_to_many</tt> associations will cause the result set to be a cartesian product, so you should be very careful with your filters when using it in that case.
687
687
 
688
688
  You can dynamically customize the eagerly loaded dataset by using using a proc. This proc is passed the dataset used for eager loading, and should return a modified copy of that dataset:
689
689
 
data/Rakefile CHANGED
@@ -1,11 +1,6 @@
1
1
  require "rake"
2
2
  require "rake/clean"
3
3
  require "rake/gempackagetask"
4
- begin
5
- require "hanna/rdoctask"
6
- rescue LoadError
7
- require "rake/rdoctask"
8
- end
9
4
 
10
5
  NAME = 'sequel'
11
6
  VERS = lambda do
@@ -13,8 +8,6 @@ VERS = lambda do
13
8
  Sequel.version
14
9
  end
15
10
  CLEAN.include ["**/.*.sw?", "sequel-*.gem", ".config", "rdoc", "coverage", "www/public/*.html", "www/public/rdoc*", '**/*.rbc']
16
- RDOC_DEFAULT_OPTS = ["--quiet", "--line-numbers", "--inline-source", '--title', 'Sequel: The Database Toolkit for Ruby']
17
- RDOC_OPTS = RDOC_DEFAULT_OPTS + ['--main', 'README.rdoc']
18
11
 
19
12
  # Gem Packaging and Release
20
13
 
@@ -40,7 +33,20 @@ end
40
33
 
41
34
  ### RDoc
42
35
 
43
- Rake::RDocTask.new do |rdoc|
36
+ RDOC_DEFAULT_OPTS = ["--quiet", "--line-numbers", "--inline-source", '--title', 'Sequel: The Database Toolkit for Ruby']
37
+
38
+ rdoc_task_class = begin
39
+ require "rdoc/task"
40
+ RDOC_DEFAULT_OPTS.concat(['-f', 'hanna'])
41
+ RDoc::Task
42
+ rescue LoadError
43
+ require "rake/rdoctask"
44
+ Rake::RDocTask
45
+ end
46
+
47
+ RDOC_OPTS = RDOC_DEFAULT_OPTS + ['--main', 'README.rdoc']
48
+
49
+ rdoc_task_class.new do |rdoc|
44
50
  rdoc.rdoc_dir = "rdoc"
45
51
  rdoc.options += RDOC_OPTS
46
52
  rdoc.rdoc_files.add %w"README.rdoc CHANGELOG MIT-LICENSE lib/**/*.rb doc/*.rdoc doc/release_notes/*.txt"
@@ -56,19 +62,19 @@ end
56
62
  desc "Make rdoc for website"
57
63
  task :website_rdoc=>[:website_rdoc_main, :website_rdoc_adapters, :website_rdoc_plugins]
58
64
 
59
- Rake::RDocTask.new(:website_rdoc_main) do |rdoc|
65
+ rdoc_task_class.new(:website_rdoc_main) do |rdoc|
60
66
  rdoc.rdoc_dir = "www/public/rdoc"
61
67
  rdoc.options += RDOC_OPTS
62
68
  rdoc.rdoc_files.add %w"README.rdoc CHANGELOG MIT-LICENSE lib/*.rb lib/sequel/*.rb lib/sequel/{connection_pool,dataset,database,model}/*.rb doc/*.rdoc doc/release_notes/*.txt lib/sequel/extensions/migration.rb"
63
69
  end
64
70
 
65
- Rake::RDocTask.new(:website_rdoc_adapters) do |rdoc|
71
+ rdoc_task_class.new(:website_rdoc_adapters) do |rdoc|
66
72
  rdoc.rdoc_dir = "www/public/rdoc-adapters"
67
73
  rdoc.options += RDOC_DEFAULT_OPTS + %w'--main Sequel'
68
74
  rdoc.rdoc_files.add %w"lib/sequel/adapters/**/*.rb"
69
75
  end
70
76
 
71
- Rake::RDocTask.new(:website_rdoc_plugins) do |rdoc|
77
+ rdoc_task_class.new(:website_rdoc_plugins) do |rdoc|
72
78
  rdoc.rdoc_dir = "www/public/rdoc-plugins"
73
79
  rdoc.options += RDOC_DEFAULT_OPTS + %w'--main Sequel'
74
80
  rdoc.rdoc_files.add %w"lib/sequel/{extensions,plugins}/**/*.rb"
@@ -0,0 +1,88 @@
1
+ = Performance Enhancements
2
+
3
+ * The internal implementation of eager_graph has been made 75% to
4
+ 225% faster than before, with greater benefits to more complex
5
+ graphs.
6
+
7
+ * Dataset creation has been made much faster (2.5x on 1.8 and 4.4x on
8
+ 1.9), and dataset cloning has been made significantly faster (40%
9
+ on 1.8 and 20% on 1.9).
10
+
11
+ = Other Improvements
12
+
13
+ * Strings passed to setter methods for integer columns are no longer
14
+ considered to be in octal format if they include leading zeroes.
15
+ The previous behavior was never intended, but was a side effect of
16
+ using Kernel#Integer. Strings with leading zeroes are now treated
17
+ as decimal, and you can still use the 0x prefix to treat them as
18
+ hexidecimal. If anyone was relying on the old octal behavior, let
19
+ me know and I'll add an extension that restores the octal behavior.
20
+
21
+ * The identity_map plugin now works with the standard eager loading
22
+ of many_to_many and many_through_many associations.
23
+
24
+ * Database#create_table! now only attempts to drop the table if it
25
+ already exists. Previously, it attempted to drop the table
26
+ unconditionally ignoring any errors, which resulted in misleading
27
+ error messages if dropping the table raised an error caused by
28
+ permissions or referential integrity issues.
29
+
30
+ * The default connection pool now correctly handles the case where a
31
+ disconnect error is raised and an exception is raised while
32
+ running the disconnection proc.
33
+
34
+ * Disconnection errors are now detected when issuing transaction
35
+ statements such as BEGIN/ROLLBACK/COMMIT. Previously, these
36
+ statements did not handle disconnect errors on most adapters.
37
+
38
+ * More disconnection errors are now detected. Specifically, the ado
39
+ adapter and do postgres subadapter now handle disconnect errors,
40
+ and the postgres adapter handles more types of disconnect errors.
41
+
42
+ * Database#table_exists? now always issues a query to select from the
43
+ table, it no longer attempts to parse the schema to determine the
44
+ information on PostgreSQL and Oracle.
45
+
46
+ * Date, DateTime, and Time values are now literalized correctly on
47
+ Microsoft Access.
48
+
49
+ * Connecting with the mysql adapter with an options hash now works if
50
+ the :port option is a string, which makes it easier to use when the
51
+ connection information is stored in YAML.
52
+
53
+ * The xml_serializer plugin now works around a bug in pure-Java
54
+ nokogiri regarding the handling of nil values.
55
+
56
+ * Nicer error messages are now used if there is an attempt to call
57
+ an invalid or restricted setter method.
58
+
59
+ * The RDocs are now formatted with hanna-nouveau, which allows for
60
+ section ordering, so the Database and Dataset RDoc pages are
61
+ more friendly.
62
+
63
+ = Backwards Compatibility
64
+
65
+ * If you call a Dataset method such as #each on an eager_graphed
66
+ dataset, you now get plain hashes that have column alias symbol
67
+ keys and their values. Previously, you got a graphed response with
68
+ table alias keys and model values. It's not wise to depend on the
69
+ behavior, the only supported way of returning records when eager
70
+ loading is to use #all.
71
+
72
+ * An error is now raised if you attempt to eager load via
73
+ Dataset#eager a many_to_many association that includes an
74
+ :eager_graph option. Previously, incorrect SQL would have been
75
+ generated and an error raised by the database.
76
+
77
+ * Datasets are no longer guaranteed to have @row_proc,
78
+ @indentifier_input_method, and @identifier_output_method defined
79
+ as instance variables. You should be be using methods to access
80
+ them anyway.
81
+
82
+ * Database#table_exists? on PostgreSQL no longer accepts an options
83
+ hash. Previously, you could use a :schema option. You must now
84
+ provide the schema inside the table argument (e.g. :schema__table).
85
+
86
+ * If you want to use the rdoc tasks in Sequel's Rakefile, and you are
87
+ still using the hanna RDoc template with RDoc 2.3, you need to
88
+ upgrade to using hanna-nouveau with RDoc 3.8+.
@@ -4,6 +4,8 @@ module Sequel
4
4
  # The ADO adapter provides connectivity to ADO databases in Windows.
5
5
  module ADO
6
6
  class Database < Sequel::Database
7
+ DISCONNECT_ERROR_RE = /Communication link failure/
8
+
7
9
  set_adapter_scheme :ado
8
10
 
9
11
  def initialize(opts)
@@ -87,9 +89,17 @@ module Sequel
87
89
  end
88
90
  end
89
91
 
92
+ def database_error_classes
93
+ [::WIN32OLERuntimeError]
94
+ end
95
+
90
96
  def disconnect_connection(conn)
91
97
  conn.Close
92
98
  end
99
+
100
+ def disconnect_error?(e, opts)
101
+ super || (e.is_a?(::WIN32OLERuntimeError) && e.message =~ DISCONNECT_ERROR_RE)
102
+ end
93
103
  end
94
104
 
95
105
  class Dataset < Sequel::Dataset
@@ -36,6 +36,8 @@ module Sequel
36
36
  # Sequel::DataObjects::Database object, or hack DataObjects (or Extlib) to
37
37
  # use a pool size at least as large as the pool size being used by Sequel.
38
38
  class Database < Sequel::Database
39
+ DISCONNECT_ERROR_RE = /terminating connection due to administrator command/
40
+
39
41
  set_adapter_scheme :do
40
42
 
41
43
  # Call the DATABASE_SETUP proc directly after initialization,
@@ -145,10 +147,20 @@ module Sequel
145
147
  :execute_non_query
146
148
  end
147
149
 
150
+ # dataobjects uses the DataObjects::Error class as the main error class.
151
+ def database_error_classes
152
+ [::DataObjects::Error]
153
+ end
154
+
148
155
  # Close the given database connection.
149
156
  def disconnect_connection(c)
150
157
  c.close
151
158
  end
159
+
160
+ # Recognize DataObjects::ConnectionError instances as disconnect errors.
161
+ def disconnect_error?(e, opts)
162
+ super || (e.is_a?(::DataObjects::Error) && (e.is_a?(::DataObjects::ConnectionError) || e.message =~ DISCONNECT_ERROR_RE))
163
+ end
152
164
 
153
165
  # Execute SQL on the connection by creating a command first
154
166
  def log_connection_execute(conn, sql)
@@ -285,6 +285,12 @@ module Sequel
285
285
  c.close
286
286
  end
287
287
 
288
+ # Raise a disconnect error if the SQL state of the cause of the exception indicates so.
289
+ def disconnect_error?(exception, opts)
290
+ cause = exception.respond_to?(:cause) ? exception.cause : exception
291
+ super || (cause.respond_to?(:getSQLState) && cause.getSQLState =~ /^08/)
292
+ end
293
+
288
294
  # Execute the prepared statement. If the provided name is a
289
295
  # dataset, use that as the prepared statement, otherwise use
290
296
  # it as a key to look it up in the prepared_statements hash.
@@ -400,12 +406,6 @@ module Sequel
400
406
  end
401
407
  end
402
408
 
403
- # Treat SQLExceptions with a "Connection Error" SQLState as disconnects
404
- def raise_error(exception, opts={})
405
- cause = exception.respond_to?(:cause) ? exception.cause : exception
406
- super(exception, {:disconnect => cause.respond_to?(:getSQLState) && cause.getSQLState =~ /^08/}.merge(opts))
407
- end
408
-
409
409
  # Java being java, you need to specify the type of each argument
410
410
  # for the prepared statement, and bind it individually. This
411
411
  # guesses which JDBC method to use, and hopefully JRuby will convert
@@ -139,7 +139,7 @@ module Sequel
139
139
  opts[:user],
140
140
  opts[:password],
141
141
  opts[:database],
142
- opts[:port],
142
+ (opts[:port].to_i if opts[:port]),
143
143
  opts[:socket],
144
144
  Mysql::CLIENT_MULTI_RESULTS +
145
145
  Mysql::CLIENT_MULTI_STATEMENTS +
@@ -220,7 +220,7 @@ module Sequel
220
220
  end
221
221
  end
222
222
  rescue Mysql::Error => e
223
- raise_error(e, :disconnect=>MYSQL_DATABASE_DISCONNECT_ERRORS.match(e.message))
223
+ raise_error(e)
224
224
  ensure
225
225
  r.free if r
226
226
  # Use up all results to avoid a commands out of sync message.
@@ -248,6 +248,12 @@ module Sequel
248
248
  def database_error_classes
249
249
  [Mysql::Error]
250
250
  end
251
+
252
+ # Raise a disconnect error if the exception message matches the list
253
+ # of recognized exceptions.
254
+ def disconnect_error?(e, opts)
255
+ super || (e.is_a?(::Mysql::Error) && MYSQL_DATABASE_DISCONNECT_ERRORS.match(e.message))
256
+ end
251
257
 
252
258
  # The database name when using the native adapter is always stored in
253
259
  # the :database option.
@@ -94,7 +94,7 @@ module Sequel
94
94
  yield conn
95
95
  end
96
96
  rescue ::Mysql2::Error => e
97
- raise_error(e, :disconnect=>MYSQL_DATABASE_DISCONNECT_ERRORS.match(e.message))
97
+ raise_error(e)
98
98
  end
99
99
  end
100
100
 
@@ -108,6 +108,10 @@ module Sequel
108
108
  [::Mysql2::Error]
109
109
  end
110
110
 
111
+ def disconnect_error?(e, opts)
112
+ super || (e.is_a?(::Mysql2::Error) && MYSQL_DATABASE_DISCONNECT_ERRORS.match(e.message))
113
+ end
114
+
111
115
  # The database name when using the native adapter is always stored in
112
116
  # the :database option.
113
117
  def database_name
@@ -52,7 +52,7 @@ module Sequel
52
52
  r = log_yield(sql){conn.run(sql)}
53
53
  yield(r) if block_given?
54
54
  rescue ::ODBC::Error, ArgumentError => e
55
- raise_error(e, :disconnect=>DISCONNECT_ERRORS.match(e.message))
55
+ raise_error(e)
56
56
  ensure
57
57
  r.drop if r
58
58
  end
@@ -65,7 +65,7 @@ module Sequel
65
65
  begin
66
66
  log_yield(sql){conn.do(sql)}
67
67
  rescue ::ODBC::Error, ArgumentError => e
68
- raise_error(e, :disconnect=>DISCONNECT_ERRORS.match(e.message))
68
+ raise_error(e)
69
69
  end
70
70
  end
71
71
  end
@@ -77,9 +77,17 @@ module Sequel
77
77
  :do
78
78
  end
79
79
 
80
+ def database_error_classes
81
+ [::ODBC::Error]
82
+ end
83
+
80
84
  def disconnect_connection(c)
81
85
  c.disconnect
82
86
  end
87
+
88
+ def disconnect_error?(e, opts)
89
+ super || (e.is_a?(::ODBC::Error) && DISCONNECT_ERRORS.match(e.message))
90
+ end
83
91
  end
84
92
 
85
93
  class Dataset < Sequel::Dataset
@@ -78,7 +78,7 @@ module Sequel
78
78
  yield(r) if block_given?
79
79
  r
80
80
  rescue OCIException => e
81
- raise_error(e, :disconnect=>CONNECTION_ERROR_CODES.include?(e.code))
81
+ raise_error(e)
82
82
  end
83
83
  end
84
84
  end
@@ -100,6 +100,10 @@ module Sequel
100
100
  rescue OCIInvalidHandle
101
101
  nil
102
102
  end
103
+
104
+ def disconnect_error?(e, opts)
105
+ super || (e.is_a?(::OCIException) && CONNECTION_ERROR_CODES.include?(e.code))
106
+ end
103
107
 
104
108
  def remove_transaction(conn)
105
109
  conn.autocommit = true if conn
@@ -136,7 +136,10 @@ module Sequel
136
136
  # PGconn subclass for connection specific methods used with the
137
137
  # pg, postgres, or postgres-pr driver.
138
138
  class Adapter < ::PGconn
139
+ DISCONNECT_ERROR_RE = /\Acould not receive data from server: Software caused connection abort/
140
+
139
141
  include Sequel::Postgres::AdapterMethods
142
+
140
143
  self.translate_results = false if respond_to?(:translate_results=)
141
144
 
142
145
  # Hash of prepared statements for this connection. Keys are
@@ -155,20 +158,23 @@ module Sequel
155
158
  end
156
159
  @prepared_statements = {} if SEQUEL_POSTGRES_USES_PG
157
160
  end
158
-
161
+
159
162
  # Raise a Sequel::DatabaseDisconnectError if a PGError is raised and
160
163
  # the connection status cannot be determined or it is not OK.
161
164
  def check_disconnect_errors
162
165
  begin
163
166
  yield
164
167
  rescue PGError =>e
168
+ disconnect = false
165
169
  begin
166
170
  s = status
167
171
  rescue PGError
168
- raise Sequel.convert_exception_class(e, Sequel::DatabaseDisconnectError)
172
+ disconnect = true
169
173
  end
170
174
  status_ok = (s == Adapter::CONNECTION_OK)
171
- status_ok ? raise : raise(Sequel.convert_exception_class(e, Sequel::DatabaseDisconnectError))
175
+ disconnect ||= !status_ok
176
+ disconnect ||= e.message =~ DISCONNECT_ERROR_RE
177
+ disconnect ? raise(Sequel.convert_exception_class(e, Sequel::DatabaseDisconnectError)) : raise
172
178
  ensure
173
179
  block if status_ok
174
180
  end
@@ -181,7 +187,7 @@ module Sequel
181
187
  begin
182
188
  block_given? ? yield(q) : q.cmd_tuples
183
189
  ensure
184
- q.clear
190
+ q.clear if q
185
191
  end
186
192
  end
187
193