ibm_db 1.0.2 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,5 +1,13 @@
1
1
  Change Log
2
2
  ==============
3
+ 2009/03/24 (IBM_DB adapter 1.0.5, driver 1.0.5) :
4
+ - Support for Ruby-1.9.1
5
+ - Support for SQLRowcount in driver
6
+ - Support for Activerecord-2.3.2 [test suite updated]
7
+ - Fixed bug [24663] --> Fixed pre-mature clearing of the sql array in handle_lobs
8
+ - Fixed bug [23115] --> Fixed truncation of a nested query during update
9
+ - Fixed wrong setting of SQLID for schema on zOS 8 dataserver when schema is explicitly specified.
10
+
3
11
  2009/03/06 (IBM_DB adapter 1.0.2, driver 1.0.1) :
4
12
  - Support for specifying connection timeout in adapter
5
13
  - Fixed Bug [23317] --> Fixed assumption of id as the primary key while updation/insertion of lob fields
data/README CHANGED
@@ -1,5 +1,5 @@
1
1
  =====================================================================
2
- README for the IBM_DB Adapter (1.0.2) and Driver (1.0.1) (2009/03/06)
2
+ README for the IBM_DB Adapter (1.0.5) and Driver (1.0.5) (2009/03/24)
3
3
  For ActiveRecord Version >= 1.15.5 (and Rails >= 1.2.5)
4
4
  =====================================================================
5
5
 
@@ -2,7 +2,7 @@
2
2
  +----------------------------------------------------------------------+
3
3
  | Licensed Materials - Property of IBM |
4
4
  | |
5
- | (C) Copyright IBM Corporation 2006, 2007,2008 |
5
+ | (C) Copyright IBM Corporation 2006, 2007,2008, 2009 |
6
6
  +----------------------------------------------------------------------+
7
7
  | Authors: Sushant Koduru, Lynh Nguyen, Kanchana Padmanabhan, |
8
8
  | Dan Scott, Helmut Tessarek, Sam Ruby, Kellen Bombardier, |
@@ -12,7 +12,7 @@
12
12
  +----------------------------------------------------------------------+
13
13
  */
14
14
 
15
- #define MODULE_RELEASE "1.0.1"
15
+ #define MODULE_RELEASE "1.0.5"
16
16
 
17
17
  #ifdef HAVE_CONFIG_H
18
18
  #include "config.h"
@@ -579,6 +579,10 @@ void ruby_init_ibm_db()
579
579
  rb_define_const(mDB, "SQL_ATTR_INFO_APPLNAME", INT2NUM(SQL_ATTR_INFO_APPLNAME));
580
580
  /* String used to identify the client accounting string sent to the host database */
581
581
  rb_define_const(mDB, "SQL_ATTR_INFO_ACCTSTR", INT2NUM(SQL_ATTR_INFO_ACCTSTR));
582
+ /* Enabling Prefetching of Rowcount - Available from V95FP3 onwards */
583
+ rb_define_const(mDB, "SQL_ATTR_ROWCOUNT_PREFETCH", INT2NUM(SQL_ATTR_ROWCOUNT_PREFETCH));
584
+ rb_define_const(mDB, "SQL_ROWCOUNT_PREFETCH_ON", INT2NUM(SQL_ROWCOUNT_PREFETCH_ON));
585
+ rb_define_const(mDB, "SQL_ROWCOUNT_PREFETCH_OFF", INT2NUM(SQL_ROWCOUNT_PREFETCH_OFF));
582
586
  rb_global_variable(&persistent_list);
583
587
 
584
588
  /* REGISTER_INI_ENTRIES(); */
@@ -831,7 +835,7 @@ static int _ruby_ibm_db_parse_options ( VALUE options, int type, void *handle )
831
835
 
