sequel 4.9.0 → 4.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +79 -1
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/Rakefile +2 -12
  6. data/bin/sequel +1 -0
  7. data/doc/advanced_associations.rdoc +82 -25
  8. data/doc/association_basics.rdoc +21 -22
  9. data/doc/core_extensions.rdoc +1 -1
  10. data/doc/opening_databases.rdoc +7 -0
  11. data/doc/release_notes/4.10.0.txt +226 -0
  12. data/doc/security.rdoc +1 -0
  13. data/doc/testing.rdoc +7 -7
  14. data/doc/transactions.rdoc +8 -0
  15. data/lib/sequel/adapters/jdbc.rb +160 -168
  16. data/lib/sequel/adapters/jdbc/db2.rb +17 -18
  17. data/lib/sequel/adapters/jdbc/derby.rb +5 -28
  18. data/lib/sequel/adapters/jdbc/h2.rb +11 -22
  19. data/lib/sequel/adapters/jdbc/hsqldb.rb +31 -18
  20. data/lib/sequel/adapters/jdbc/jtds.rb +0 -15
  21. data/lib/sequel/adapters/jdbc/oracle.rb +36 -35
  22. data/lib/sequel/adapters/jdbc/postgresql.rb +72 -90
  23. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +18 -16
  24. data/lib/sequel/adapters/jdbc/sqlite.rb +7 -0
  25. data/lib/sequel/adapters/jdbc/sqlserver.rb +10 -30
  26. data/lib/sequel/adapters/jdbc/transactions.rb +5 -6
  27. data/lib/sequel/adapters/openbase.rb +1 -7
  28. data/lib/sequel/adapters/postgres.rb +1 -1
  29. data/lib/sequel/adapters/shared/access.rb +3 -6
  30. data/lib/sequel/adapters/shared/cubrid.rb +24 -9
  31. data/lib/sequel/adapters/shared/db2.rb +13 -5
  32. data/lib/sequel/adapters/shared/firebird.rb +16 -16
  33. data/lib/sequel/adapters/shared/informix.rb +2 -5
  34. data/lib/sequel/adapters/shared/mssql.rb +72 -63
  35. data/lib/sequel/adapters/shared/mysql.rb +72 -40
  36. data/lib/sequel/adapters/shared/oracle.rb +27 -15
  37. data/lib/sequel/adapters/shared/postgres.rb +24 -44
  38. data/lib/sequel/adapters/shared/progress.rb +1 -5
  39. data/lib/sequel/adapters/shared/sqlanywhere.rb +26 -18
  40. data/lib/sequel/adapters/shared/sqlite.rb +21 -6
  41. data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +8 -1
  42. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +8 -2
  43. data/lib/sequel/adapters/utils/split_alter_table.rb +8 -0
  44. data/lib/sequel/core.rb +14 -9
  45. data/lib/sequel/database/dataset_defaults.rb +1 -0
  46. data/lib/sequel/database/misc.rb +12 -0
  47. data/lib/sequel/database/query.rb +4 -1
  48. data/lib/sequel/database/schema_methods.rb +3 -2
  49. data/lib/sequel/database/transactions.rb +47 -17
  50. data/lib/sequel/dataset/features.rb +12 -2
  51. data/lib/sequel/dataset/mutation.rb +2 -0
  52. data/lib/sequel/dataset/placeholder_literalizer.rb +12 -4
  53. data/lib/sequel/dataset/prepared_statements.rb +6 -0
  54. data/lib/sequel/dataset/query.rb +1 -1
  55. data/lib/sequel/dataset/sql.rb +132 -70
  56. data/lib/sequel/extensions/columns_introspection.rb +1 -1
  57. data/lib/sequel/extensions/null_dataset.rb +8 -4
  58. data/lib/sequel/extensions/pg_array.rb +4 -4
  59. data/lib/sequel/extensions/pg_row.rb +1 -0
  60. data/lib/sequel/model/associations.rb +468 -188
  61. data/lib/sequel/model/base.rb +88 -13
  62. data/lib/sequel/plugins/association_pks.rb +23 -64
  63. data/lib/sequel/plugins/auto_validations.rb +3 -2
  64. data/lib/sequel/plugins/dataset_associations.rb +1 -3
  65. data/lib/sequel/plugins/many_through_many.rb +18 -65
  66. data/lib/sequel/plugins/pg_array_associations.rb +97 -86
  67. data/lib/sequel/plugins/prepared_statements.rb +2 -1
  68. data/lib/sequel/plugins/prepared_statements_associations.rb +36 -27
  69. data/lib/sequel/plugins/rcte_tree.rb +12 -16
  70. data/lib/sequel/plugins/sharding.rb +21 -3
  71. data/lib/sequel/plugins/single_table_inheritance.rb +2 -1
  72. data/lib/sequel/plugins/subclasses.rb +1 -9
  73. data/lib/sequel/plugins/tactical_eager_loading.rb +9 -0
  74. data/lib/sequel/plugins/tree.rb +2 -2
  75. data/lib/sequel/plugins/validation_class_methods.rb +1 -1
  76. data/lib/sequel/version.rb +1 -1
  77. data/spec/adapters/mssql_spec.rb +57 -15
  78. data/spec/adapters/mysql_spec.rb +11 -0
  79. data/spec/bin_spec.rb +2 -2
  80. data/spec/core/database_spec.rb +38 -4
  81. data/spec/core/dataset_spec.rb +45 -7
  82. data/spec/core/placeholder_literalizer_spec.rb +17 -0
  83. data/spec/core/schema_spec.rb +6 -1
  84. data/spec/extensions/active_model_spec.rb +18 -9
  85. data/spec/extensions/association_pks_spec.rb +20 -18
  86. data/spec/extensions/association_proxies_spec.rb +9 -9
  87. data/spec/extensions/auto_validations_spec.rb +6 -0
  88. data/spec/extensions/columns_introspection_spec.rb +1 -0
  89. data/spec/extensions/constraint_validations_spec.rb +3 -1
  90. data/spec/extensions/many_through_many_spec.rb +191 -111
  91. data/spec/extensions/pg_array_associations_spec.rb +133 -103
  92. data/spec/extensions/prepared_statements_associations_spec.rb +23 -4
  93. data/spec/extensions/rcte_tree_spec.rb +35 -27
  94. data/spec/extensions/sequel_3_dataset_methods_spec.rb +0 -1
  95. data/spec/extensions/sharding_spec.rb +2 -2
  96. data/spec/extensions/tactical_eager_loading_spec.rb +4 -0
  97. data/spec/extensions/to_dot_spec.rb +1 -0
  98. data/spec/extensions/touch_spec.rb +2 -2
  99. data/spec/integration/associations_test.rb +130 -37
  100. data/spec/integration/dataset_test.rb +17 -0
  101. data/spec/integration/model_test.rb +17 -0
  102. data/spec/integration/schema_test.rb +14 -0
  103. data/spec/integration/transaction_test.rb +25 -1
  104. data/spec/model/association_reflection_spec.rb +63 -24
  105. data/spec/model/associations_spec.rb +104 -57
  106. data/spec/model/base_spec.rb +14 -1
  107. data/spec/model/class_dataset_methods_spec.rb +1 -0
  108. data/spec/model/eager_loading_spec.rb +221 -74
  109. data/spec/model/model_spec.rb +119 -1
  110. metadata +4 -2
