ibm_db 2.5.26-universal-darwin-14
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.
- checksums.yaml +7 -0
- data/CHANGES +233 -0
- data/LICENSE +18 -0
- data/MANIFEST +14 -0
- data/ParameterizedQueries README +39 -0
- data/README +225 -0
- data/ext/Makefile.nt32 +181 -0
- data/ext/Makefile.nt32.191 +212 -0
- data/ext/extconf.rb +261 -0
- data/ext/ibm_db.c +11793 -0
- data/ext/ruby_ibm_db.h +240 -0
- data/ext/ruby_ibm_db_cli.c +845 -0
- data/ext/ruby_ibm_db_cli.h +489 -0
- data/init.rb +42 -0
- data/lib/IBM_DB.rb +19 -0
- data/lib/active_record/connection_adapters/ibm_db_adapter.rb +3289 -0
- data/lib/active_record/connection_adapters/ibm_db_pstmt.rb +1965 -0
- data/lib/active_record/connection_adapters/ibmdb_adapter.rb +2 -0
- data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -0
- data/lib/linux/rb18x/ibm_db.bundle +0 -0
- data/lib/linux/rb19x/ibm_db.bundle +0 -0
- data/lib/linux/rb20x/ibm_db.bundle +0 -0
- data/lib/linux/rb21x/ibm_db.bundle +0 -0
- data/test/cases/adapter_test.rb +207 -0
- data/test/cases/associations/belongs_to_associations_test.rb +711 -0
- data/test/cases/associations/cascaded_eager_loading_test.rb +181 -0
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +851 -0
- data/test/cases/associations/join_model_test.rb +743 -0
- data/test/cases/attribute_methods_test.rb +822 -0
- data/test/cases/base_test.rb +2133 -0
- data/test/cases/calculations_test.rb +482 -0
- data/test/cases/migration_test.rb +2408 -0
- data/test/cases/persistence_test.rb +642 -0
- data/test/cases/query_cache_test.rb +257 -0
- data/test/cases/relations_test.rb +1182 -0
- data/test/cases/schema_dumper_test.rb +256 -0
- data/test/cases/transaction_callbacks_test.rb +300 -0
- data/test/cases/validations/uniqueness_validation_test.rb +299 -0
- data/test/cases/xml_serialization_test.rb +408 -0
- data/test/config.yml +154 -0
- data/test/connections/native_ibm_db/connection.rb +44 -0
- data/test/ibm_db_test.rb +25 -0
- data/test/models/warehouse_thing.rb +5 -0
- data/test/schema/i5/ibm_db_specific_schema.rb +137 -0
- data/test/schema/ids/ibm_db_specific_schema.rb +140 -0
- data/test/schema/luw/ibm_db_specific_schema.rb +137 -0
- data/test/schema/schema.rb +751 -0
- data/test/schema/zOS/ibm_db_specific_schema.rb +208 -0
- metadata +114 -0
| @@ -0,0 +1,256 @@ | |
| 1 | 
            +
            require "cases/helper"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
             | 
| 4 | 
            +
            class SchemaDumperTest < ActiveRecord::TestCase
         | 
| 5 | 
            +
              def setup
         | 
| 6 | 
            +
                @stream = StringIO.new
         | 
| 7 | 
            +
              end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              def standard_dump
         | 
| 10 | 
            +
                @stream = StringIO.new
         | 
| 11 | 
            +
                ActiveRecord::SchemaDumper.ignore_tables = []
         | 
| 12 | 
            +
                ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, @stream)
         | 
| 13 | 
            +
                @stream.string
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              if "string".encoding_aware?
         | 
| 17 | 
            +
                def test_magic_comment
         | 
| 18 | 
            +
                  assert_match "# encoding: #{@stream.external_encoding.name}", standard_dump
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              def test_schema_dump
         | 
| 23 | 
            +
                output = standard_dump
         | 
| 24 | 
            +
                assert_match %r{create_table "accounts"}, output
         | 
| 25 | 
            +
                assert_match %r{create_table "authors"}, output
         | 
| 26 | 
            +
                assert_no_match %r{create_table "schema_migrations"}, output
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              def test_schema_dump_excludes_sqlite_sequence
         | 
| 30 | 
            +
                output = standard_dump
         | 
| 31 | 
            +
                assert_no_match %r{create_table "sqlite_sequence"}, output
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              def test_schema_dump_includes_camelcase_table_name
         | 
| 35 | 
            +
                output = standard_dump
         | 
| 36 | 
            +
                if current_adapter?(:IBM_DBAdapter)
         | 
| 37 | 
            +
                  #DB2 is case insensitive
         | 
| 38 | 
            +
                  assert_match %r{create_table "camelcase"}, output
         | 
| 39 | 
            +
                else
         | 
| 40 | 
            +
                  assert_match %r{create_table "CamelCase"}, output
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
              def assert_line_up(lines, pattern, required = false)
         | 
| 45 | 
            +
                return assert(true) if lines.empty?
         | 