832
836
  if ( !NIL_P(options) ) {
833
837
  keys = rb_funcall(options, id_keys, 0);
834
- numOpts = RARRAY(keys)->len;
838
+ numOpts = RARRAY_LEN(keys);
835
839
 
836
840
  for ( i = 0; i < numOpts; i++) {
837
841
  key = rb_ary_entry(keys,i);
@@ -3140,11 +3144,10 @@ VALUE ibm_db_free_result(int argc, VALUE *argv, VALUE self)
3140
3144
  Data_Get_Struct(stmt, stmt_handle, stmt_res);
3141
3145
  if ( stmt_res->hstmt ) {
3142
3146
  /* Free any cursors that might have been allocated in a previous call to SQLExecute */
3143
- rc = SQLFreeHandle( SQL_HANDLE_STMT, stmt_res->hstmt);
3147
+ rc = SQLFreeStmt( stmt_res->hstmt, SQL_CLOSE);
3144
3148
  if ( rc == SQL_ERROR ) {
3145
3149
  _ruby_ibm_db_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
3146
3150
  }
3147
- stmt_res->hstmt = 0;
3148
3151
  }
3149
3152
  _ruby_ibm_db_free_result_struct(stmt_res);
3150
3153
  } else {
@@ -3653,7 +3656,7 @@ VALUE ibm_db_execute(int argc, VALUE *argv, VALUE self)
3653
3656
  return Qfalse;
3654
3657
  }
3655
3658
 
3656
- numOpts = RARRAY(parameters_array)->len;
3659
+ numOpts = RARRAY_LEN(parameters_array);
3657
3660
 
3658
3661
  if (numOpts > num) {
3659
3662
  /* More are passed in -- Warning - Use the max number present */
@@ -2,10 +2,11 @@
2
2
  +----------------------------------------------------------------------+
3
3
  | Licensed Materials - Property of IBM |
4
4
  | |
5
- | (C) Copyright IBM Corporation 2006, 2007. |
5
+ | (C) Copyright IBM Corporation 2006, 2007, 2008, 2009 |
6
6
  +----------------------------------------------------------------------+
7
7
  | Authors: Sushant Koduru, Lynh Nguyen, Kanchana Padmanabhan, |
8
8
  | Dan Scott, Helmut Tessarek, Kellen Bombardier, Sam Ruby |
9
+ | Ambrish Bhargava, Tarun Pasrija |
9
10
  +----------------------------------------------------------------------+
10
11
  */
11
12
 
@@ -26,6 +27,13 @@
26
27
  #define SQL_DECFLOAT -360
27
28
  #endif
28
29
 
30
+ /* needed for backward compatibility (SQL_ATTR_ROWCOUNT_PREFETCH not defined prior to DB2 9.5.0.3) */
31
+ #ifndef SQL_ATTR_ROWCOUNT_PREFETCH
32
+ #define SQL_ATTR_ROWCOUNT_PREFETCH 2592
33
+ #define SQL_ROWCOUNT_PREFETCH_OFF 0
34
+ #define SQL_ROWCOUNT_PREFETCH_ON 1
35
+ #endif
36
+
29
37
  /* SQL_ATTR_USE_TRUSTED_CONTEXT,
30
38
  * SQL_ATTR_TRUSTED_CONTEXT_USERID and
31
39
  * SQL_ATTR_TRUSTED_CONTEXT_PASSWORD
@@ -86,7 +86,7 @@ module ActiveRecord
86
86
  end
87
87
  end # if clob_sql
88
88
  end #connection.sql.each
89
- connection.sql = []
89
+ connection.handle_lobs_triggered = true
90
90
  end # if connection.kind_of?
91
91
  end # handle_lobs
92
92
  private :handle_lobs
@@ -362,7 +362,7 @@ module ActiveRecord
362
362
  if options[:limit]
363
363
  column.limit = options[:limit]
364
364
  elsif @base.native_database_types[type.to_sym]
365
- column.limit = @base.native_database_types[type.to_sym][:limit]
365
+ column.limit = @base.native_database_types[type.to_sym][:limit] if @base.native_database_types[type.to_sym].has_key? :limit
366
366
  end
367
367
 
368
368
  unless @columns.include? column
@@ -400,7 +400,7 @@ module ActiveRecord
400
400
  #
401
401
  class IBM_DBAdapter < AbstractAdapter
402
402
  attr_reader :connection, :servertype
403
- attr_accessor :sql
403
+ attr_accessor :sql,:handle_lobs_triggered
404
404
  attr_reader :schema, :app_user, :account, :application, :workstation
405
405
 
406
406
  # Name of the adapter
@@ -431,6 +431,7 @@ module ActiveRecord
431
431
  @workstation = conn_options[:workstation] if conn_options.has_key?(:workstation)
432
432
 
433
433
  @sql = []
434
+ @handle_lobs_triggered = false
434
435
 
435
436
  # Calls the parent class +ConnectionAdapters+' initializer
436
437
  # which sets @connection, @logger, @runtime and @last_verification
@@ -674,8 +675,9 @@ module ActiveRecord
674
675
  column_list = columns(table_name)
675
676
  fixture.each do |item|
676
677
  col = nil
677
- column_list.each do |col|
678
- if col.name == item.at(0)
678
+ column_list.each do |column|
679
+ if column.name.downcase == item.at(0).downcase
680
+ col= column
679
681
  break
680
682
  end
681
683
  end
@@ -723,6 +725,11 @@ module ActiveRecord
723
725
  # This can be the ID passed to the method or the one auto-generated by the database,
724
726
  # and retrieved by the +last_generated_id+ method.
725
727
  def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
728
+ if @handle_lobs_triggered #Ensure the array of sql is cleared if they have been handled in the callback
729
+ @sql = []
730
+ @handle_lobs_triggered = false
731
+ end
732
+
726
733
  if stmt = execute(sql, name)
727
734
  begin
728
735
  @sql << sql
@@ -746,11 +753,24 @@ module ActiveRecord
746
753
 
747
754
  # Executes an "UPDATE" SQL statement
748
755
  def update(sql, name = nil)
756
+ if @handle_lobs_triggered #Ensure the array of sql is cleared if they have been handled in the callback
757
+ @sql = []
758
+ @handle_lobs_triggered = false
759
+ end
760
+
749
761
  # Make sure the WHERE clause handles NULL's correctly
750
762
  sqlarray = sql.split(/\s*WHERE\s*/)
751
- if !sqlarray[1].nil?
752
- sqlarray[1].gsub!( /(=\s*NULL|IN\s*\(NULL\))/i, " IS NULL" )
753
- sql = sqlarray[0] + " WHERE " + sqlarray[1]
763
+ size = sqlarray.size
764
+ if size > 1
765
+ sql = sqlarray[0] + " WHERE "
766
+ if size > 2
767
+ 1.upto size-2 do |index|
768
+ sqlarray[index].gsub!( /(=\s*NULL|IN\s*\(NULL\))/i, " IS NULL" ) unless sqlarray[index].nil?
769
+ sql = sql + sqlarray[index] + " WHERE "
770
+ end
771
+ end
772
+ sqlarray[size-1].gsub!( /(=\s*NULL|IN\s*\(NULL\))/i, " IS NULL" ) unless sqlarray[size-1].nil?
773
+ sql = sql + sqlarray[size-1]
754
774
  end
755
775
 
756
776
  # Logs and execute the given sql query.
@@ -927,7 +947,7 @@ module ActiveRecord
927
947
  # database types
928
948
  def native_database_types
929
949
  {
930
- :primary_key => @servertype.primary_key,
950
+ :primary_key => { :name => @servertype.primary_key},
931
951
  :string => { :name => "varchar", :limit => 255 },
932
952
  :text => { :name => "clob" },
933
953
  :integer => { :name => "integer" },
@@ -1034,7 +1054,7 @@ module ActiveRecord
1034
1054
  while ( pk_index_row = IBM_DB.fetch_array(stmt) )
1035
1055
  if pk_index_row[5]
1036
1056
  pk_index_name = pk_index_row[5].downcase
1037
- pk_index_columns = pk_index_row[3].map{|c| c.downcase} # COLUMN_NAME
1057
+ pk_index_columns = [pk_index_row[3].downcase] # COLUMN_NAME
1038
1058
  if pk_index
1039
1059
  pk_index.columns = pk_index.columns + pk_index_columns
1040
1060
  else
@@ -1070,7 +1090,7 @@ module ActiveRecord
1070
1090
  if index_stats[5] # INDEX_NAME
1071
1091
  index_name = index_stats[5].downcase
1072
1092
  index_unique = (index_stats[3] == 0)
1073
- index_columns = index_stats[8].map{|c| c.downcase} # COLUMN_NAME
1093
+ index_columns = [index_stats[8].downcase] # COLUMN_NAME
1074
1094
  index_qualifier = index_stats[4].downcase #Index_Qualifier
1075
1095
  # Create an IndexDefinition object and add to the indexes array
1076
1096
  i = 0;
@@ -1228,6 +1248,7 @@ module ActiveRecord
1228
1248
  @servertype.change_column(table_name, column_name, type, options)
1229
1249
  end
1230
1250
 
1251
+ =begin
1231
1252
  #overrides the abstract adapter method to generate proper sql
1232
1253
  #specifying the column options, like default value and nullability clause
1233
1254
  def add_column_options!(sql,options={})
@@ -1251,6 +1272,7 @@ module ActiveRecord
1251
1272
  end
1252
1273
  end
1253
1274
  end
1275
+ =end
1254
1276
 
1255
1277
  # Sets a new default value for a column. This does not set the default
1256
1278
  # value to +NULL+, instead, it needs DatabaseStatements#execute which
@@ -1764,11 +1786,6 @@ SET WITH DEFAULT #{@adapter.quote(default)}"
1764
1786
 
1765
1787
  class IBM_DB2_ZOS_8 < IBM_DB2_ZOS
1766
1788
  include HostedDataServer
1767
- # Setting the SQLID on z/OS will also update the CURRENT SCHEMA
1768
- # special register, but not vice versa
1769
- def set_schema(schema)
1770
- execute("SET CURRENT SQLID ='#{schema.upcase}'")
1771
- end
1772
1789
 
1773
1790
  # This call is needed on DB2 z/OS v8 for the creation of tables
1774
1791
  # with LOBs. When issued, this call does the following:
@@ -106,6 +106,14 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase
106
106
  authors.first.posts.first.special_comments.first.post.very_special_comment
107
107
  end
108
108
  end
109
+
110
+ def test_eager_association_loading_where_first_level_returns_nil
111
+ authors = Author.find(:all, :include => {:post_about_thinking => :comments}, :order => 'authors.id DESC')
112
+ assert_equal [authors(:mary), authors(:david)], authors
113
+ assert_no_queries do
114
+ authors[1].post_about_thinking.comments.first
115
+ end
116
+ end
109
117
  end
110
118
 
111
119
  require 'models/vertex'
@@ -1,6 +1,7 @@
1
1
  require "cases/helper"
2
2
  require 'models/post'
3
3
  require 'models/tagging'
4
+ require 'models/tag'
4
5
  require 'models/comment'
5
6
  require 'models/author'
6
7
  require 'models/category'
@@ -145,7 +146,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
145
146
  def test_finding_with_includes_on_null_belongs_to_association_with_same_include_includes_only_once
146
147
  post = posts(:welcome)
147
148
  post.update_attributes!(:author => nil)
148
- post = assert_queries(2) { Post.find(post.id, :include => {:author_with_address => :author_address}) } # find the post, then find the author which is null so no query for the address
149
+ post = assert_queries(1) { Post.find(post.id, :include => {:author_with_address => :author_address}) } # find the post, then find the author which is null so no query for the author or address
149
150
  assert_no_queries do
150
151
  assert_equal nil, post.author_with_address
151
152
  end
@@ -387,12 +388,28 @@ class EagerAssociationTest < ActiveRecord::TestCase
387
388
  assert_equal count, posts.size
388
389
  end
389
390
 
390
- def test_eager_with_has_many_and_limit_ond_high_offset
391
+ def test_eager_with_has_many_and_limit_and_high_offset
391
392
  posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :offset => 10, :conditions => [ "authors.name = ?", 'David' ])
392
393
  assert_equal 0, posts.size
393
394
  end
394
395
 
395
- def test_count_eager_with_has_many_and_limit_ond_high_offset
396
+ def test_eager_with_has_many_and_limit_and_high_offset_and_multiple_array_conditions
397
+ assert_queries(1) do
398
+ posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :offset => 10,
399
+ :conditions => [ "authors.name = ? and comments.body = ?", 'David', 'go crazy' ])
400
+ assert_equal 0, posts.size
401
+ end
402
+ end
403
+
404
+ def test_eager_with_has_many_and_limit_and_high_offset_and_multiple_hash_conditions
405
+ assert_queries(1) do
406
+ posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :offset => 10,
407
+ :conditions => { 'authors.name' => 'David', 'comments.body' => 'go crazy' })
408
+ assert_equal 0, posts.size
409
+ end
410
+ end
411
+
412
+ def test_count_eager_with_has_many_and_limit_and_high_offset
396
413
  posts = Post.count(:all, :include => [ :author, :comments ], :limit => 2, :offset => 10, :conditions => [ "authors.name = ?", 'David' ])
