sequel 4.9.0 → 4.10.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 (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