| 46 | 
            +
                matches = lines.map { |line| line.match(pattern) }
         | 
| 47 | 
            +
                assert matches.all? if required
         | 
| 48 | 
            +
                matches.compact!
         | 
| 49 | 
            +
                return assert(true) if matches.empty?
         | 
| 50 | 
            +
                assert_equal 1, matches.map{ |match| match.offset(0).first }.uniq.length
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              def column_definition_lines(output = standard_dump)
         | 
| 54 | 
            +
                output.scan(/^( *)create_table.*?\n(.*?)^\1end/m).map{ |m| m.last.split(/\n/) }
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
              def test_types_line_up
         | 
| 58 | 
            +
                column_definition_lines.each do |column_set|
         | 
| 59 | 
            +
                  next if column_set.empty?
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  lengths = column_set.map do |column|
         | 
| 62 | 
            +
                    if match = column.match(/t\.(?:integer|decimal|float|datetime|timestamp|time|date|text|binary|string|boolean)\s+"/)
         | 
| 63 | 
            +
                      match[0].length
         | 
| 64 | 
            +
                    end
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                  assert_equal 1, lengths.uniq.length
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
              end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
              def test_arguments_line_up
         | 
| 72 | 
            +
                column_definition_lines.each do |column_set|
         | 
| 73 | 
            +
                  assert_line_up(column_set, /:default => /)
         | 
| 74 | 
            +
                  assert_line_up(column_set, /:limit => /)
         | 
| 75 | 
            +
                  assert_line_up(column_set, /:null => /)
         | 
| 76 | 
            +
                end
         | 
| 77 | 
            +
              end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
              def test_no_dump_errors
         | 
| 80 | 
            +
                output = standard_dump
         | 
| 81 | 
            +
                assert_no_match %r{\# Could not dump table}, output
         | 
| 82 | 
            +
              end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
              def test_schema_dump_includes_not_null_columns
         | 
| 85 | 
            +
                stream = StringIO.new
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                ActiveRecord::SchemaDumper.ignore_tables = [/^[^r]/]
         | 
| 88 | 
            +
                ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
         | 
| 89 | 
            +
                output = stream.string
         | 
| 90 | 
            +
                assert_match %r{:null => false}, output
         | 
| 91 | 
            +
              end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
              def test_schema_dump_includes_limit_constraint_for_integer_columns
         | 
| 94 | 
            +
                stream = StringIO.new
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                ActiveRecord::SchemaDumper.ignore_tables = [/^(?!integer_limits)/]
         | 
| 97 | 
            +
                ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
         | 
| 98 | 
            +
                output = stream.string
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                if current_adapter?(:PostgreSQLAdapter)
         | 
| 101 | 
            +
                  assert_match %r{c_int_1.*:limit => 2}, output
         | 
| 102 | 
            +
                  assert_match %r{c_int_2.*:limit => 2}, output
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                  # int 3 is 4 bytes in postgresql
         | 
| 105 | 
            +
                  assert_match %r{c_int_3.*}, output
         | 
| 106 | 
            +
                  assert_no_match %r{c_int_3.*:limit}, output
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                  assert_match %r{c_int_4.*}, output
         | 
| 109 | 
            +
                  assert_no_match %r{c_int_4.*:limit}, output
         | 
| 110 | 
            +
                elsif current_adapter?(:MysqlAdapter) or current_adapter?(:Mysql2Adapter)
         | 
| 111 | 
            +
                  assert_match %r{c_int_1.*:limit => 1}, output
         | 
| 112 | 
            +
                  assert_match %r{c_int_2.*:limit => 2}, output
         | 
| 113 | 
            +
                  assert_match %r{c_int_3.*:limit => 3}, output
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                  assert_match %r{c_int_4.*}, output
         | 
| 116 | 
            +
                  assert_no_match %r{c_int_4.*:limit}, output
         | 
| 117 | 
            +
                elsif current_adapter?(:SQLite3Adapter)
         | 
| 118 | 
            +
                  assert_match %r{c_int_1.*:limit => 1}, output
         | 
| 119 | 
            +
                  assert_match %r{c_int_2.*:limit => 2}, output
         | 
| 120 | 
            +
                  assert_match %r{c_int_3.*:limit => 3}, output
         | 
| 121 | 
            +
                  assert_match %r{c_int_4.*:limit => 4}, output
         | 
| 122 | 
            +
                end
         | 
| 123 | 
            +
                assert_match %r{c_int_without_limit.*}, output
         | 
| 124 | 
            +
                assert_no_match %r{c_int_without_limit.*:limit}, output
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                if current_adapter?(:SQLite3Adapter)
         | 
| 127 | 
            +
                  assert_match %r{c_int_5.*:limit => 5}, output
         | 
| 128 | 
            +
                  assert_match %r{c_int_6.*:limit => 6}, output
         | 
| 129 | 
            +
                  assert_match %r{c_int_7.*:limit => 7}, output
         | 
| 130 | 
            +
                  assert_match %r{c_int_8.*:limit => 8}, output
         | 
| 131 | 
            +
                elsif current_adapter?(:OracleAdapter)
         | 
| 132 | 
            +
                  assert_match %r{c_int_5.*:limit => 5}, output
         | 
| 133 | 
            +
                  assert_match %r{c_int_6.*:limit => 6}, output
         | 
| 134 | 
            +
                  assert_match %r{c_int_7.*:limit => 7}, output
         | 
| 135 | 
            +
                  assert_match %r{c_int_8.*:limit => 8}, output
         | 
| 136 | 
            +
                elsif current_adapter?(:IBM_DBAdapter)
         | 
| 137 | 
            +
                  #Limits is not supported on integer column by DB2
         | 
| 138 | 
            +
                else
         | 
| 139 | 
            +
                  assert_match %r{c_int_5.*:limit => 8}, output
         | 
| 140 | 
            +
                  assert_match %r{c_int_6.*:limit => 8}, output
         | 
| 141 | 
            +
                  assert_match %r{c_int_7.*:limit => 8}, output
         | 
| 142 | 
            +
                  assert_match %r{c_int_8.*:limit => 8}, output
         | 
| 143 | 
            +
                end
         | 
| 144 | 
            +
              end
         | 
| 145 | 
            +
             | 
| 146 | 
            +
              def test_schema_dump_with_string_ignored_table
         | 
| 147 | 
            +
                stream = StringIO.new
         | 
| 148 | 
            +
             | 
| 149 | 
            +
                ActiveRecord::SchemaDumper.ignore_tables = ['accounts']
         | 
| 150 | 
            +
                ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
         | 
| 151 | 
            +
                output = stream.string
         | 
| 152 | 
            +
                assert_no_match %r{create_table "accounts"}, output
         | 
| 153 | 
            +
                assert_match %r{create_table "authors"}, output
         | 
| 154 | 
            +
                assert_no_match %r{create_table "schema_migrations"}, output
         | 
| 155 | 
            +
              end
         | 
| 156 | 
            +
             | 
| 157 | 
            +
              def test_schema_dump_with_regexp_ignored_table
         | 
| 158 | 
            +
                stream = StringIO.new
         | 
| 159 | 
            +
             | 
| 160 | 
            +
                ActiveRecord::SchemaDumper.ignore_tables = [/^account/]
         | 
| 161 | 
            +
                ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
         | 
| 162 | 
            +
                output = stream.string
         | 
| 163 | 
            +
                assert_no_match %r{create_table "accounts"}, output
         | 
| 164 | 
            +
                assert_match %r{create_table "authors"}, output
         | 
| 165 | 
            +
                assert_no_match %r{create_table "schema_migrations"}, output
         | 
| 166 | 
            +
              end
         | 
| 167 | 
            +
             | 
| 168 | 
            +
              def test_schema_dump_illegal_ignored_table_value
         | 
| 169 | 
            +
                stream = StringIO.new
         | 
| 170 | 
            +
                ActiveRecord::SchemaDumper.ignore_tables = [5]
         | 
| 171 | 
            +
                assert_raise(StandardError) do
         | 
| 172 | 
            +
                  ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
         | 
| 173 | 
            +
                end
         | 
| 174 | 
            +
              end
         | 
| 175 | 
            +
             | 
| 176 | 
            +
              def test_schema_dumps_index_columns_in_right_order
         | 
| 177 | 
            +
                index_definition = standard_dump.split(/\n/).grep(/add_index.*companies/).first.strip
         | 
| 178 | 
            +
                assert_equal 'add_index "companies", ["firm_id", "type", "rating", "ruby_type"], :name => "company_index"', index_definition
         | 
| 179 | 
            +
              end
         | 
| 180 | 
            +
             | 
| 181 | 
            +
              def test_schema_dump_should_honor_nonstandard_primary_keys
         | 
| 182 | 
            +
                output = standard_dump
         | 
| 183 | 
            +
                match = output.match(%r{create_table "movies"(.*)do})
         | 
| 184 | 
            +
                assert_not_nil(match, "nonstandardpk table not found")
         | 
| 185 | 
            +
                assert_match %r(:primary_key => "movieid"), match[1], "non-standard primary key not preserved"
         | 
| 186 | 
            +
              end
         | 
| 187 | 
            +
             | 
| 188 | 
            +
              if current_adapter?(:MysqlAdapter) or current_adapter?(:Mysql2Adapter)
         | 
| 189 | 
            +
                def test_schema_dump_should_not_add_default_value_for_mysql_text_field
         | 
| 190 | 
            +
                  output = standard_dump
         | 
| 191 | 
            +
                  assert_match %r{t.text\s+"body",\s+:null => false$}, output
         | 
| 192 | 
            +
                end
         | 
| 193 | 
            +
             | 
| 194 | 
            +
                def test_schema_dump_includes_length_for_mysql_blob_and_text_fields
         | 
| 195 | 
            +
                  output = standard_dump
         | 
| 196 | 
            +
                  assert_match %r{t.binary\s+"tiny_blob",\s+:limit => 255$}, output
         | 
| 197 | 
            +
                  assert_match %r{t.binary\s+"normal_blob"$}, output
         | 
| 198 | 
            +
                  assert_match %r{t.binary\s+"medium_blob",\s+:limit => 16777215$}, output
         | 
| 199 | 
            +
                  assert_match %r{t.binary\s+"long_blob",\s+:limit => 2147483647$}, output
         | 
| 200 | 
            +
                  assert_match %r{t.text\s+"tiny_text",\s+:limit => 255$}, output
         | 
| 201 | 
            +
                  assert_match %r{t.text\s+"normal_text"$}, output
         | 
| 202 | 
            +
                  assert_match %r{t.text\s+"medium_text",\s+:limit => 16777215$}, output
         | 
| 203 | 
            +
                  assert_match %r{t.text\s+"long_text",\s+:limit => 2147483647$}, output
         | 
| 204 | 
            +
                end
         | 
| 205 | 
            +
              end
         | 
| 206 | 
            +
             | 
| 207 | 
            +
              def test_schema_dump_includes_decimal_options
         | 
| 208 | 
            +
                stream = StringIO.new
         | 
| 209 | 
            +
                ActiveRecord::SchemaDumper.ignore_tables = [/^[^n]/]
         | 
| 210 | 
            +
                ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
         | 
| 211 | 
            +
                output = stream.string
         | 
| 212 | 
            +
                assert_match %r{:precision => 3,[[:space:]]+:scale => 2,[[:space:]]+:default => 2.78}, output
         | 
| 213 | 
            +
              end
         | 
| 214 | 
            +
             | 
| 215 | 
            +
              if current_adapter?(:PostgreSQLAdapter)
         | 
| 216 | 
            +
                def test_schema_dump_includes_xml_shorthand_definition
         | 
| 217 | 
            +
                  output = standard_dump
         | 
| 218 | 
            +
                  if %r{create_table "postgresql_xml_data_type"} =~ output
         | 
| 219 | 
            +
                    assert_match %r{t.xml "data"}, output
         | 
| 220 | 
            +
                  end
         | 
| 221 | 
            +
                end
         | 
| 222 | 
            +
             | 
| 223 | 
            +
                def test_schema_dump_includes_tsvector_shorthand_definition
         | 
| 224 | 
            +
                  output = standard_dump
         | 
| 225 | 
            +
                  if %r{create_table "postgresql_tsvectors"} =~ output
         | 
| 226 | 
            +
                    assert_match %r{t.tsvector "text_vector"}, output
         | 
| 227 | 
            +
                  end
         | 
| 228 | 
            +
                end
         | 
| 229 | 
            +
              end
         | 
| 230 | 
            +
             | 
| 231 | 
            +
              def test_schema_dump_keeps_large_precision_integer_columns_as_decimal
         | 
| 232 | 
            +
                output = standard_dump
         | 
| 233 | 
            +
                # Oracle supports precision up to 38 and it identifies decimals with scale 0 as integers
         | 
| 234 | 
            +
                if current_adapter?(:OracleAdapter)
         | 
| 235 | 
            +
                  assert_match %r{t.integer\s+"atoms_in_universe",\s+:precision => 38,\s+:scale => 0}, output
         | 
| 236 | 
            +
                elsif current_adapter?(:IBM_DBAdapter)
         | 
| 237 | 
            +
                  # DB2 supports precision up to 31
         | 
| 238 | 
            +
                  assert_match %r{t.decimal\s+"atoms_in_universe",\s+:precision => 31,\s+:scale => 0}, output
         | 
| 239 | 
            +
                else
         | 
| 240 | 
            +
                  assert_match %r{t.decimal\s+"atoms_in_universe",\s+:precision => 55,\s+:scale => 0}, output
         | 
| 241 | 
            +
                end
         | 
| 242 | 
            +
              end
         | 
| 243 | 
            +
             | 
| 244 | 
            +
              def test_schema_dump_keeps_id_column_when_id_is_false_and_id_column_added
         | 
| 245 | 
            +
                output = standard_dump
         | 
| 246 | 
            +
                match = output.match(%r{create_table "goofy_string_id"(.*)do.*\n(.*)\n})
         | 
| 247 | 
            +
                assert_not_nil(match, "goofy_string_id table not found")
         | 
| 248 | 
            +
                assert_match %r(:id => false), match[1], "no table id not preserved"
         | 
| 249 | 
            +
                assert_match %r{t.string[[:space:]]+"id",[[:space:]]+:null => false$}, match[2], "non-primary key id column not preserved"
         | 
| 250 | 
            +
              end
         | 
| 251 | 
            +
             | 
| 252 | 
            +
              def test_schema_dump_keeps_id_false_when_id_is_false_and_unique_not_null_column_added
         | 
| 253 | 
            +
                output = standard_dump
         | 
| 254 | 
            +
                assert_match %r{create_table "subscribers", :id => false}, output
         | 
| 255 | 
            +
              end
         | 
| 256 | 
            +
            end
         | 
| @@ -0,0 +1,300 @@ | |
| 1 | 
            +
            require "cases/helper"
         | 
| 2 | 
            +
            require 'models/topic'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            class TransactionCallbacksTest < ActiveRecord::TestCase
         | 
| 5 | 
            +
              self.use_transactional_fixtures = false
         | 
| 6 | 
            +
              fixtures :topics
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              class TopicWithCallbacks < ActiveRecord::Base
         | 
| 9 | 
            +
                self.table_name = :topics
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                after_commit{|record| record.send(:do_after_commit, nil)}
         | 
| 12 | 
            +
                after_commit(:on => :create){|record| record.send(:do_after_commit, :create)}
         | 
| 13 | 
            +
                after_commit(:on => :update){|record| record.send(:do_after_commit, :update)}
         | 
| 14 | 
            +
                after_commit(:on => :destroy){|record| record.send(:do_after_commit, :destroy)}
         | 
| 15 | 
            +
                after_rollback{|record| record.send(:do_after_rollback, nil)}
         | 
| 16 | 
            +
                after_rollback(:on => :create){|record| record.send(:do_after_rollback, :create)}
         | 
| 17 | 
            +
                after_rollback(:on => :update){|record| record.send(:do_after_rollback, :update)}
         | 
| 18 | 
            +
                after_rollback(:on => :destroy){|record| record.send(:do_after_rollback, :destroy)}
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def history
         | 
| 21 | 
            +
                  @history ||= []
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def after_commit_block(on = nil, &block)
         | 
| 25 | 
            +
                  @after_commit ||= {}
         | 
| 26 | 
            +
                  @after_commit[on] ||= []
         | 
| 27 | 
            +
                  @after_commit[on] << block
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                def after_rollback_block(on = nil, &block)
         | 
| 31 | 
            +
                  @after_rollback ||= {}
         | 
| 32 | 
            +
                  @after_rollback[on] ||= []
         | 
| 33 | 
            +
                  @after_rollback[on] << block
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                def do_after_commit(on)
         | 
| 37 | 
            +
                  blocks = @after_commit[on] if defined?(@after_commit)
         | 
| 38 | 
            +
                  blocks.each{|b| b.call(self)} if blocks
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                def do_after_rollback(on)
         | 
| 42 | 
            +
                  blocks = @after_rollback[on] if defined?(@after_rollback)
         | 
| 43 | 
            +
                  blocks.each{|b| b.call(self)} if blocks
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
              def setup
         | 
| 48 | 
            +
                @first, @second = TopicWithCallbacks.find(1, 3).sort_by { |t| t.id }
         | 
| 49 | 
            +
              end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
              def test_call_after_commit_after_transaction_commits
         | 
| 52 | 
            +
                @first.after_commit_block{|r| r.history << :after_commit}
         | 
| 53 | 
            +
                @first.after_rollback_block{|r| r.history << :after_rollback}
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                @first.save!
         | 
| 56 | 
            +
                assert_equal [:after_commit], @first.history
         | 
| 57 | 
            +
              end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
              def test_only_call_after_commit_on_update_after_transaction_commits_for_existing_record
         | 
| 60 | 
            +
                @first.after_commit_block(:create){|r| r.history << :commit_on_create}
         | 
| 61 | 
            +
                @first.after_commit_block(:update){|r| r.history << :commit_on_update}
         | 
| 62 | 
            +
                @first.after_commit_block(:destroy){|r| r.history << :commit_on_destroy}
         | 
| 63 | 
            +
                @first.after_rollback_block(:create){|r| r.history << :rollback_on_create}
         | 
| 64 | 
            +
                @first.after_rollback_block(:update){|r| r.history << :rollback_on_update}
         | 
| 65 | 
            +
                @first.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy}
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                @first.save!
         | 
| 68 | 
            +
                assert_equal [:commit_on_update], @first.history
         | 
| 69 | 
            +
              end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
              def test_only_call_after_commit_on_destroy_after_transaction_commits_for_destroyed_record
         | 
| 72 | 
            +
                @first.after_commit_block(:create){|r| r.history << :commit_on_create}
         | 
| 73 | 
            +
                @first.after_commit_block(:update){|r| r.history << :commit_on_update}
         | 
| 74 | 
            +
                @first.after_commit_block(:destroy){|r| r.history << :commit_on_destroy}
         | 
| 75 | 
            +
                @first.after_rollback_block(:create){|r| r.history << :rollback_on_create}
         | 
| 76 | 
            +
                @first.after_rollback_block(:update){|r| r.history << :rollback_on_update}
         | 
| 77 | 
            +
                @first.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy}
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                @first.destroy
         | 