397
414
  assert_equal 0, posts
398
415
  end
@@ -534,16 +551,16 @@ class EagerAssociationTest < ActiveRecord::TestCase
534
551
  end
535
552
 
536
553
  def test_eager_with_invalid_association_reference
537
- assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
554
+ assert_raise(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
538
555
  post = Post.find(6, :include=> :monkeys )
539
556
  }
540
- assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
557
+ assert_raise(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
541
558
  post = Post.find(6, :include=>[ :monkeys ])
542
559
  }
543
- assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
560
+ assert_raise(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
544
561
  post = Post.find(6, :include=>[ 'monkeys' ])
545
562
  }
546
- assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys, :elephants") {
563
+ assert_raise(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys, :elephants") {
547
564
  post = Post.find(6, :include=>[ :monkeys, :elephants ])
548
565
  }
549
566
  end
@@ -694,5 +711,120 @@ class EagerAssociationTest < ActiveRecord::TestCase
694
711
  def test_order_on_join_table_with_include_and_limit
695
712
  assert_equal 5, Developer.find(:all, :include => 'projects', :order => 'developers_projects.joined_on DESC', :limit => 5).size
696
713
  end
697
- end
714
+ end
715
+
716
+ def test_eager_loading_with_order_on_joined_table_preloads
717
+ posts = assert_queries(2) do
718
+ Post.find(:all, :joins => :comments, :include => :author, :order => 'comments.id DESC')
719
+ end
720
+ assert_equal posts(:eager_other), posts[0]
721
+ assert_equal authors(:mary), assert_no_queries { posts[0].author}
722
+ end
723
+
724
+ def test_eager_loading_with_conditions_on_joined_table_preloads
725
+ posts = assert_queries(2) do
726
+ Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => [:comments], :conditions => "comments.body like 'Thank you%'", :order => 'posts.id')
727
+ end
728
+ assert_equal [posts(:welcome)], posts
729
+ assert_equal authors(:david), assert_no_queries { posts[0].author}
730
+
731
+ posts = assert_queries(2) do
732
+ Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => [:comments], :conditions => "comments.body like 'Thank you%'", :order => 'posts.id')
733
+ end
734
+ assert_equal [posts(:welcome)], posts
735
+ assert_equal authors(:david), assert_no_queries { posts[0].author}
736
+
737
+ posts = assert_queries(2) do
738
+ Post.find(:all, :include => :author, :joins => {:taggings => :tag}, :conditions => "tags.name = 'General'", :order => 'posts.id')
739
+ end
740
+ assert_equal posts(:welcome, :thinking), posts
741
+
742
+ posts = assert_queries(2) do
743
+ Post.find(:all, :include => :author, :joins => {:taggings => {:tag => :taggings}}, :conditions => "taggings_tags.super_tag_id=2", :order => 'posts.id')
744
+ end
745
+ assert_equal posts(:welcome, :thinking), posts
746
+
747
+ end
748
+
749
+ def test_eager_loading_with_conditions_on_string_joined_table_preloads
750
+ posts = assert_queries(2) do
751
+ Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => "INNER JOIN comments on comments.post_id = posts.id", :conditions => "comments.body like 'Thank you%'", :order => 'posts.id')
752
+ end
753
+ assert_equal [posts(:welcome)], posts
754
+ assert_equal authors(:david), assert_no_queries { posts[0].author}
755
+
756
+ posts = assert_queries(2) do
757
+ Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => ["INNER JOIN comments on comments.post_id = posts.id"], :conditions => "comments.body like 'Thank you%'", :order => 'posts.id')
758
+ end
759
+ assert_equal [posts(:welcome)], posts
760
+ assert_equal authors(:david), assert_no_queries { posts[0].author}
761
+
762
+ end
763
+
764
+ def test_eager_loading_with_select_on_joined_table_preloads
765
+ posts = assert_queries(2) do
766
+ Post.find(:all, :select => 'posts.*, authors.name as author_name', :include => :comments, :joins => :author, :order => 'posts.id')
767
+ end
768
+ assert_equal 'David', posts[0].author_name
769
+ assert_equal posts(:welcome).comments, assert_no_queries { posts[0].comments}
770
+ end
771
+
772
+ def test_eager_loading_with_conditions_on_join_model_preloads
773
+ authors = assert_queries(2) do
774
+ Author.find(:all, :include => :author_address, :joins => :comments, :conditions => "posts.title like 'Welcome%'")
775
+ end
776
+ assert_equal authors(:david), authors[0]
777
+ assert_equal author_addresses(:david_address), authors[0].author_address
778
+ end
779
+
780
+ def test_preload_belongs_to_uses_exclusive_scope
781
+ people = Person.males.find(:all, :include => :primary_contact)
782
+ assert_not_equal people.length, 0
783
+ people.each do |person|
784
+ assert_no_queries {assert_not_nil person.primary_contact}
785
+ assert_equal Person.find(person.id).primary_contact, person.primary_contact
786
+ end
787
+ end
788
+
789
+ def test_preload_has_many_uses_exclusive_scope
790
+ people = Person.males.find :all, :include => :agents
791
+ people.each do |person|
792
+ assert_equal Person.find(person.id).agents, person.agents
793
+ end
794
+ end
795
+
796
+ def test_preload_has_many_using_primary_key
797
+ expected = Firm.find(:first).clients_using_primary_key.to_a
798
+ firm = Firm.find :first, :include => :clients_using_primary_key
799
+ assert_no_queries do
800
+ assert_equal expected, firm.clients_using_primary_key
801
+ end
802
+ end
803
+
804
+ def test_include_has_many_using_primary_key
805
+ expected = Firm.find(1).clients_using_primary_key.sort_by &:name
806
+ firm = Firm.find 1, :include => :clients_using_primary_key, :order => 'clients_using_primary_keys_companies.name'
807
+ assert_no_queries do
808
+ assert_equal expected, firm.clients_using_primary_key
809
+ end
810
+ end
811
+
812
+ def test_preload_has_one_using_primary_key
813
+ expected = Firm.find(:first).account_using_primary_key
814
+ firm = Firm.find :first, :include => :account_using_primary_key
815
+ assert_no_queries do
816
+ assert_equal expected, firm.account_using_primary_key
817
+ end
818
+ end
819
+
820
+ unless current_adapter?(:IBM_DBAdapter)
821
+ def test_include_has_one_using_primary_key
822
+ expected = Firm.find(1).account_using_primary_key
823
+ firm = Firm.find(:all, :include => :account_using_primary_key, :order => 'accounts.id').detect {|f| f.id == 1}
824
+ assert_no_queries do
825
+ assert_equal expected, firm.account_using_primary_key
826
+ end
827
+ end
828
+ end
829
+
698
830
  end
