sequel 3.38.0 → 3.39.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 (79) hide show
  1. data/CHANGELOG +62 -0
  2. data/README.rdoc +2 -2
  3. data/bin/sequel +12 -2
  4. data/doc/advanced_associations.rdoc +1 -1
  5. data/doc/association_basics.rdoc +13 -0
  6. data/doc/release_notes/3.39.0.txt +237 -0
  7. data/doc/schema_modification.rdoc +4 -4
  8. data/lib/sequel/adapters/jdbc/derby.rb +1 -0
  9. data/lib/sequel/adapters/mock.rb +5 -0
  10. data/lib/sequel/adapters/mysql.rb +8 -1
  11. data/lib/sequel/adapters/mysql2.rb +10 -3
  12. data/lib/sequel/adapters/postgres.rb +72 -8
  13. data/lib/sequel/adapters/shared/db2.rb +1 -0
  14. data/lib/sequel/adapters/shared/mssql.rb +57 -0
  15. data/lib/sequel/adapters/shared/mysql.rb +95 -19
  16. data/lib/sequel/adapters/shared/oracle.rb +14 -0
  17. data/lib/sequel/adapters/shared/postgres.rb +63 -24
  18. data/lib/sequel/adapters/shared/sqlite.rb +6 -9
  19. data/lib/sequel/connection_pool/sharded_threaded.rb +8 -3
  20. data/lib/sequel/connection_pool/threaded.rb +9 -4
  21. data/lib/sequel/database/query.rb +60 -48
  22. data/lib/sequel/database/schema_generator.rb +13 -6
  23. data/lib/sequel/database/schema_methods.rb +65 -12
  24. data/lib/sequel/dataset/actions.rb +22 -4
  25. data/lib/sequel/dataset/features.rb +5 -0
  26. data/lib/sequel/dataset/graph.rb +2 -3
  27. data/lib/sequel/dataset/misc.rb +2 -2
  28. data/lib/sequel/dataset/query.rb +0 -2
  29. data/lib/sequel/dataset/sql.rb +33 -12
  30. data/lib/sequel/extensions/constraint_validations.rb +451 -0
  31. data/lib/sequel/extensions/eval_inspect.rb +17 -2
  32. data/lib/sequel/extensions/pg_array_ops.rb +15 -5
  33. data/lib/sequel/extensions/pg_interval.rb +2 -2
  34. data/lib/sequel/extensions/pg_row_ops.rb +18 -0
  35. data/lib/sequel/extensions/schema_dumper.rb +3 -11
  36. data/lib/sequel/model/associations.rb +3 -2
  37. data/lib/sequel/model/base.rb +57 -13
  38. data/lib/sequel/model/exceptions.rb +20 -2
  39. data/lib/sequel/plugins/constraint_validations.rb +198 -0
  40. data/lib/sequel/plugins/defaults_setter.rb +15 -1
  41. data/lib/sequel/plugins/dirty.rb +2 -2
  42. data/lib/sequel/plugins/identity_map.rb +12 -8
  43. data/lib/sequel/plugins/subclasses.rb +19 -1
  44. data/lib/sequel/plugins/tree.rb +3 -3
  45. data/lib/sequel/plugins/validation_helpers.rb +24 -4
  46. data/lib/sequel/sql.rb +64 -24
  47. data/lib/sequel/timezones.rb +10 -2
  48. data/lib/sequel/version.rb +1 -1
  49. data/spec/adapters/mssql_spec.rb +26 -25
  50. data/spec/adapters/mysql_spec.rb +57 -23
  51. data/spec/adapters/oracle_spec.rb +34 -49
  52. data/spec/adapters/postgres_spec.rb +226 -128
  53. data/spec/adapters/sqlite_spec.rb +50 -49
  54. data/spec/core/connection_pool_spec.rb +22 -0
  55. data/spec/core/database_spec.rb +53 -47
  56. data/spec/core/dataset_spec.rb +36 -32
  57. data/spec/core/expression_filters_spec.rb +14 -2
  58. data/spec/core/mock_adapter_spec.rb +4 -0
  59. data/spec/core/object_graph_spec.rb +0 -13
  60. data/spec/core/schema_spec.rb +64 -5
  61. data/spec/core_extensions_spec.rb +1 -0
  62. data/spec/extensions/constraint_validations_plugin_spec.rb +196 -0
  63. data/spec/extensions/constraint_validations_spec.rb +316 -0
  64. data/spec/extensions/defaults_setter_spec.rb +24 -0
  65. data/spec/extensions/eval_inspect_spec.rb +9 -0
  66. data/spec/extensions/identity_map_spec.rb +11 -2
  67. data/spec/extensions/pg_array_ops_spec.rb +9 -0
  68. data/spec/extensions/pg_row_ops_spec.rb +11 -1
  69. data/spec/extensions/pg_row_plugin_spec.rb +4 -0
  70. data/spec/extensions/schema_dumper_spec.rb +8 -5
  71. data/spec/extensions/subclasses_spec.rb +14 -0
  72. data/spec/extensions/validation_helpers_spec.rb +15 -2
  73. data/spec/integration/dataset_test.rb +75 -1
  74. data/spec/integration/plugin_test.rb +146 -0
  75. data/spec/integration/schema_test.rb +34 -0
  76. data/spec/model/dataset_methods_spec.rb +38 -0
  77. data/spec/model/hooks_spec.rb +6 -0
  78. data/spec/model/validations_spec.rb +27 -2
  79. metadata +8 -2