| 80 | 
            +
                assert_equal [:commit_on_destroy], @first.history
         | 
| 81 | 
            +
              end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
              def test_only_call_after_commit_on_create_after_transaction_commits_for_new_record
         | 
| 84 | 
            +
                unless current_adapter?(:IBM_DBAdapter)
         | 
| 85 | 
            +
                  @new_record = TopicWithCallbacks.new(:title => "New topic", :written_on => Date.today)
         | 
| 86 | 
            +
                else
         | 
| 87 | 
            +
                  @new_record = TopicWithCallbacks.new(:title => "New topic", :written_on => Time.now)
         | 
| 88 | 
            +
                end
         | 
| 89 | 
            +
                @new_record.after_commit_block(:create){|r| r.history << :commit_on_create}
         | 
| 90 | 
            +
                @new_record.after_commit_block(:update){|r| r.history << :commit_on_update}
         | 
| 91 | 
            +
                @new_record.after_commit_block(:destroy){|r| r.history << :commit_on_destroy}
         | 
| 92 | 
            +
                @new_record.after_rollback_block(:create){|r| r.history << :rollback_on_create}
         | 
| 93 | 
            +
                @new_record.after_rollback_block(:update){|r| r.history << :rollback_on_update}
         | 
| 94 | 
            +
                @new_record.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy}
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                @new_record.save!
         | 