@@ -429,6 +429,33 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
429
429
  assert_date_from_db Date.new(2004, 10, 10), Developer.find(1).projects.first.joined_on.to_date
430
430
  end
431
431
 
432
+ def test_destroying
433
+ david = Developer.find(1)
434
+ active_record = Project.find(1)
435
+ david.projects.reload
436
+ assert_equal 2, david.projects.size
437
+ assert_equal 3, active_record.developers.size
438
+
439
+ assert_difference "Project.count", -1 do
440
+ david.projects.destroy(active_record)
441
+ end
442
+
443
+ assert_equal 1, david.reload.projects.size
444
+ assert_equal 1, david.projects(true).size
445
+ end
446
+
447
+ def test_destroying_array
448
+ david = Developer.find(1)
449
+ david.projects.reload
450
+
451
+ assert_difference "Project.count", -Project.count do
452
+ david.projects.destroy(Project.find(:all))
453
+ end
454
+
455
+ assert_equal 0, david.reload.projects.size
456
+ assert_equal 0, david.projects(true).size
457
+ end
458
+
432
459
  def test_destroy_all
433
460
  david = Developer.find(1)
434
461
  david.projects.reload
@@ -664,7 +691,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
664
691
  def test_updating_attributes_on_rich_associations
665
692
  david = projects(:action_controller).developers.first