@@ -130,7 +130,8 @@ module Sequel
130
130
  h = @prepared_statements[type]
131
131
  Sequel.synchronize do
132
132
  if v = h[subtype]
133
- return v end
133
+ return v
134
+ end
134
135
  end
135
136
  ps = yield
136
137
  Sequel.synchronize{h[subtype] = ps}
@@ -22,17 +22,6 @@ module Sequel
22
22
  # lambda returns the next integer to use.
23
23
  NEXT = lambda{MUTEX.synchronize{i += 1}}
24
24
 
25
- module ClassMethods
26
- # Disable prepared statement use if a block is given, or the :dataset or :conditions
27
- # options are used, or you are cloning an association.
28
- def associate(type, name, opts = OPTS, &block)
29
- if block || opts[:dataset] || (opts[:clone] && association_reflection(opts[:clone])[:prepared_statement] == false)
30
- opts = opts.merge(:prepared_statement=>false)
31
- end
32
- super(type, name, opts, &block)
33
- end
34
- end
35
-
36
25
  module InstanceMethods
37
26
  private
38
27
 
@@ -50,9 +39,9 @@ module Sequel
50
39
  association_bound_variable_hash(opts.associated_class.table_name, opts.primary_keys, opts[:keys])
51
40
  when :one_to_many, :one_to_one