| 97 | 
            +
                assert_equal [:commit_on_create], @new_record.history
         | 
| 98 | 
            +
              end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
              def test_call_after_rollback_after_transaction_rollsback
         | 
| 101 | 
            +
                @first.after_commit_block{|r| r.history << :after_commit}
         | 
| 102 | 
            +
                @first.after_rollback_block{|r| r.history << :after_rollback}
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                Topic.transaction do
         | 
| 105 | 
            +
                  @first.save!
         | 
| 106 | 
            +
                  raise ActiveRecord::Rollback
         | 
| 107 | 
            +
                end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                assert_equal [:after_rollback], @first.history
         | 
| 110 | 
            +
              end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
              def test_only_call_after_rollback_on_update_after_transaction_rollsback_for_existing_record
         | 
| 113 | 
            +
                @first.after_commit_block(:create){|r| r.history << :commit_on_create}
         | 
| 114 | 
            +
                @first.after_commit_block(:update){|r| r.history << :commit_on_update}
         | 
| 115 | 
            +
                @first.after_commit_block(:destroy){|r| r.history << :commit_on_destroy}
         | 
| 116 | 
            +
                @first.after_rollback_block(:create){|r| r.history << :rollback_on_create}
         | 
| 117 | 
            +
                @first.after_rollback_block(:update){|r| r.history << :rollback_on_update}
         | 