666
693
  david.name = "DHH"
667
- assert_raises(ActiveRecord::ReadOnlyRecord) { david.save! }
694
+ assert_raise(ActiveRecord::ReadOnlyRecord) { david.save! }
668
695
  end
669
696
 
670
697
  def test_updating_attributes_on_rich_associations_with_limited_find_from_reflection
@@ -706,6 +733,11 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
706
733
  assert_equal 1, categories(:technology).posts_gruoped_by_title.size
707
734
  end
708
735
 
736
+ def test_find_scoped_grouped_having
737
+ assert_equal 2, projects(:active_record).well_payed_salary_groups.size
738
+ assert projects(:active_record).well_payed_salary_groups.all? { |g| g.salary > 10000 }
739
+ end
740
+
709
741
  def test_get_ids
710
742
  assert_equal projects(:active_record, :action_controller).map(&:id).sort, developers(:david).project_ids.sort
711
743
  assert_equal [projects(:active_record).id], developers(:jamis).project_ids
@@ -785,41 +817,58 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
785
817
  assert_equal developer, project.developers.find(:first)
786
818
  assert_equal project, developer.projects.find(:first)
787
819
  end
820
+
821
+ def test_self_referential_habtm_without_foreign_key_set_should_raise_exception
822
+ assert_raise(ActiveRecord::HasAndBelongsToManyAssociationForeignKeyNeeded) {
823
+ Member.class_eval do
824
+ has_and_belongs_to_many :friends, :class_name => "Member", :join_table => "member_friends"
825
+ end
826
+ }
827
+ end
788
828
 