52
41
  association_bound_variable_hash(opts.associated_class.table_name, opts[:keys], opts[:primary_keys])
53
- when :many_to_many
42
+ when :many_to_many, :one_through_one
54
43
  association_bound_variable_hash(opts.join_table_alias, opts[:left_keys], opts[:left_primary_keys])
55
- when :many_through_many
44
+ when :many_through_many, :one_through_many
56
45
  association_bound_variable_hash(opts.final_reverse_edge[:alias], Array(opts[:left_key]), opts[:left_primary_keys])
57
46
  end
58
47
  end
@@ -62,26 +51,46 @@ module Sequel
62
51
  # instance. Return false if such a prepared statement cannot be created.
63
52
  def association_prepared_statement(opts, assoc_bv)
64
53
  opts.send(:cached_fetch, :prepared_statement) do
65
- ds, bv = _associated_dataset(opts, {}).unbind
66
- if bv.length != assoc_bv.length
67
- h = {}
68
- bv.each do |k,v|
69
- h[k] = v unless assoc_bv.has_key?(k)
54
+ unless opts[:instance_specific]
55
+ ds, bv = _associated_dataset(opts, {}).unbind
56
+ if bv.length != assoc_bv.length
57
+ h = {}
58
+ bv.each do |k,v|
59
+ h[k] = v unless assoc_bv.has_key?(k)
60
+ end
61
+ ds = ds.bind(h)
70
62
  end
71
- ds = ds.bind(h)
63
+ ps = ds.prepare(opts.returns_array? ? :select : :first, :"smpsap_#{NEXT.call}")
64
+ ps.log_sql = true
65
+ ps
72
66
  end
73
- ps = ds.prepare(opts.returns_array? ? :select : :first, :"smpsap_#{NEXT.call}")
74
- ps.log_sql = true
75
- ps
76
67
  end
77
68
  end
78
69
 
79
- # If a prepared statement can be used to load the associated objects, execute it to retrieve them. Otherwise,
80
- # fall back to the default implementation.
81
- def _load_associated_objects(opts, dynamic_opts=OPTS)
82
- if !opts.can_have_associated_objects?(self) || dynamic_opts[:callback] || (load_with_primary_key_lookup?(opts, dynamic_opts) && opts.associated_class.respond_to?(:cache_get_pk))
70
+ # Use a prepared statement if possible to load the associated object,
71
+ # unless a dynamic callback is given.
72
+ def _load_associated_object(opts, dynamic_opts)
73
+ if !dynamic_opts[:callback] && (bv = association_bound_variables(opts)) && (ps ||= association_prepared_statement(opts, bv))
74
+ ps.call(bv)
75
+ else
83
76
  super
84
- elsif (bv = association_bound_variables(opts)) && (ps ||= association_prepared_statement(opts, bv))
77
+ end
78
+ end
79
+
80
+ # Use a prepared statement if possible to load the associated object,
81
+ # unless the associated model uses caching.
82
+ def _load_associated_object_via_primary_key(opts)
83
+ if !opts.associated_class.respond_to?(:cache_get_pk) && (bv = association_bound_variables(opts)) && (ps ||= association_prepared_statement(opts, bv))
84
+ ps.call(bv)
85
+ else
86
+ super
87
+ end
88
+ end
89
+
90
+ # Use a prepared statement if possible to load the associated objects,
91
+ # unless a dynamic callback is given.
92
+ def _load_associated_object_array(opts, dynamic_opts)
93
+ if !dynamic_opts[:callback] && (bv = association_bound_variables(opts)) && (ps ||= association_prepared_statement(opts, bv))
85
94
  ps.call(bv)
86
95
  else
87
96
  super
@@ -204,15 +204,12 @@ module Sequel
204
204
  end