@@ -37,11 +37,25 @@ module Sequel
37
37
 
38
38
  private
39
39
 
40
+ # Parse the cached database schema for this model and set the default values appropriately.
40
41
  def set_default_values
41
42
  h = {}
42
- @db_schema.each{|k, v| h[k] = v[:ruby_default] if v[:ruby_default]} if @db_schema
43
+ @db_schema.each{|k, v| h[k] = convert_default_value(v[:ruby_default]) unless v[:ruby_default].nil?} if @db_schema
43
44
  @default_values = h
44
45
  end
46
+
47
+ # Handle the CURRENT_DATE and CURRENT_TIMESTAMP values specially by returning an appropriate Date or
48
+ # Time/DateTime value.
49
+ def convert_default_value(v)
50
+ case v
51
+ when Sequel::CURRENT_DATE
52
+ lambda{Date.today}
53
+ when Sequel::CURRENT_TIMESTAMP
54
+ lambda{Sequel.datetime_class.now}
55
+ else
56
+ v
57
+ end
58
+ end
45
59
  end
46
60
 
47
61
  module InstanceMethods
@@ -14,7 +14,7 @@ module Sequel
14
14
  # artist.name # => 'Foo'
15
15
  # artist.column_changed?(:name) # false
16
16
  #
17
- # It allows makes changed_columns more accurate in that it
17
+ # It also makes changed_columns more accurate in that it
18
18
  # can detect when a the column value is changed and then
19
19
  # changed back:
20
20
  #
@@ -183,7 +183,7 @@ module Sequel
183
183
 
184
184
  # If the values hash does not contain the column, make sure missing_initial_values
185
185
  # does so that it doesn't get deleted from changed_columns if changed back,
186
- # and so that reseting the column value can be handled correctly.
186
+ # and so that resetting the column value can be handled correctly.
187
187
  def check_missing_initial_value(column)
188
188
  unless values.has_key?(column) || (miv = missing_initial_values).include?(column)
189
189
  miv << column
@@ -153,7 +153,8 @@ module Sequel
153
153
  # The identity map key for an object of the current class with the given pk.
154
154
  # May not always be correct for a class which uses STI.
155
155
  def identity_map_key(pk)
156
- "#{self}:#{pk ? Array(pk).join(',') : "nil:#{rand}"}"
156
+ pk = Array(pk)
157
+ "#{self}:#{pk.join(',')}" unless pk.compact.empty?
157
158
  end