| 118 | 
            +
                @first.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy}
         | 
| 119 | 
            +
             | 
| 120 | 
            +
                Topic.transaction do
         | 
| 121 | 
            +
                  @first.save!
         | 
| 122 | 
            +
                  raise ActiveRecord::Rollback
         | 
| 123 | 
            +
                end
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                assert_equal [:rollback_on_update], @first.history
         | 
| 126 | 
            +
              end
         | 
| 127 | 
            +
             | 
| 128 | 
            +
              def test_only_call_after_rollback_on_destroy_after_transaction_rollsback_for_destroyed_record
         | 
| 129 | 
            +
                @first.after_commit_block(:create){|r| r.history << :commit_on_create}
         | 
| 130 | 
            +
                @first.after_commit_block(:update){|r| r.history << :commit_on_update}
         | 
| 131 | 
            +
                @first.after_commit_block(:destroy){|r| r.history << :commit_on_update}
         | 
| 132 | 
            +
                @first.after_rollback_block(:create){|r| r.history << :rollback_on_create}
         | 
| 133 | 
            +
                @first.after_rollback_block(:update){|r| r.history << :rollback_on_update}
         | 
| 134 | 
            +
                @first.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy}
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                Topic.transaction do
         | 
| 137 | 
            +
                  @first.destroy
         | 
