ibm_db 1.0.2 → 1.0.5

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.
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