158
159
 
159
160
  # If the identity map is in use, check it for a current copy of the object.
@@ -164,12 +165,14 @@ module Sequel
164
165
  # fields and request other, potentially overlapping fields in a new query,
165
166
  # and not have the second query override fields you modified.
166
167
  def call(row)
167
- return super unless idm = identity_map
168
- if o = idm[identity_map_key(Array(primary_key).map{|x| row[x]})]
168
+ return super unless (idm = identity_map) && (pk = primary_key)
169
+ if (k = identity_map_key(Array(pk).map{|x| row[x]})) && (o = idm[k])
169
170
  o.merge_db_update(row)
170
171
  else
171
172
  o = super
172
- idm[identity_map_key(o.pk)] = o
173
+ if (k = identity_map_key(o.pk))
174
+ idm[k] = o
175
+ end
173
176
  end
174
177
  o
175
178
  end
@@ -196,7 +199,7 @@ module Sequel
196
199
  # Check the current identity map if it exists for the object with
197
200
  # the matching pk. If one is found, return it, otherwise call super.
198
201
  def primary_key_lookup(pk)
199
- (idm = identity_map and o = idm[identity_map_key(pk)]) ? o : super
202
+ ((idm = identity_map) && (k = identity_map_key(pk)) && (o = idm[k])) ? o : super
200
203
  end
201
204
  end
202
205
 
@@ -204,8 +207,8 @@ module Sequel
204
207
  # Remove instances from the identity map cache if they are deleted.
205
208
  def delete
206
209
  super
207
- if idm = model.identity_map
208
- idm.delete(model.identity_map_key(pk))
210
+ if (idm = model.identity_map) && (k = model.identity_map_key(pk))
211
+ idm.delete(k)
209
212
  end
210
213
  self
211
214
  end
@@ -239,7 +242,8 @@ module Sequel
239
242
  if cache_lookup &&
240
243
  !dynamic_opts[:callback] &&
241
244
  (idm = klass.identity_map) &&
242
- (o = idm[klass.identity_map_key(_associated_object_pk(opts[:key]))])
245
+ (k = klass.identity_map_key(_associated_object_pk(opts[:key]))) &&
246
+ (o = idm[k])
243
247
  o
244
248
  else
245
249
  super
@@ -15,13 +15,27 @@ module Sequel
15
15
  # sc2.subclasses # []
16
16
  # ssc1.subclasses # []
17
17
  # c.descendents # [sc1, ssc1, sc2]
18
+ #
19
+ # You can provide a block when loading the plugin, and it will be called
20
+ # with each subclass created:
21
+ #
22
+ # a = []
23
+ # Sequel::Model.plugin(:subclasses){|sc| a << sc}
24
+ # class A < Sequel::Model; end
25
+ # class B < Sequel::Model; end
26
+ # a # => [A, B]
18
27
  module Subclasses
19
28
  # Initialize the subclasses instance variable for the model.
20
- def self.apply(model)
29
+ def self.apply(model, &block)
21
30
  model.instance_variable_set(:@subclasses, [])
31
+ model.instance_variable_set(:@on_subclass, block)
22
32
  end
23
33
 
24
34
  module ClassMethods
35
+ # Callable object that should be called with every descendent
36
+ # class created.
37
+ attr_reader :on_subclass
38
+
25
39
  # All subclasses for the current model. Does not
26
40
  # include the model itself.
27
41
  attr_reader :subclasses
@@ -38,6 +52,10 @@ module Sequel
38
52
  super
39
53
  Sequel.synchronize{subclasses << subclass}
40
54
  subclass.instance_variable_set(:@subclasses, [])
55
+ if on_subclass
56
+ subclass.instance_variable_set(:@on_subclass, on_subclass)
57
+ on_subclass.call(subclass)
58
+ end
41
59
  end
42
60
 
43
61
  private
@@ -4,7 +4,7 @@ module Sequel
4
4
  # treat a Model as a tree.