| 138 | 
            +
                  raise ActiveRecord::Rollback
         | 
| 139 | 
            +
                end
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                assert_equal [:rollback_on_destroy], @first.history
         | 
| 142 | 
            +
              end
         | 
| 143 | 
            +
             | 
| 144 | 
            +
              def test_only_call_after_rollback_on_create_after_transaction_rollsback_for_new_record
         | 
| 145 | 
            +
                unless current_adapter?(:IBM_DBAdapter)
         | 
| 146 | 
            +
                  @new_record = TopicWithCallbacks.new(:title => "New topic", :written_on => Date.today)
         | 
| 147 | 
            +
                else
         | 
| 148 | 
            +
                  @new_record = TopicWithCallbacks.new(:title => "New topic", :written_on => Time.now)
         | 
| 149 | 
            +
                end
         | 
| 150 | 
            +
                @new_record.after_commit_block(:create){|r| r.history << :commit_on_create}
         | 
| 151 | 
            +
                @new_record.after_commit_block(:update){|r| r.history << :commit_on_update}
         | 
| 152 | 
            +
                @new_record.after_commit_block(:destroy){|r| r.history << :commit_on_destroy}
         | 
| 153 | 
            +
                @new_record.after_rollback_block(:create){|r| r.history << :rollback_on_create}
         | 