789
- unless current_adapter?(:IBM_DBAdapter)#refer SQL0214N
829
+ unless current_adapter?(:IBM_DBAdapter) #refer SQL214n
790
830
  def test_dynamic_find_should_respect_association_include
791
831
  # SQL error in sort clause if :include is not included
792
832
  # due to Unknown column 'authors.id'
793
833
  assert Category.find(1).posts_with_authors_sorted_by_author_id.find_by_title('Welcome to the weblog')
794
834
  end
795
-
796
- def test_counting_on_habtm_association_and_not_array
797
- david = Developer.find(1)
798
- # Extra parameter just to make sure we aren't falling back to
799
- # Array#count in Ruby >=1.8.7, which would raise an ArgumentError
800
- assert_nothing_raised { david.projects.count(:all, :conditions => '1=1') }
801
- end
835
+ end
802
836
 
803
- def test_count
804
- david = Developer.find(1)
805
- assert_equal 2, david.projects.count
806
- end
837
+ def test_counting_on_habtm_association_and_not_array
838
+ david = Developer.find(1)
839
+ # Extra parameter just to make sure we aren't falling back to
840
+ # Array#count in Ruby >=1.8.7, which would raise an ArgumentError
841
+ assert_nothing_raised { david.projects.count(:all, :conditions => '1=1') }
842
+ end
843
+
844
+ def test_count
845
+ david = Developer.find(1)
846
+ assert_equal 2, david.projects.count
847
+ end
807
848
 