205
205
  end
206
206
  table_alias = model.dataset.schema_and_table(model.table_name)[1].to_sym
207
- elds = model.eager_loading_dataset(r,
208
- model.from(SQL::AliasedExpression.new(t, table_alias)).
209
- with_recursive(t, base_case,
210
- recursive_case,
211
- :args=>((key_aliases + col_aliases) if col_aliases)),
212
- r.select,
213
- eo[:associations], eo)
214
- elds = elds.select_append(ka) unless elds.opts[:select] == nil
215
- elds.all do |obj|
207
+ ds = model.from(SQL::AliasedExpression.new(t, table_alias)).
208
+ with_recursive(t, base_case, recursive_case,
209
+ :args=>((key_aliases + col_aliases) if col_aliases))
210
+ ds = r.apply_eager_dataset_changes(ds)
211
+ ds = ds.select_append(ka) unless ds.opts[:select] == nil
212
+ model.eager_load_results(r, eo.merge(:loader=>false, :initalize_rows=>false, :dataset=>ds, :id_map=>nil)) do |obj|
216
213
  opk = prkey_conv[obj]
217
214
  if parent_map.has_key?(opk)
218
215
  if idm_obj = parent_map[opk]
@@ -308,13 +305,12 @@ module Sequel
308
305
  recursive_case = recursive_case.select_more(SQL::AliasedExpression.new(SQL::QualifiedIdentifier.new(t, la) + 1, la)).filter(SQL::QualifiedIdentifier.new(t, la) < level - 1)
309
306
  end
310
307
  table_alias = model.dataset.schema_and_table(model.table_name)[1].to_sym
311
- elds = model.eager_loading_dataset(r,
312
- model.from(SQL::AliasedExpression.new(t, table_alias)).with_recursive(t, base_case, recursive_case,
313
- :args=>((key_aliases + col_aliases + (level ? [la] : [])) if col_aliases)),
314
- r.select,
315
- associations, eo)
316
- elds = elds.select_append(ka) unless elds.opts[:select] == nil
317
- elds.all do |obj|
308
+ ds = model.from(SQL::AliasedExpression.new(t, table_alias)).
309
+ with_recursive(t, base_case, recursive_case,
310
+ :args=>((key_aliases + col_aliases + (level ? [la] : [])) if col_aliases))
311
+ ds = r.apply_eager_dataset_changes(ds)
312
+ ds = ds.select_append(ka) unless ds.opts[:select] == nil
313
+ model.eager_load_results(r, eo.merge(:loader=>false, :initalize_rows=>false, :dataset=>ds, :id_map=>nil, :associations=>{})) do |obj|
318
314
  if level
319
315
  no_cache = no_cache_level == obj.values.delete(la)
320
316
  end
@@ -24,9 +24,22 @@ module Sequel
24
24
  new_using_server(s, values, &block).save
25
25
  end
26
26
 
27
- # When eagerly loading, if the current dataset has a defined shard and the
28
- # dataset that you will be using to get the associated records does not,
29
- # use the current dataset's shard for the associated dataset.
27
+ # Eager load the association with the given eager loader options.
28
+ def eager_load_results(opts, eo, &block)
29
+ if (s = eo[:self]) && (server = s.opts[:server])
30
+ eb = eo[:eager_block]
31
+ set_server = proc do |ds|
32
+ ds = eb.call(ds) if eb
33
+ ds = ds.server(server) unless ds.opts[:server]
34
+ ds
35
+ end
36
+ eo = eo.merge(:eager_block=>set_server)
37
+ end
38
+
39
+ super
40
+ end
41
+
42
+ # REMOVE410
30
43
  def eager_loading_dataset(opts, ds, select, associations, eager_options=OPTS)
31
44
  ds = super(opts, ds, select, associations, eager_options)
32
45
  if !ds.opts[:server] and s = eager_options[:self] and server = s.opts[:server]
@@ -70,6 +83,11 @@ module Sequel
70
83
  use_server(super)
71
84
  end
72
85
 
86
+ # Don't use an associated object loader, as it won't respect the shard used.
87
+ def _associated_object_loader(opts, dynamic_opts)
88
+ nil
89
+ end
90
+
73
91
  # Ensure that the join table for many_to_many associations uses the correct shard.
