sequel 3.38.0 → 3.39.0

Sign up to get free protection for your applications and to get access to all the features.
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'