808
- def test_count_with_counter_sql
809
- developer = DeveloperWithCounterSQL.create(:name => 'tekin')
810
- developer.project_ids = [projects(:active_record).id]
811
- developer.save
812
- developer.reload
813
- assert_equal 1, developer.projects.count
849
+ def test_count_with_counter_sql
850
+ developer = DeveloperWithCounterSQL.create(:name => 'tekin')
851
+ developer.project_ids = [projects(:active_record).id]
852
+ developer.save
853
+ developer.reload
854
+ assert_equal 1, developer.projects.count
855
+ end
856
+
857
+ def test_association_proxy_transaction_method_starts_transaction_in_association_class
858
+ Post.expects(:transaction)
859
+ Category.find(:first).posts.transaction do
860
+ # nothing
814
861
  end
862
+ end
815
863
 
816
- uses_mocha 'mocking Post.transaction' do
817
- def test_association_proxy_transaction_method_starts_transaction_in_association_class
818
- Post.expects(:transaction)
819
- Category.find(:first).posts.transaction do
820
- # nothing
821
- end
822
- end
823
- end
864
+ def test_caching_of_columns
865
+ david = Developer.find(1)
866
+ # clear cache possibly created by other tests
867
+ david.projects.reset_column_information
868
+ assert_queries(0) { david.projects.columns; david.projects.columns }
869
+ # and again to verify that reset_column_information clears the cache correctly
870
+ david.projects.reset_column_information
871
+ assert_queries(0) { david.projects.columns; david.projects.columns }
824
872
  end
825
- end
873
+
874
+ end