5
5
  #
6
6
  # A column for holding the parent key is required and is :parent_id by default.
7
- # This may be overridden by passing column name via :key
7
+ # This may be overridden by passing column name via :key.
8
8
  #
9
9
  # Optionally, a column to control order of nodes returned can be specified
10
10
  # by passing column name via :order.
@@ -98,7 +98,7 @@ module Sequel
98
98
  nodes
99
99
  end
100
100
 
101
- # Returns the root node of the tree that this node descends from
101
+ # Returns the root node of the tree that this node descends from.
102
102
  # This node is returned if it is a root node itself.
103
103
  def root
104
104
  ancestors.last || self
@@ -124,7 +124,7 @@ module Sequel
124
124
  end
125
125
  end
126
126
 
127
- # Plugin included when :single_root option is passed
127
+ # Plugin included when :single_root option is passed.
128
128
  module SingleRoot
129
129
  module ClassMethods
130
130
  # Returns the single root node.
@@ -193,19 +193,39 @@ module Sequel
193
193
  # since it can deal with a grouping of multiple attributes.
194
194
  #
195
195
  # Possible Options:
196
- # * :message - The message to use (default: 'is already taken')
197
- # * :only_if_modified - Only check the uniqueness if the object is new or
198
- # one of the columns has been modified.
196
+ # :message :: The message to use (default: 'is already taken')
197
+ # :only_if_modified :: Only check the uniqueness if the object is new or
198
+ # one of the columns has been modified.
199
+ # :where :: A callable object where call takes three arguments, a dataset,
200
+ # the current object, and an array of columns, and should return
201
+ # a modified dataset that is filtered to include only rows with
202
+ # the same values as the current object for each column in the array.
203
+ #
204
+ # If you want to to a case insensitive uniqueness validation on a database that
205
+ # is case sensitive by default, you can use:
206
+ #
207
+ # :where=>(proc do |ds, obj, cols|
208
+ # ds.where(cols.map do |c|
209
+ # v = obj.send(c)
210
+ # v = v.downcase if v
211
+ # [Sequel.function(:lower, c), v]
212
+ # end)
213
+ # end)
199
214
  def validates_unique(*atts)
200
215
  opts = default_validation_helpers_options(:unique)
201
216
  if atts.last.is_a?(Hash)
202
217
  opts = opts.merge(atts.pop)
203
218
  end
204
219
  message = validation_error_message(opts[:message])
220
+ where = opts[:where]
205
221
  atts.each do |a|
206
222
  arr = Array(a)
207
223
  next if opts[:only_if_modified] && !new? && !arr.any?{|x| changed_columns.include?(x)}
208
- ds = model.filter(arr.map{|x| [x, send(x)]})
224
+ ds = if where
225
+ where.call(model.dataset, self, arr)
226
+ else
227
+ model.where(arr.map{|x| [x, send(x)]})
228
+ end
209
229
  ds = yield(ds) if block_given?
210
230
  ds = ds.exclude(pk_hash) unless new?
211
231
  errors.add(a, message) unless ds.count == 0
data/lib/sequel/sql.rb CHANGED
@@ -60,29 +60,38 @@ module Sequel
60
60
 
61
61
  # Base class for all SQL expression objects.
62
62
  class Expression
63
- # Expression objects are assumed to be value objects, where their
64
- # attribute values can't change after assignment. In order to make
65
- # it easy to define equality and hash methods, subclass
66
- # instances assume that the only values that affect the results of
67
- # such methods are the values of the object's attributes.
68
- def self.attr_reader(*args)
69
- super
70
- comparison_attrs.concat(args)
71
- end
63
+ @comparison_attrs = []
64
+
65
+ class << self
66
+ # All attributes used for equality and hash methods.
67
+ attr_reader :comparison_attrs
68
+
69
+ # Expression objects are assumed to be value objects, where their
70
+ # attribute values can't change after assignment. In order to make
71
+ # it easy to define equality and hash methods, subclass
72
+ # instances assume that the only values that affect the results of
73
+ # such methods are the values of the object's attributes.
74
+ def attr_reader(*args)
75
+ super
76
+ comparison_attrs.concat(args)
77
+ end
72
78
 