| 154 | 
            +
                @new_record.after_rollback_block(:update){|r| r.history << :rollback_on_update}
         | 
| 155 | 
            +
                @new_record.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy}
         | 
| 156 | 
            +
             | 
| 157 | 
            +
                Topic.transaction do
         | 
| 158 | 
            +
                  @new_record.save!
         | 
| 159 | 
            +
                  raise ActiveRecord::Rollback
         | 
| 160 | 
            +
                end
         | 
| 161 | 
            +
             | 
| 162 | 
            +
                assert_equal [:rollback_on_create], @new_record.history
         | 
| 163 | 
            +
              end
         | 
| 164 | 
            +
             | 
| 165 | 
            +
              def test_call_after_rollback_when_commit_fails
         | 
| 166 | 
            +
                @first.connection.class.send(:alias_method, :real_method_commit_db_transaction, :commit_db_transaction)
         | 
| 167 | 
            +
                begin
         | 
| 168 | 
            +
                  @first.connection.class.class_eval do
         | 
| 169 | 
            +
                    def commit_db_transaction; raise "boom!"; end
         | 
| 170 | 
            +
                  end
         | 
| 171 | 
            +
             | 
| 172 | 
            +
                  @first.after_commit_block{|r| r.history << :after_commit}
         | 
| 173 | 
            +
                  @first.after_rollback_block{|r| r.history << :after_rollback}
         | 
| 174 | 
            +
             | 
| 175 | 
            +
                  assert !@first.save rescue nil
         | 
| 176 | 
            +
                  assert_equal [:after_rollback], @first.history
         | 
| 177 | 
            +
                ensure
         | 
| 178 | 
            +
                  @first.connection.class.send(:remove_method, :commit_db_transaction)
         | 
| 179 | 
            +
                  @first.connection.class.send(:alias_method, :commit_db_transaction, :real_method_commit_db_transaction)
         | 
| 180 | 
            +
                end
         | 
| 181 | 
            +
              end
         | 
| 182 | 
            +
             | 
| 183 | 
            +
              def test_only_call_after_rollback_on_records_rolled_back_to_a_savepoint
         | 
| 184 | 
            +
                def @first.rollbacks(i=0); @rollbacks ||= 0; @rollbacks += i if i; end
         | 
| 185 | 
            +
                def @first.commits(i=0); @commits ||= 0; @commits += i if i; end
         | 
| 186 | 
            +
                @first.after_rollback_block{|r| r.rollbacks(1)}
         | 
| 187 | 
            +
                @first.after_commit_block{|r| r.commits(1)}
         | 
| 188 | 
            +
             | 
| 189 | 
            +
                def @second.rollbacks(i=0); @rollbacks ||= 0; @rollbacks += i if i; end
         | 
| 190 | 
            +
                def @second.commits(i=0); @commits ||= 0; @commits += i if i; end
         | 
| 191 | 
            +
                @second.after_rollback_block{|r| r.rollbacks(1)}
         | 
| 192 | 
            +
                @second.after_commit_block{|r| r.commits(1)}
         | 
| 193 | 
            +
             | 
| 194 | 
            +
                Topic.transaction do
         | 
| 195 | 
            +
                  @first.save!
         | 
| 196 | 
            +
                  Topic.transaction(:requires_new => true) do
         | 
| 197 | 
            +
                    @second.save!
         | 
| 198 | 
            +
                    raise ActiveRecord::Rollback
         | 
| 199 | 
            +
                  end
         | 
| 200 | 
            +
                end
         | 
| 201 | 
            +
             | 
| 202 | 
            +
                assert_equal 1, @first.commits
         | 
| 203 | 
            +
                assert_equal 0, @first.rollbacks
         | 
| 204 | 
            +
                assert_equal 0, @second.commits
         | 
| 205 | 
            +
                assert_equal 1, @second.rollbacks
         | 
| 206 | 
            +
              end
         | 
| 207 | 
            +
             | 
| 208 | 
            +
              def test_only_call_after_rollback_on_records_rolled_back_to_a_savepoint_when_release_savepoint_fails
         | 
| 209 | 
            +
                def @first.rollbacks(i=0); @rollbacks ||= 0; @rollbacks += i if i; end
         | 
| 210 | 
            +
                def @first.commits(i=0); @commits ||= 0; @commits += i if i; end
         | 
| 211 | 
            +
             | 
| 212 | 
            +
                @first.after_rollback_block{|r| r.rollbacks(1)}
         | 
| 213 | 
            +
                @first.after_commit_block{|r| r.commits(1)}
         | 
| 214 | 
            +
             | 
| 215 | 
            +
                Topic.transaction do
         | 
| 216 | 
            +
                  @first.save
         | 
| 217 | 
            +
                  Topic.transaction(:requires_new => true) do
         | 
| 218 | 
            +
                    @first.save!
         | 
| 219 | 
            +
                    raise ActiveRecord::Rollback
         | 
| 220 | 
            +
                  end
         | 
| 221 | 
            +
                  Topic.transaction(:requires_new => true) do
         | 