74
92
  def _join_table_dataset(opts)
75
93
  use_server(super)
@@ -182,7 +182,8 @@ module Sequel
182
182
  # keys for all of their descendant classes.
183
183
  def sti_subclass_added(key)
184
184
  if sti_key_array
185
- Sequel.synchronize{sti_key_array.push(*Array(key))}
185
+ key_array = Array(key)
186
+ Sequel.synchronize{sti_key_array.push(*key_array)}
186
187
  superclass.sti_subclass_added(key)
187
188
  end
188
189
  end
@@ -42,7 +42,7 @@ module Sequel
42
42
 
43
43
  # All descendent classes of this model.
44
44
  def descendents
45
- Sequel.synchronize{_descendents}
45
+ Sequel.synchronize{subclasses.dup}.map{|x| [x] + x.send(:descendents)}.flatten
46
46
  end
47
47
 
48
48
  Plugins.inherited_instance_variables(self, :@subclasses=>lambda{|v| []}, :@on_subclass=>nil)
@@ -55,14 +55,6 @@ module Sequel
55
55
  Sequel.synchronize{subclasses << subclass}
56
56
  on_subclass.call(subclass) if on_subclass
57
57
  end
58
-
59
- private
60
-
61
- # Recursive, non-thread safe version of descendents, since
62
- # the mutex Sequel uses isn't reentrant.
63
- def _descendents
64
- subclasses.map{|x| [x] + x.send(:_descendents)}.flatten
65
- end
66
58
  end
67
59
  end
68
60
  end
@@ -35,6 +35,15 @@ module Sequel
35
35
  # reteived via Dataset#all.
36
36
  attr_accessor :retrieved_with
37
37
 
38
+ # Remove retrieved_by and retrieved_with when marshalling. retrieved_by
39
+ # contains unmarshallable objects, and retrieved_with can be very large
40
+ # and is not helpful without retrieved_by.
41
+ def marshallable!
42
+ @retrieved_by = nil
43
+ @retrieved_with = nil
44
+ super
45
+ end
46
+
38
47
  private
39
48
 
40
49
  # If there the association is not in the associations cache and the object
@@ -88,9 +88,9 @@ module Sequel
88
88
  nodes
89
89
  end
90
90
 
91
- # Returns list of ancestors, starting from parent until root.
91
+ # Returns list of descendants
92
92
  #
93
- # subchild1.ancestors # => [child1, root]
93
+ # node.descendants # => [child1, child2, subchild1_1, subchild1_2, subchild2_1, subchild2_2]
94
94
  def descendants
95
95
  nodes = children.dup
96
96
  children.each{|child| nodes.concat(child.descendants)}
@@ -67,7 +67,7 @@ module Sequel
67
67
  # Instructs the model to skip validations defined in superclasses
68
68
  def skip_superclass_validations
69
69
  superclass.validations.each do |att, procs|
70
- if ps = @validations[att]
70
+ if @validations[att]
71
71
  @validations[att] -= procs
72
72
  end
73
73
  end
@@ -3,7 +3,7 @@ module Sequel
3
3
  MAJOR = 4
4
4
  # The minor version of Sequel. Bumped for every non-patch level
5
5
  # release, generally around once a month.
6
- MINOR = 9
6
+ MINOR = 10
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
@@ -656,25 +656,67 @@ describe "MSSQL Stored Procedure support" do
656
656
  @db.execute('DROP PROCEDURE dbo.SequelTest')
657
657
  end
658
658
 
659
- it "should return a hash of output variables" do
660
- r = @db.call_mssql_sproc(:SequelTest, {:args => [@now, 1, :output, :output]})
661
- r.should be_a_kind_of(Hash)
662
- r.values_at(:var2, :var3).should == [@now, '1']
663
- end
659
+ describe "with unnamed parameters" do
660
+ it "should return a hash of output variables" do
661
+ r = @db.call_mssql_sproc(:SequelTest, {:args => [@now, 1, :output, :output]})
662
+ r.should be_a_kind_of(Hash)
663
+ r.values_at(:var2, :var3).should == [@now, '1']
664
+ end
664
665
 