73
- # All attributes used for equality and hash methods.
74
- def self.comparison_attrs
75
- @comparison_attrs ||= self == Expression ? [] : superclass.comparison_attrs.clone
76
- end
79
+ # Copy the comparison_attrs into the subclass.
80
+ def inherited(subclass)
81
+ super
82
+ subclass.instance_variable_set(:@comparison_attrs, comparison_attrs.dup)
83
+ end
84
+
85
+ private
77
86
 
78
- # Create a to_s instance method that takes a dataset, and calls
79
- # the method provided on the dataset with args as the argument (self by default).
80
- # Used to DRY up some code.
81
- def self.to_s_method(meth, args=:self) # :nodoc:
82
- class_eval("def to_s(ds) ds.#{meth}(#{args}) end", __FILE__, __LINE__)
83
- class_eval("def to_s_append(ds, sql) ds.#{meth}_append(sql, #{args}) end", __FILE__, __LINE__)
87
+ # Create a to_s instance method that takes a dataset, and calls
88
+ # the method provided on the dataset with args as the argument (self by default).
89
+ # Used to DRY up some code.
90
+ def to_s_method(meth, args=:self) # :nodoc:
91
+ class_eval("def to_s(ds) ds.#{meth}(#{args}) end", __FILE__, __LINE__)
92
+ class_eval("def to_s_append(ds, sql) ds.#{meth}_append(sql, #{args}) end", __FILE__, __LINE__)
93
+ end
84
94
  end
85
- private_class_method :to_s_method
86
95
 
87
96
  # Alias of <tt>eql?</tt>
88
97
  def ==(other)
@@ -140,6 +149,9 @@ module Sequel
140
149
  # Bitwise mathematical operators used in +NumericMethods+
141
150
  BITWISE_OPERATORS = [:&, :|, :^, :<<, :>>, :%]
142
151
 
152
+ # Operators that check for equality
153
+ EQUALITY_OPERATORS = [:'=', :'!=']
154
+
143
155
  # Inequality operators used in +InequalityMethods+
144
156
  INEQUALITY_OPERATORS = [:<, :>, :<=, :>=]
145
157
 
@@ -152,10 +164,14 @@ module Sequel
152
164
  # Operators that use IS, used for special casing to override literal true/false values
153
165
  IS_OPERATORS = [:IS, :'IS NOT']
154
166
 
167
+ # Operators that do pattern matching via regular expressions
168
+ REGEXP_OPERATORS = [:~, :'!~', :'~*', :'!~*']
169
+
170
+ # Operators that do pattern matching via LIKE
171
+ LIKE_OPERATORS = [:LIKE, :'NOT LIKE', :ILIKE, :'NOT ILIKE']
172
+
155
173
  # Operator symbols that take exactly two arguments
156
- TWO_ARITY_OPERATORS = [:'=', :'!=', :LIKE, :'NOT LIKE', \
157
- :~, :'!~', :'~*', :'!~*', :ILIKE, :'NOT ILIKE'] + \
158
- INEQUALITY_OPERATORS + IS_OPERATORS + IN_OPERATORS
174
+ TWO_ARITY_OPERATORS = EQUALITY_OPERATORS + INEQUALITY_OPERATORS + IS_OPERATORS + IN_OPERATORS + REGEXP_OPERATORS + LIKE_OPERATORS
159
175
 
160
176
  # Operator symbols that take one or more arguments
161
177
  N_ARITY_OPERATORS = [:AND, :OR, :'||'] + MATHEMATICAL_OPERATORS + BITWISE_OPERATORS
@@ -352,6 +368,15 @@ module Sequel
352
368
  cast(arg, sql_type || String).sql_string
353
369
  end
354
370
 