| 222 | 
            +
                    @first.save!
         | 
| 223 | 
            +
                    raise ActiveRecord::Rollback
         | 
| 224 | 
            +
                  end
         | 
| 225 | 
            +
                end
         | 
| 226 | 
            +
             | 
| 227 | 
            +
                assert_equal 1, @first.commits
         | 
| 228 | 
            +
                assert_equal 2, @first.rollbacks
         | 
| 229 | 
            +
              end
         | 
| 230 | 
            +
             | 
| 231 | 
            +
              def test_after_transaction_callbacks_should_prevent_callbacks_from_being_called
         | 
| 232 | 
            +
                def @first.last_after_transaction_error=(e); @last_transaction_error = e; end
         | 
| 233 | 
            +
                def @first.last_after_transaction_error; @last_transaction_error; end
         | 
| 234 | 
            +
                @first.after_commit_block{|r| r.last_after_transaction_error = :commit; raise "fail!";}
         | 
| 235 | 
            +
                @first.after_rollback_block{|r| r.last_after_transaction_error = :rollback; raise "fail!";}
         | 
| 236 | 
            +
                @second.after_commit_block{|r| r.history << :after_commit}
         | 
| 237 | 
            +
                @second.after_rollback_block{|r| r.history << :after_rollback}
         | 
| 238 | 
            +
             | 
| 239 | 
            +
                Topic.transaction do
         | 
| 240 | 
            +
                  @first.save!
         | 
| 241 | 
            +
                  @second.save!
         | 
| 242 | 
            +
                end
         | 
| 243 | 
            +
                assert_equal :commit, @first.last_after_transaction_error
         | 
| 244 | 
            +
                assert_equal [:after_commit], @second.history
         | 
| 245 | 
            +
             | 
| 246 | 
            +
                @second.history.clear
         | 
| 247 | 
            +
                Topic.transaction do
         | 
| 248 | 
            +
                  @first.save!
         | 
| 249 | 
            +
                  @second.save!
         | 
| 250 | 
            +
                  raise ActiveRecord::Rollback
         | 
| 251 | 
            +
                end
         | 
| 252 | 
            +
                assert_equal :rollback, @first.last_after_transaction_error
         | 
| 253 | 
            +
                assert_equal [:after_rollback], @second.history
         | 
| 254 | 
            +
              end
         | 
| 255 | 
            +
            end
         | 
| 256 | 
            +
             | 
| 257 | 
            +
             | 
| 258 | 
            +
            class TransactionObserverCallbacksTest < ActiveRecord::TestCase
         | 
| 259 | 
            +
              self.use_transactional_fixtures = false
         | 
| 260 | 
            +
              fixtures :topics
         | 
| 261 | 
            +
             | 
| 262 | 
            +
              class TopicWithObserverAttached < ActiveRecord::Base
         | 
| 263 | 
            +
                self.table_name = :topics
         | 
| 264 | 
            +
                def history
         | 
| 265 | 
            +
                  @history ||= []
         | 
| 266 | 
            +
                end
         | 
| 267 | 
            +
              end
         | 
| 268 | 
            +
             | 
| 269 | 
            +
              class TopicWithObserverAttachedObserver < ActiveRecord::Observer
         | 
| 270 | 
            +
                def after_commit(record)
         | 
| 271 | 
            +
                  record.history.push "after_commit"
         | 
| 272 | 
            +
                end
         | 
| 273 | 
            +
             | 
| 274 | 
            +
                def after_rollback(record)
         | 
| 275 | 
            +
                  record.history.push "after_rollback"
         | 
| 276 | 
            +
                end
         | 
| 277 | 
            +
              end
         | 
| 278 | 
            +
             | 
| 279 | 
            +
              def test_after_commit_called
         | 
| 280 | 
            +
                assert TopicWithObserverAttachedObserver.instance, 'should have observer'
         | 
| 281 | 
            +
             | 
| 282 | 
            +
                topic = TopicWithObserverAttached.new
         | 
| 283 | 
            +
                topic.save!
         | 
| 284 | 
            +
             | 
| 285 | 
            +
                assert_equal %w{ after_commit }, topic.history
         | 
| 286 | 
            +
              end
         | 
| 287 | 
            +
             | 
| 288 | 
            +
              def test_after_rollback_called
         | 
| 289 | 
            +
                assert TopicWithObserverAttachedObserver.instance, 'should have observer'
         | 
| 290 | 
            +
             | 
| 291 | 
            +
                topic = TopicWithObserverAttached.new
         | 
| 292 | 
            +
             | 
| 293 | 
            +
                Topic.transaction do
         | 
| 294 | 
            +
                  topic.save!
         | 
| 295 | 
            +
                  raise ActiveRecord::Rollback
         | 
| 296 | 
            +
                end
         | 
| 297 | 
            +
             | 
| 298 | 
            +
                assert_equal %w{ after_rollback }, topic.history
         | 
| 299 | 
            +
              end
         | 
| 300 | 
            +
            end
         |