665
- it "should support typed output variables" do
666
- @db.call_mssql_sproc(:SequelTest, {:args => [@now, 1, :output, [:output, 'int']]})[:var3].should == 1
667
- end
666
+ it "should support typed output variables" do
667
+ @db.call_mssql_sproc(:SequelTest, {:args => [@now, 1, :output, [:output, 'int']]})[:var3].should == 1
668
+ end
668
669
 
669
- it "should support named output variables" do
670
- @db.call_mssql_sproc(:SequelTest, {:args => [@now, 1, [:output, nil, 'output'], :output]})[:output].should == @now
671
- end
670
+ it "should support named output variables" do
671
+ @db.call_mssql_sproc(:SequelTest, {:args => [@now, 1, [:output, nil, 'output'], :output]})[:output].should == @now
672
+ end
673
+
674
+ it "should return the number of Affected Rows" do
675
+ @db.call_mssql_sproc(:SequelTest, {:args => [@now, 1, :output, :output]})[:numrows].should == 1
676
+ end
672
677
 
673
- it "should return the number of Affected Rows" do
674
- @db.call_mssql_sproc(:SequelTest, {:args => [@now, 1, :output, :output]})[:numrows].should == 1
678
+ it "should return the Result Code" do
679
+ @db.call_mssql_sproc(:SequelTest, {:args => [@now, 1, :output, :output]})[:result].should == 1
680
+ end
675
681
  end
676
682
 
677
- it "should return the Result Code" do
678
- @db.call_mssql_sproc(:SequelTest, {:args => [@now, 1, :output, :output]})[:result].should == 1
683
+ describe "with named parameters" do
684
+ it "should return a hash of output variables" do
685
+ r = @db.call_mssql_sproc(:SequelTest, :args => {
686
+ 'Input' => @now,
687
+ 'IntegerInput' => 1,
688
+ 'Output' => [:output, nil, 'output'],
689
+ 'IntegerOutput' => [:output, nil, 'integer_output']
690
+ })
691
+ r.should be_a_kind_of(Hash)
692
+ r.values_at(:output, :integer_output).should == [@now, '1']
693
+ end
694
+
695
+ it "should support typed output variables" do
696
+ @db.call_mssql_sproc(:SequelTest, :args => {
697
+ 'Input' => @now,
698
+ 'IntegerInput' => 1,
699
+ 'Output' => [:output, nil, 'output'],
700
+ 'IntegerOutput' => [:output, 'int', 'integer_output']
701
+ })[:integer_output].should == 1
702
+ end
703
+
704
+ it "should return the number of Affected Rows" do
705
+ @db.call_mssql_sproc(:SequelTest, :args => {
706
+ 'Input' => @now,
707
+ 'IntegerInput' => 1,
708
+ 'Output' => [:output, nil, 'output'],
709
+ 'IntegerOutput' => [:output, nil, 'integer_output']
710
+ })[:numrows].should == 1
711
+ end
712
+
713
+ it "should return the Result Code" do
714
+ @db.call_mssql_sproc(:SequelTest, :args => {
715
+ 'Input' => @now,
716
+ 'IntegerInput' => 1,
717
+ 'Output' => [:output, nil, 'output'],
718
+ 'IntegerOutput' => [:output, nil, 'integer_output']
719
+ })[:result].should == 1
720
+ end
679
721
  end
680
722
  end unless DB.adapter_scheme == :odbc
@@ -520,6 +520,17 @@ describe "A MySQL database" do
520
520
  end
521
521
  end
522
522
 
523
+ specify "should correctly format ALTER TABLE statements with named foreign keys" do
524
+ @db.create_table(:items){Integer :id}
525
+ @db.create_table(:users){primary_key :id}
526
+ @db.alter_table(:items){add_foreign_key :p_id, :users, :key => :id, :null => false, :on_delete => :cascade, :foreign_key_constraint_name => :pk_items__users }
527
+ check_sqls do
528
+ @db.sqls.should == ["CREATE TABLE `items` (`id` integer)",
529
+ "CREATE TABLE `users` (`id` integer PRIMARY KEY AUTO_INCREMENT)",
530
+ "ALTER TABLE `items` ADD COLUMN `p_id` integer NOT NULL, ADD CONSTRAINT `pk_items__users` FOREIGN KEY (`p_id`) REFERENCES `users`(`id`) ON DELETE CASCADE"]
531
+ end
532
+ end
533
+
523
534
  specify "should have rename_column support keep existing options" do