371
+ # Return an emulated function call for getting the number of characters
372
+ # in the argument:
373
+ #
374
+ # Sequel.char_length(:a) # char_length(a) -- Most databases
375
+ # Sequel.char_length(:a) # length(a) -- SQLite
376
+ def char_length(arg)
377
+ SQL::EmulatedFunction.new(:char_length, arg)
378
+ end
379
+
355
380
  # Order the given argument descending.
356
381
  # Options:
357
382
  #
@@ -567,6 +592,15 @@ module Sequel
567
592
  SQL::Subscript.new(exp, subs.flatten)
568
593
  end
569
594
 
595
+ # Return an emulated function call for trimming a string of spaces from
596
+ # both sides (similar to ruby's String#strip).
597
+ #
598
+ # Sequel.trim(:a) # trim(a) -- Most databases
599
+ # Sequel.trim(:a) # ltrim(rtrim(a)) -- Microsoft SQL Server
600
+ def trim(arg)
601
+ SQL::EmulatedFunction.new(:trim, arg)
602
+ end
603
+
570
604
  # Return a <tt>SQL::ValueList</tt> created from the given array. Used if the array contains
571
605
  # all two element arrays and you want it treated as an SQL value list (IN predicate)
572
606
  # instead of as a conditions specifier (similar to a hash). This is not necessary if you are using
@@ -1071,7 +1105,7 @@ module Sequel
1071
1105
 
1072
1106
  # Represents inverse boolean constants (currently only +NOTNULL+). A
1073
1107
  # special class to allow for special behavior.
1074
- class NegativeBooleanConstant < BooleanConstant
1108
+ class NegativeBooleanConstant < Constant
1075
1109
  to_s_method :negative_boolean_constant_sql, '@constant'
1076
1110
  end
1077
1111
 
@@ -1110,6 +1144,12 @@ module Sequel
1110
1144
 
1111
1145
  to_s_method :function_sql
1112
1146
  end
1147
+
1148
+ # Represents an SQL function call that is translated/emulated
1149
+ # on databases that lack support for such a function.
1150
+ class EmulatedFunction < Function
1151
+ to_s_method :emulated_function_sql
1152
+ end
1113
1153
 
1114
1154
  class GenericExpression
1115
1155
  include AliasMethods
@@ -165,15 +165,23 @@ module Sequel
165
165
  convert_input_timestamp(ary, input_timezone)
166
166
  when Time
167
167
  if datetime_class == DateTime
168
- v.respond_to?(:to_datetime) ? v.to_datetime : string_to_datetime(v.iso8601)
168
+ if v.respond_to?(:to_datetime)
169
+ v.to_datetime
170
+ else
171
+ # Ruby 1.8 code, %N not available and %z broken on Windows
172
+ offset_hours, offset_minutes = (v.utc_offset/60).divmod(60)
173
+ string_to_datetime(v.strftime("%Y-%m-%dT%H:%M:%S") << sprintf(".%06i%+03i%02i", v.usec, offset_hours, offset_minutes))
174
+ end
169
175
  else
170
176
  v
171
177
  end
172
178
  when DateTime
173
179
  if datetime_class == DateTime
174
180
  v
181
+ elsif v.respond_to?(:to_time)
182
+ v.to_time
175
183
  else
176
- v.respond_to?(:to_time) ? v.to_time : string_to_datetime(v.to_s)
184
+ string_to_datetime(v.strftime("%FT%T.%N%z"))
177
185
  end
178
186
  else
179
187
  raise InvalidValue, "Invalid convert_input_timestamp type: #{v.inspect}"
@@ -3,7 +3,7 @@ module Sequel
3
3
  MAJOR = 3
4
4
  # The minor version of Sequel. Bumped for every non-patch level
5
5
  # release, generally around once a month.
6
- MINOR = 38
6
+ MINOR = 39
7
7
  # The tiny version of Sequel. Usually 0, only bumped for bugfix
8
8
  # releases that fix regressions from previous versions.