524
535
  @db.create_table(:items){String :id, :null=>false, :default=>'blah'}
525
536
  @db.alter_table(:items){rename_column :id, :nid}
data/spec/bin_spec.rb CHANGED
@@ -140,7 +140,7 @@ END
140
140
  end
141
141
 
142
142
  it "-E should echo SQL statements to stdout" do
143
- bin(:args=>'-E -c DB.tables').should =~ %r{I, \[\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d+ #\d+\] INFO -- : \(\d\.\d+s\) PRAGMA foreign_keys = 1\nI, \[\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d+ #\d+\] INFO -- : \(\d\.\d+s\) PRAGMA case_sensitive_like = 1\nI, \[\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d+ #\d+\] INFO -- : \(\d\.\d+s\) SELECT \* FROM `sqlite_master` WHERE \(type = 'table' AND NOT name = 'sqlite_sequence'\)\n}
143
+ bin(:args=>'-E -c DB.tables').should =~ %r{SELECT \* FROM `sqlite_master` WHERE \(type = 'table' AND NOT name = 'sqlite_sequence'\)\n}
144
144
  end
145
145
 
146
146
  it "-I should include directory in load path" do
@@ -149,7 +149,7 @@ END
149
149
 
150
150
  it "-l should log SQL statements to file" do
151
151
  bin(:args=>"-l #{TMP_FILE} -c DB.tables").should == ''
152
- File.read(TMP_FILE).should =~ %r{I, \[\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d+ #\d+\] INFO -- : \(\d\.\d+s\) PRAGMA foreign_keys = 1\nI, \[\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d+ #\d+\] INFO -- : \(\d\.\d+s\) PRAGMA case_sensitive_like = 1\nI, \[\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d+ #\d+\] INFO -- : \(\d\.\d+s\) SELECT \* FROM `sqlite_master` WHERE \(type = 'table' AND NOT name = 'sqlite_sequence'\)\n}
152
+ File.read(TMP_FILE).should =~ %r{SELECT \* FROM `sqlite_master` WHERE \(type = 'table' AND NOT name = 'sqlite_sequence'\)\n}
153
153
  end
154
154
 
155
155
  it "-L should load all *.rb files in given directory" do
@@ -927,7 +927,6 @@ describe "Database#transaction with savepoint support" do
927
927
  it_should_behave_like "Database#transaction"
928
928
 
929
929
  specify "should support after_commit inside savepoints" do
930
- meta_def(@db, :supports_savepoints?){true}
931
930
  @db.transaction do
932
931
  @db.after_commit{@db.execute('foo')}
933
932
  @db.transaction(:savepoint=>true){@db.after_commit{@db.execute('bar')}}
@@ -937,7 +936,6 @@ describe "Database#transaction with savepoint support" do
937
936
  end
938
937
 
939
938
  specify "should support after_rollback inside savepoints" do
940
- meta_def(@db, :supports_savepoints?){true}
941
939
  @db.transaction do
942
940
  @db.after_rollback{@db.execute('foo')}
943
941
  @db.transaction(:savepoint=>true){@db.after_rollback{@db.execute('bar')}}
@@ -948,14 +946,12 @@ describe "Database#transaction with savepoint support" do
948
946
  end
949
947
 
950
948
  specify "should raise an error if you attempt to use after_commit inside a savepoint in a prepared transaction" do
951
- meta_def(@db, :supports_savepoints?){true}
952
949
  meta_def(@db, :supports_prepared_transactions?){true}
953
950
  proc{@db.transaction(:prepare=>'XYZ'){@db.transaction(:savepoint=>true){@db.after_commit{@db.execute('foo')}}}}.should raise_error(Sequel::Error)
954
951
  @db.sqls.should == ['BEGIN', 'SAVEPOINT autopoint_1','ROLLBACK TO SAVEPOINT autopoint_1', 'ROLLBACK']
955
952
  end
956
953
 
957
954
  specify "should raise an error if you attempt to use after_rollback inside a savepoint in a prepared transaction" do
958
- meta_def(@db, :supports_savepoints?){true}
959
955
  meta_def(@db, :supports_prepared_transactions?){true}
960
956
  proc{@db.transaction(:prepare=>'XYZ'){@db.transaction(:savepoint=>true){@db.after_rollback{@db.execute('foo')}}}}.should raise_error(Sequel::Error)
961
957
  @db.sqls.should == ['BEGIN', 'SAVEPOINT autopoint_1','ROLLBACK TO SAVEPOINT autopoint_1', 'ROLLBACK']
@@ -1023,6 +1019,25 @@ describe "Database#transaction with savepoints" do
1023
1019
  @db.sqls.should == ['BEGIN', 'SAVEPOINT autopoint_1', 'DROP TABLE test;', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1024
1020
  end
1025
1021
 
1022
+ specify "should use savepoints if surrounding transaction uses :auto_savepoint option" do
1023
+ @db.transaction(:auto_savepoint=>true){@db.transaction{@db.execute 'DROP TABLE test;'}}
1024
+ @db.sqls.should == ['BEGIN', 'SAVEPOINT autopoint_1', 'DROP TABLE test;', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1025
+
1026
+ @db.transaction(:auto_savepoint=>true){@db.transaction{@db.transaction{@db.execute 'DROP TABLE test;'}}}
1027
+ @db.sqls.should == ['BEGIN', 'SAVEPOINT autopoint_1', 'DROP TABLE test;', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1028
+
1029
+ @db.transaction(:auto_savepoint=>true){@db.transaction(:auto_savepoint=>true){@db.transaction{@db.execute 'DROP TABLE test;'}}}
1030
+ @db.sqls.should == ['BEGIN', 'SAVEPOINT autopoint_1', 'SAVEPOINT autopoint_2', 'DROP TABLE test;', 'RELEASE SAVEPOINT autopoint_2', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1031
+
1032
+ @db.transaction{@db.transaction(:auto_savepoint=>true, :savepoint=>true){@db.transaction{@db.execute 'DROP TABLE test;'}}}
1033
+ @db.sqls.should == ['BEGIN', 'SAVEPOINT autopoint_1', 'SAVEPOINT autopoint_2', 'DROP TABLE test;', 'RELEASE SAVEPOINT autopoint_2', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1034
+ end
1035
+
1036
+ specify "should not use savepoints if surrounding transaction uses :auto_savepoint and current transaction uses :savepoint=>false option" do
1037
+ @db.transaction(:auto_savepoint=>true){@db.transaction(:savepoint=>false){@db.execute 'DROP TABLE test;'}}
1038
+ @db.sqls.should == ['BEGIN', 'DROP TABLE test;', 'COMMIT']
1039
+ end
1040
+
1026
1041
  specify "should not use a savepoint if no transaction is in progress" do
1027
1042
  @db.transaction(:savepoint=>true){@db.execute 'DROP TABLE test;'}
1028
1043
  @db.sqls.should == ['BEGIN', 'DROP TABLE test;', 'COMMIT']
@@ -2434,3 +2449,22 @@ describe "Database#schema_type_class" do
2434
2449
  end
2435
2450
  end
2436
2451
  end
2452
+
2453
+ describe "Database#execute_{dui,ddl,insert}" do
2454
+ before do
2455
+ @db = Sequel::Database.new
2456
+ def @db.execute(sql, opts={})
2457
+ (@sqls ||= []) << sql
2458
+ end
2459
+ def @db.sqls
2460
+ @sqls
2461
+ end
2462
+ end
2463
+
2464
+ specify "should execute the SQL" do
2465
+ @db.execute_dui "DELETE FROM table"
2466
+ @db.execute_ddl "SET foo"
2467
+ @db.execute_insert "INSERT INTO table DEFAULT VALUES"
2468
+ @db.sqls.should == ["DELETE FROM table", "SET foo", "INSERT INTO table DEFAULT VALUES"]
2469
+ end
2470
+ end