9
9
  TINY = 0
@@ -18,23 +18,6 @@ def logger.method_missing(m, msg)
18
18
  end
19
19
  MSSQL_DB.loggers = [logger]
20
20
 
21
- MSSQL_DB.create_table! :test do
22
- String :name, :type=>:text
23
- Integer :value, :index => true
24
- end
25
- MSSQL_DB.create_table! :test2 do
26
- String :name, :type=>:text
27
- Integer :value
28
- end
29
- MSSQL_DB.create_table! :test3 do
30
- Integer :value
31
- Time :time
32
- end
33
- MSSQL_DB.create_table! :test4 do
34
- String :name, :size => 20
35
- column :value, 'varbinary(max)'
36
- end
37
-
38
21
  describe "A MSSQL database" do
39
22
  before do
40
23
  @db = MSSQL_DB
@@ -54,7 +37,20 @@ describe "A MSSQL database" do
54
37
  proc{@db.server_version}.should_not raise_error
55
38
  proc{@db.dataset.server_version}.should_not raise_error
56
39
  end
40
+ end
57
41
 
42
+ describe "A MSSQL database" do
43
+ before do
44
+ @db = MSSQL_DB
45
+ @db.create_table! :test3 do
46
+ Integer :value
47
+ Time :time
48
+ end
49
+ end
50
+ after do
51
+ @db.drop_table?(:test3)
52
+ end
53
+
58
54
  specify "should work with NOLOCK" do
59
55
  @db.transaction{@db[:test3].nolock.all.should == []}
60
56
  end
@@ -379,12 +375,15 @@ describe "MSSSQL::Dataset#insert" do
379
375
  before do
380
376
  @db = MSSQL_DB
381
377
  @db.create_table!(:test5){primary_key :xid; Integer :value}
378
+ @db.create_table! :test4 do
379
+ String :name, :size => 20
380
+ column :value, 'varbinary(max)'
381
+ end
382
382
  @db.sqls.clear
383
383
  @ds = @db[:test5]
384
384
  end
385
385
  after do
386
- @db[:test4].delete
387
- @db.drop_table?(:test5)
386
+ @db.drop_table?(:test5, :test4)
388
387
  end
389
388
 
390
389
  specify "should have insert_select return nil if disable_insert_output is used" do
@@ -409,11 +408,9 @@ describe "MSSSQL::Dataset#insert" do
409
408
  b.length.should == blob.length
410
409
  b.should == blob
411
410
  end
412
- end
413
411
 
414
- describe "MSSSQL::Dataset#disable_insert_output" do
415
412
  specify "should play nicely with simple_select_all?" do
416
- MSSQL_DB[:test].disable_insert_output.send(:simple_select_all?).should == true
413
+ MSSQL_DB[:test4].disable_insert_output.send(:simple_select_all?).should == true
417
414
  end
418
415
  end
419
416
 
@@ -462,16 +459,20 @@ describe "A MSSQL database" do
462
459
  end
463
460
 
464
461
  describe "MSSQL::Database#rename_table" do
462
+ after do
463
+ MSSQL_DB.drop_table?(:foo)
464
+ end
465
+
465
466
  specify "should work on non-schema bound tables which need escaping" do
466
467
  MSSQL_DB.quote_identifiers = true
467
468
  MSSQL_DB.create_table! :'foo bar' do
468
469
  text :name
469
470
  end
470
- MSSQL_DB.drop_table? :baz
471
- proc { MSSQL_DB.rename_table 'foo bar', 'baz' }.should_not raise_error
471
+ MSSQL_DB.drop_table? :foo
472
+ proc { MSSQL_DB.rename_table 'foo bar', 'foo' }.should_not raise_error
472
473
  end
473
474
 
474
- specify "should workd on schema bound tables" do
475
+ specify "should work on schema bound tables" do
475
476
  MSSQL_DB.execute(<<-SQL)
476
477
  IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = 'MY')
477
478
  EXECUTE sp_executesql N'create schema MY'