odbc-rails 1.3 → 1.4
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/ChangeLog +18 -0
- data/NEWS +5 -0
- data/README +20 -7
- data/lib/active_record/connection_adapters/odbc_adapter.rb +254 -211
- data/lib/active_record/vendor/odbcext_informix.rb +17 -4
- data/lib/active_record/vendor/odbcext_ingres.rb +5 -5
- data/lib/active_record/vendor/odbcext_microsoftsqlserver.rb +35 -4
- data/lib/active_record/vendor/odbcext_mysql.rb +36 -8
- data/lib/active_record/vendor/odbcext_oracle.rb +4 -4
- data/lib/active_record/vendor/odbcext_postgresql.rb +8 -12
- data/lib/active_record/vendor/odbcext_progress.rb +3 -3
- data/lib/active_record/vendor/odbcext_progress89.rb +5 -4
- data/lib/active_record/vendor/odbcext_sybase.rb +6 -5
- data/lib/active_record/vendor/odbcext_virtuoso.rb +16 -3
- data/support/odbc_rails.diff +335 -266
- data/support/rake_fixes/README +6 -0
- data/support/rake_fixes/databases.dif +13 -0
- data/support/test/base_test.rb +333 -75
- data/support/test/migration_test.rb +430 -149
- data/test/connections/native_odbc/connection.rb +63 -44
- data/test/fixtures/db_definitions/db2.drop.sql +1 -0
- data/test/fixtures/db_definitions/db2.sql +9 -0
- data/test/fixtures/db_definitions/informix.drop.sql +1 -0
- data/test/fixtures/db_definitions/informix.sql +10 -0
- data/test/fixtures/db_definitions/ingres.drop.sql +2 -0
- data/test/fixtures/db_definitions/ingres.sql +9 -0
- data/test/fixtures/db_definitions/mysql.drop.sql +1 -0
- data/test/fixtures/db_definitions/mysql.sql +21 -12
- data/test/fixtures/db_definitions/oracle_odbc.drop.sql +4 -0
- data/test/fixtures/db_definitions/oracle_odbc.sql +29 -1
- data/test/fixtures/db_definitions/postgresql.drop.sql +3 -1
- data/test/fixtures/db_definitions/postgresql.sql +13 -3
- data/test/fixtures/db_definitions/progress.drop.sql +2 -0
- data/test/fixtures/db_definitions/progress.sql +11 -0
- data/test/fixtures/db_definitions/sqlserver.drop.sql +3 -0
- data/test/fixtures/db_definitions/sqlserver.sql +35 -0
- data/test/fixtures/db_definitions/sybase.drop.sql +2 -0
- data/test/fixtures/db_definitions/sybase.sql +16 -7
- data/test/fixtures/db_definitions/virtuoso.drop.sql +1 -0
- data/test/fixtures/db_definitions/virtuoso.sql +10 -0
- metadata +6 -3
    
        data/ChangeLog
    CHANGED
    
    | @@ -1,3 +1,21 @@ | |
| 1 | 
            +
            2007-02-27 15:28  source
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            	* Set version 1.4 for final release
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            2007-02-27 12:53  source
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            	* Small rdoc fix
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            2007-02-27 11:05  source
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            	* Added small diff for rake unit testing
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            2007-02-27 11:00  source
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            	* Changes for Rails 1.2.x / ActiveRecord 1.15.x
         | 
| 16 | 
            +
            	* Added support for :decimal type
         | 
| 17 | 
            +
            	* Added :emulate_booleans connection option
         | 
| 18 | 
            +
             | 
| 1 19 | 
             
            2007-01-09 10:18  source
         | 
| 2 20 |  | 
| 3 21 | 
             
            	* Updated version number to 1.3
         | 
    
        data/NEWS
    CHANGED
    
    
    
        data/README
    CHANGED
    
    | @@ -2,11 +2,21 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            (C) 2006 OpenLink Software
         | 
| 4 4 |  | 
| 5 | 
            -
            09-Jan-2007
         | 
| 6 | 
            -
             | 
| 7 5 |  | 
| 8 6 | 
             
            == Status
         | 
| 9 7 |  | 
| 8 | 
            +
            23-Feb-2007
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            The adapter has been updated to support Rails 1.2.x / ActiveRecord 1.15.x.
         | 
| 11 | 
            +
            The new adapter (v1.4) is not recommended for use with Rails 1.1 / ActiveRecord
         | 
| 12 | 
            +
            1.14.x. Please use v1.3 of the adapter with Rails 1.1.
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            The driver now supports the new ActiveRecord :decimal type and an
         | 
| 15 | 
            +
            :emulate_booleans connection option. See http://odbc-rails.rubyforge.org for
         | 
| 16 | 
            +
            more information about this option.
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            09-Jan-2007
         | 
| 19 | 
            +
             | 
| 10 20 | 
             
            The adapter accompanying this note is a Generic ODBC Adapter for Ruby on Rails
         | 
| 11 21 | 
             
            being developed by <B>OpenLink Software</B>[http://www.openlinksw.com].
         | 
| 12 22 |  | 
| @@ -18,7 +28,7 @@ its own adapter. | |
| 18 28 | 
             
            It currently supports Ingres r3, Informix 9.3 or later, Oracle 10g,
         | 
| 19 29 | 
             
            MySQL 5 and OpenLink's Virtuoso
         | 
| 20 30 | 
             
            (Open Source Edition[http://virtuoso.openlinksw.com]), 
         | 
| 21 | 
            -
            SQL Server 2000, Sybase ASE 15, DB2 v9, Progress v8/9/10 and PostgreSQL 8.2.
         | 
| 31 | 
            +
            SQL Server 2000/2005, Sybase ASE 15, DB2 v9, Progress v8/9/10 and PostgreSQL 8.2.
         | 
| 22 32 |  | 
| 23 33 | 
             
            Testing to date has been limited to the ROR 'Expenses' sample
         | 
| 24 34 | 
             
            application described at http://developer.apple.com/tools/rubyonrails.html
         | 
| @@ -71,18 +81,21 @@ due course, if we request that the OpenLink ODBC Adapter for Ruby | |
| 71 81 | 
             
            on Rails be added to the ActiveRecord source distribution to accompany
         | 
| 72 82 | 
             
            the existing Rails adapters.
         | 
| 73 83 |  | 
| 74 | 
            -
            Only one  | 
| 84 | 
            +
            Only one of the patches is really necessary. In adapter release 1.3 or
         | 
| 85 | 
            +
            earlier, the diff file includes a patch to:
         | 
| 75 86 |  | 
| 76 87 | 
             
                lib/active_record/connection_adapters/abstract/schema_definitions.rb
         | 
| 77 88 |  | 
| 78 | 
            -
            This fixes what appears to be a bug in Active Record.
         | 
| 89 | 
            +
            This fixes what appears to be a bug in Active Record 1.14. The patch
         | 
| 90 | 
            +
            is unnecessary for AR 1.15 and consequently not included in adapter
         | 
| 91 | 
            +
            release 1.4
         | 
| 79 92 |  | 
| 80 93 | 
             
            The patches to base_test.rb and migration_test.rb are not essential.
         | 
| 81 94 | 
             
            However, they modify or bypass certain tests to cope with limitations
         | 
| 82 95 | 
             
            of particular databases. Other developers have previously modified
         | 
| 83 96 | 
             
            the tests similarly to cope with limitations of other Rails-supported
         | 
| 84 | 
            -
            databases. The patched versions of files touched by odbc_rails.diff can | 
| 85 | 
            -
            found in support/lib and support/test.
         | 
| 97 | 
            +
            databases. The patched versions of files touched by odbc_rails.diff can
         | 
| 98 | 
            +
            be found in support/lib and support/test.
         | 
| 86 99 |  | 
| 87 100 | 
             
            == Installation
         | 
| 88 101 |  | 
| @@ -1,5 +1,5 @@ | |
| 1 1 | 
             
            #
         | 
| 2 | 
            -
            #  $Id: odbc_adapter.rb,v 1. | 
| 2 | 
            +
            #  $Id: odbc_adapter.rb,v 1.5 2007/02/27 12:53:51 source Exp $
         | 
| 3 3 | 
             
            #
         | 
| 4 4 | 
             
            #  OpenLink ODBC Adapter for Ruby on Rails
         | 
| 5 5 | 
             
            #  Copyright (C) 2006 OpenLink Software
         | 
| @@ -41,12 +41,16 @@ begin | |
| 41 41 | 
             
                    end
         | 
| 42 42 | 
             
                    username = config[:username] ? config[:username].to_s : nil
         | 
| 43 43 | 
             
                    password = config[:password] ? config[:password].to_s : nil
         | 
| 44 | 
            -
                    trace = config[:trace] ? config[:trace] | 
| 45 | 
            -
                    conv_num_lits = config[:convert_numeric_literals] ? config[:convert_numeric_literals] | 
| 44 | 
            +
                    trace = config[:trace].nil? ? false : config[:trace]
         | 
| 45 | 
            +
                    conv_num_lits = config[:convert_numeric_literals].nil? ? false : config[:convert_numeric_literals]
         | 
| 46 | 
            +
                    emulate_bools = config[:emulate_booleans].nil? ? false : config[:emulate_booleans]
         | 
| 47 | 
            +
                    
         | 
| 46 48 | 
             
                    conn = ODBC::connect(dsn, username, password)      
         | 
| 47 49 | 
             
                    conn.autocommit = true
         | 
| 48 | 
            -
                     | 
| 49 | 
            -
             | 
| 50 | 
            +
                    
         | 
| 51 | 
            +
                    ConnectionAdapters::ODBCAdapter.new(conn, {:dsn => dsn, :username => username, 
         | 
| 52 | 
            +
                    :password => password, :trace => trace, :conv_num_lits => conv_num_lits, 
         | 
| 53 | 
            +
                    :emulate_booleans => emulate_bools}, logger)
         | 
| 50 54 | 
             
                  end
         | 
| 51 55 | 
             
                end # class Base
         | 
| 52 56 |  | 
| @@ -57,7 +61,15 @@ begin | |
| 57 61 | 
             
                  # The ODBC adapter requires the Ruby ODBC module (version 0.9991 or 
         | 
| 58 62 | 
             
                  # later), available from http://raa.ruby-lang.org/project/ruby-odbc
         | 
| 59 63 | 
             
                  #
         | 
| 60 | 
            -
                  # == Status | 
| 64 | 
            +
                  # == Status
         | 
| 65 | 
            +
                  #
         | 
| 66 | 
            +
                  # === 27-Feb-2007
         | 
| 67 | 
            +
                  #
         | 
| 68 | 
            +
                  # Adapter updated to support Rails 1.2.x / ActiveRecord 1.15.x.
         | 
| 69 | 
            +
                  # Support added for AR :decimal type and :emulate_booleans connection
         | 
| 70 | 
            +
                  # option introduced.
         | 
| 71 | 
            +
                  #
         | 
| 72 | 
            +
                  # === 09-Jan-2007
         | 
| 61 73 | 
             
                  #
         | 
| 62 74 | 
             
                  # The current adapter supports Ingres r3, Informix 9.3 or later, 
         | 
| 63 75 | 
             
                  # Virtuoso (Open-Source Edition) 4.5, Oracle 10g, MySQL 5, 
         | 
| @@ -109,6 +121,11 @@ begin | |
| 109 121 | 
             
                  #   If set to <tt>true</tt>, suppresses quoting of numeric literals.
         | 
| 110 122 | 
             
                  #   If omitted, <tt>:convert_numeric_literals</tt> defaults to 
         | 
| 111 123 | 
             
                  #   <tt>false</tt>.
         | 
| 124 | 
            +
                  # <tt>:emulate_booleans</tt>::
         | 
| 125 | 
            +
                  #   Instructs the adapter to interpret certain numeric column types as
         | 
| 126 | 
            +
                  #   holding boolean, rather than numeric, data. It is intended for use 
         | 
| 127 | 
            +
                  #   with databases which do not have a native boolean data type. 
         | 
| 128 | 
            +
                  #   If omitted, <tt>:emulate_booleans</tt> defaults to <tt>false</tt>.
         | 
| 112 129 | 
             
                  #   
         | 
| 113 130 | 
             
                  # == Usage Notes
         | 
| 114 131 | 
             
                  # === Informix
         | 
| @@ -187,115 +204,144 @@ begin | |
| 187 204 | 
             
                        # Uses dbmsName as key and dbmsMajorVer as a subkey.          
         | 
| 188 205 | 
             
                        :db2 => {
         | 
| 189 206 | 
             
                          :any_version => {
         | 
| 190 | 
            -
                            :primary_key => " | 
| 207 | 
            +
                            :primary_key => "INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 10000) PRIMARY KEY",
         | 
| 191 208 | 
             
                            :has_autoincrement_col => true,
         | 
| 192 209 | 
             
                            :supports_migrations => true,
         | 
| 193 210 | 
             
                            :supports_schema_names => true,
         | 
| 194 | 
            -
                            :supports_count_distinct => true
         | 
| 211 | 
            +
                            :supports_count_distinct => true,
         | 
| 212 | 
            +
                            :boolean_col_surrogate => "DECIMAL(1)"
         | 
| 195 213 | 
             
                          }
         | 
| 196 214 | 
             
                        },
         | 
| 197 215 | 
             
                        :informix => {
         | 
| 198 216 | 
             
                          :any_version => {
         | 
| 199 | 
            -
                            :primary_key => " | 
| 217 | 
            +
                            :primary_key => "SERIAL PRIMARY KEY",
         | 
| 200 218 | 
             
                            :has_autoincrement_col => true,
         | 
| 201 219 | 
             
                            :supports_migrations => true,
         | 
| 202 220 | 
             
                            :supports_schema_names => true,
         | 
| 203 | 
            -
                            :supports_count_distinct => true
         | 
| 221 | 
            +
                            :supports_count_distinct => true,
         | 
| 222 | 
            +
                            # This data adapter automatically maps ODBC::SQL_BIT to 
         | 
| 223 | 
            +
                            # :boolean. So, the following is unnecessary if the ODBC
         | 
| 224 | 
            +
                            # driver maps the native BOOLEAN type available in 
         | 
| 225 | 
            +
                            # Informix 9.x to ODBC::SQL_BIT in SQLGetTypeInfo.
         | 
| 226 | 
            +
                            :boolean_col_surrogate => "SMALLINT"
         | 
| 204 227 | 
             
                          }
         | 
| 205 228 | 
             
                        },
         | 
| 206 229 | 
             
                        :ingres => {
         | 
| 207 230 | 
             
                          :any_version => {
         | 
| 208 | 
            -
                            :primary_key => " | 
| 231 | 
            +
                            :primary_key => "INTEGER PRIMARY KEY NOT NULL",
         | 
| 209 232 | 
             
                            :has_autoincrement_col => false,
         | 
| 210 233 | 
             
                            :supports_migrations => true,
         | 
| 211 234 | 
             
                            :supports_schema_names => true,
         | 
| 212 | 
            -
                            :supports_count_distinct => true
         | 
| 235 | 
            +
                            :supports_count_distinct => true,
         | 
| 236 | 
            +
                            :boolean_col_surrogate => "INTEGER1"
         | 
| 213 237 | 
             
                          }
         | 
| 214 238 | 
             
                        },
         | 
| 215 | 
            -
                        : | 
| 239 | 
            +
                        :microsoftsqlserver => {
         | 
| 216 240 | 
             
                          :any_version => {
         | 
| 217 | 
            -
                            :primary_key => " | 
| 241 | 
            +
                            :primary_key => "INT NOT NULL IDENTITY(1, 1) PRIMARY KEY",
         | 
| 218 242 | 
             
                            :has_autoincrement_col => true,
         | 
| 219 243 | 
             
                            :supports_migrations => true,
         | 
| 220 | 
            -
                            :supports_schema_names =>  | 
| 221 | 
            -
                            :supports_count_distinct => true
         | 
| 244 | 
            +
                            :supports_schema_names => true,
         | 
| 245 | 
            +
                            :supports_count_distinct => true,
         | 
| 246 | 
            +
                            # boolean_col_surrogate not necessary. 
         | 
| 247 | 
            +
                            # SQL Server's BIT data type is mapped to ODBC::SQL_BIT/:boolean.
         | 
| 248 | 
            +
                            :boolean_col_surrogate => nil
         | 
| 222 249 | 
             
                          },
         | 
| 223 | 
            -
                           | 
| 224 | 
            -
                            :primary_key => " | 
| 250 | 
            +
                          8 => {
         | 
| 251 | 
            +
                            :primary_key => "INT NOT NULL IDENTITY(1, 1) PRIMARY KEY",
         | 
| 225 252 | 
             
                            :has_autoincrement_col => true,
         | 
| 226 253 | 
             
                            :supports_migrations => true,
         | 
| 227 | 
            -
                            :supports_schema_names =>  | 
| 228 | 
            -
                            :supports_count_distinct => true
         | 
| 254 | 
            +
                            :supports_schema_names => true,
         | 
| 255 | 
            +
                            :supports_count_distinct => true,
         | 
| 256 | 
            +
                            # boolean_col_surrogate not necessary. 
         | 
| 257 | 
            +
                            # SQL Server's BIT data type is mapped to ODBC::SQL_BIT/:boolean.
         | 
| 258 | 
            +
                            :boolean_col_surrogate => nil
         | 
| 229 259 | 
             
                          }
         | 
| 230 260 | 
             
                        },
         | 
| 231 | 
            -
                        : | 
| 261 | 
            +
                        :mysql => {
         | 
| 232 262 | 
             
                          :any_version => {
         | 
| 233 | 
            -
                            :primary_key => " | 
| 263 | 
            +
                            :primary_key => "INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY",
         | 
| 234 264 | 
             
                            :has_autoincrement_col => true,
         | 
| 235 265 | 
             
                            :supports_migrations => true,
         | 
| 236 | 
            -
                            :supports_schema_names =>  | 
| 237 | 
            -
                            :supports_count_distinct => true
         | 
| 266 | 
            +
                            :supports_schema_names => false,
         | 
| 267 | 
            +
                            :supports_count_distinct => true,
         | 
| 268 | 
            +
                            :boolean_col_surrogate => "TINYINT"                                
         | 
| 238 269 | 
             
                          },
         | 
| 239 | 
            -
                           | 
| 240 | 
            -
                            :primary_key => " | 
| 270 | 
            +
                          5 => {
         | 
| 271 | 
            +
                            :primary_key => "INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY",
         | 
| 241 272 | 
             
                            :has_autoincrement_col => true,
         | 
| 242 273 | 
             
                            :supports_migrations => true,
         | 
| 243 | 
            -
                            :supports_schema_names =>  | 
| 244 | 
            -
                            :supports_count_distinct => true
         | 
| 274 | 
            +
                            :supports_schema_names => false,
         | 
| 275 | 
            +
                            :supports_count_distinct => true,
         | 
| 276 | 
            +
                            :boolean_col_surrogate => "TINYINT"
         | 
| 245 277 | 
             
                          }
         | 
| 246 278 | 
             
                        },
         | 
| 247 279 | 
             
                        :oracle => {
         | 
| 248 280 | 
             
                          :any_version => {
         | 
| 249 | 
            -
                            :primary_key => " | 
| 281 | 
            +
                            :primary_key => "NUMBER(10) PRIMARY KEY NOT NULL",
         | 
| 250 282 | 
             
                            :has_autoincrement_col => false,
         | 
| 251 283 | 
             
                            :supports_migrations => true,
         | 
| 252 284 | 
             
                            :supports_schema_names => true,
         | 
| 253 | 
            -
                            :supports_count_distinct => true
         | 
| 285 | 
            +
                            :supports_count_distinct => true,
         | 
| 286 | 
            +
                            :boolean_col_surrogate => "NUMBER(1)"
         | 
| 254 287 | 
             
                          }
         | 
| 255 288 | 
             
                        },
         | 
| 256 289 | 
             
                        :postgresql => {
         | 
| 257 290 | 
             
                          :any_version => {
         | 
| 258 | 
            -
                            :primary_key => " | 
| 291 | 
            +
                            :primary_key => "SERIAL PRIMARY KEY",
         | 
| 259 292 | 
             
                            :has_autoincrement_col => true,
         | 
| 260 293 | 
             
                            :supports_migrations => true,
         | 
| 261 294 | 
             
                            :supports_schema_names => false,
         | 
| 262 | 
            -
                            :supports_count_distinct => true
         | 
| 295 | 
            +
                            :supports_count_distinct => true,
         | 
| 296 | 
            +
                            # boolean_col_surrogate not necessary. 
         | 
| 297 | 
            +
                            # PostgreSQL's BOOL data type is mapped to ODBC::SQL_BIT/:boolean.
         | 
| 298 | 
            +
                            :boolean_col_surrogate => nil                
         | 
| 263 299 | 
             
                          }
         | 
| 264 300 | 
             
                        },
         | 
| 265 301 | 
             
                        :progress => {
         | 
| 266 302 | 
             
                          :any_version => {
         | 
| 267 | 
            -
                            :primary_key => " | 
| 303 | 
            +
                            :primary_key => "INTEGER NOT NULL PRIMARY KEY",
         | 
| 268 304 | 
             
                            :has_autoincrement_col => false,
         | 
| 269 305 | 
             
                            :supports_migrations => true,
         | 
| 270 306 | 
             
                            :supports_schema_names => true,
         | 
| 271 | 
            -
                            :supports_count_distinct => true
         | 
| 307 | 
            +
                            :supports_count_distinct => true,
         | 
| 308 | 
            +
                            # boolean_col_surrogate not necessary. 
         | 
| 309 | 
            +
                            # Progress SQL-92's BIT data type is mapped to ODBC::SQL_BIT/:boolean.
         | 
| 310 | 
            +
                            :boolean_col_surrogate => nil
         | 
| 272 311 | 
             
                          }
         | 
| 273 312 | 
             
                        },
         | 
| 274 313 | 
             
                        :progress89 => {
         | 
| 275 314 | 
             
                          :any_version => {
         | 
| 276 | 
            -
                            :primary_key => " | 
| 315 | 
            +
                            :primary_key => "INTEGER NOT NULL UNIQUE",
         | 
| 277 316 | 
             
                            :has_autoincrement_col => false,
         | 
| 278 317 | 
             
                            :supports_migrations => true,
         | 
| 279 318 | 
             
                            :supports_schema_names => false,
         | 
| 280 | 
            -
                            :supports_count_distinct => true
         | 
| 319 | 
            +
                            :supports_count_distinct => true,
         | 
| 320 | 
            +
                            # boolean_col_surrogate not necessary. 
         | 
| 321 | 
            +
                            # Progress SQL-89's LOGICAL data type is mapped to ODBC::SQL_BIT/:boolean.
         | 
| 322 | 
            +
                            :boolean_col_surrogate => nil                
         | 
| 281 323 | 
             
                          }
         | 
| 282 324 | 
             
                        },
         | 
| 283 325 | 
             
                        :sybase => {
         | 
| 284 326 | 
             
                          :any_version => {
         | 
| 285 | 
            -
                            :primary_key => " | 
| 327 | 
            +
                            :primary_key => "INT IDENTITY PRIMARY KEY",
         | 
| 286 328 | 
             
                            :has_autoincrement_col => true,
         | 
| 287 329 | 
             
                            :supports_migrations => true,
         | 
| 288 330 | 
             
                            :supports_schema_names => true,
         | 
| 289 | 
            -
                            :supports_count_distinct => true
         | 
| 331 | 
            +
                            :supports_count_distinct => true,
         | 
| 332 | 
            +
                            # boolean_col_surrogate not necessary. 
         | 
| 333 | 
            +
                            # Sybase's BIT data type is mapped to ODBC::SQL_BIT/:boolean.
         | 
| 334 | 
            +
                            :boolean_col_surrogate => nil                                
         | 
| 290 335 | 
             
                          }
         | 
| 291 336 | 
             
                        },
         | 
| 292 337 | 
             
                        :virtuoso => {
         | 
| 293 338 | 
             
                          :any_version => {
         | 
| 294 | 
            -
                            :primary_key => " | 
| 339 | 
            +
                            :primary_key => "INT NOT NULL IDENTITY PRIMARY KEY",
         | 
| 295 340 | 
             
                            :has_autoincrement_col => true,
         | 
| 296 341 | 
             
                            :supports_migrations => true,
         | 
| 297 342 | 
             
                            :supports_schema_names => true,
         | 
| 298 | 
            -
                            :supports_count_distinct => true
         | 
| 343 | 
            +
                            :supports_count_distinct => true,
         | 
| 344 | 
            +
                            :boolean_col_surrogate => "SMALLINT"
         | 
| 299 345 | 
             
                          }
         | 
| 300 346 | 
             
                        }
         | 
| 301 347 | 
             
                      }
         | 
| @@ -333,7 +379,8 @@ begin | |
| 333 379 | 
             
                      ODBC::SQL_IDENTIFIER_QUOTE_CHAR,
         | 
| 334 380 | 
             
                      ODBC::SQL_MAX_IDENTIFIER_LEN,		
         | 
| 335 381 | 
             
                      ODBC::SQL_MAX_TABLE_NAME_LEN,
         | 
| 336 | 
            -
                      ODBC::SQL_USER_NAME
         | 
| 382 | 
            +
                      ODBC::SQL_USER_NAME,
         | 
| 383 | 
            +
                      ODBC::SQL_DATABASE_NAME
         | 
| 337 384 | 
             
                      ]
         | 
| 338 385 |  | 
| 339 386 | 
             
                      def initialize(connection)
         | 
| @@ -376,9 +423,12 @@ begin | |
| 376 423 | 
             
                    # DBMS; so similar names are mapped to the same symbol. 
         | 
| 377 424 | 
             
                    # _dbmsName_ is the SQL_DBMS_NAME returned by ODBC, downcased with
         | 
| 378 425 | 
             
                    # whitespace removed. e.g. <tt>informix</tt>, <tt>ingres</tt>,
         | 
| 379 | 
            -
                    # <tt>microsoftsqlserver</tt> etc. | 
| 426 | 
            +
                    # <tt>microsoftsqlserver</tt> etc.              
         | 
| 380 427 | 
             
                    attr_reader :dbmsName
         | 
| 381 428 |  | 
| 429 | 
            +
                    # Emulate boolean columns if the database doesn't have a native BOOLEAN type.
         | 
| 430 | 
            +
                    attr_reader :emulate_booleans
         | 
| 431 | 
            +
                    
         | 
| 382 432 | 
             
                    # Supports lookups of DBMS-dependent information/settings which
         | 
| 383 433 | 
             
                    # cannot be derived satisfactorily through ODBC
         | 
| 384 434 | 
             
                    @@dbmsLookups = DbmsInfo.create
         | 
| @@ -386,8 +436,8 @@ begin | |
| 386 436 | 
             
                    @@trace = nil
         | 
| 387 437 | 
             
                    #--
         | 
| 388 438 |  | 
| 389 | 
            -
                    def initialize(connection, connection_options,  | 
| 390 | 
            -
                      @@trace = trace && logger if !@@trace
         | 
| 439 | 
            +
                    def initialize(connection, connection_options, logger = nil)
         | 
| 440 | 
            +
                      @@trace = connection_options[:trace] && logger if !@@trace
         | 
| 391 441 | 
             
                      # Mixins in odbcext_xxx.rb included using Object#extend can't access
         | 
| 392 442 | 
             
                      # @@trace. Why?
         | 
| 393 443 | 
             
                      # (Error message "NameError: uninitialized class variable @@trace".)
         | 
| @@ -399,7 +449,9 @@ begin | |
| 399 449 | 
             
                      @logger.unknown("ODBCAdapter#initialize>") if @@trace
         | 
| 400 450 |  | 
| 401 451 | 
             
                      @connection, @connection_options = connection, connection_options
         | 
| 402 | 
            -
                      @convert_numeric_literals =  | 
| 452 | 
            +
                      @convert_numeric_literals = connection_options[:conv_num_lits]
         | 
| 453 | 
            +
                      @emulate_booleans = connection_options[:emulate_booleans]
         | 
| 454 | 
            +
                      
         | 
| 403 455 | 
             
                      # Caches SQLGetInfo output
         | 
| 404 456 | 
             
                      @dsInfo = DSInfo.new(connection)
         | 
| 405 457 | 
             
                      # Caches SQLGetTypeInfo output
         | 
| @@ -437,7 +489,7 @@ begin | |
| 437 489 | 
             
                    # Returns the human-readable name of the adapter.
         | 
| 438 490 | 
             
                    def adapter_name
         | 
| 439 491 | 
             
                      @logger.unknown("ODBCAdapter#adapter_name>") if @@trace
         | 
| 440 | 
            -
             | 
| 492 | 
            +
                      'ODBC'
         | 
| 441 493 | 
             
                    end
         | 
| 442 494 |  | 
| 443 495 | 
             
                    # Does this adapter support migrations?
         | 
| @@ -505,11 +557,14 @@ begin | |
| 505 557 | 
             
                      @logger.unknown("ODBCAdapter#quote>") if @@trace
         | 
| 506 558 | 
             
                      @logger.unknown("args=[#{value}]") if @@trace
         | 
| 507 559 | 
             
                      case value
         | 
| 508 | 
            -
                      when String
         | 
| 560 | 
            +
                      when String, ActiveSupport::Multibyte::Chars          
         | 
| 561 | 
            +
                        value = value.to_s
         | 
| 509 562 | 
             
                        if column && column.type == :binary && self.respond_to?(:string_to_binary)
         | 
| 510 563 | 
             
                          "'#{string_to_binary(value)}'"
         | 
| 511 | 
            -
                        elsif (column && [:integer, :float].include?(column.type)) | 
| 512 | 
            -
             | 
| 564 | 
            +
                        elsif (column && [:integer, :float].include?(column.type))
         | 
| 565 | 
            +
                          value = column.type == :integer ? value.to_i : value.to_f
         | 
| 566 | 
            +
                          value.to_s            
         | 
| 567 | 
            +
                        elsif (column.nil? && @convert_numeric_literals && 
         | 
| 513 568 | 
             
                         (value =~ /^[-+]?[0-9]+[.]?[0-9]*([eE][-+]?[0-9]+)?$/))
         | 
| 514 569 | 
             
                          value
         | 
| 515 570 | 
             
                        else
         | 
| @@ -564,12 +619,12 @@ begin | |
| 564 619 |  | 
| 565 620 | 
             
                    def quoted_true
         | 
| 566 621 | 
             
                      @logger.unknown("ODBCAdapter#quoted_true>") if @@trace
         | 
| 567 | 
            -
             | 
| 622 | 
            +
            		  '1'
         | 
| 568 623 | 
             
                    end
         | 
| 569 624 |  | 
| 570 625 | 
             
                    def quoted_false
         | 
| 571 626 | 
             
                      @logger.unknown("ODBCAdapter#quoted_false>") if @@trace
         | 
| 572 | 
            -
             | 
| 627 | 
            +
            		  '0'
         | 
| 573 628 | 
             
                    end
         | 
| 574 629 |  | 
| 575 630 | 
             
                    def quoted_date(value)
         | 
| @@ -580,10 +635,10 @@ begin | |
| 580 635 | 
             
                      case value
         | 
| 581 636 | 
             
                      when Time, DateTime
         | 
| 582 637 | 
             
                        #%Q!{ts #{value.strftime("%Y-%m-%d %H:%M:%S")}}!
         | 
| 583 | 
            -
             | 
| 638 | 
            +
                        %Q!'#{value.strftime("%Y-%m-%d %H:%M:%S")}'!
         | 
| 584 639 | 
             
                      when Date
         | 
| 585 640 | 
             
                        #%Q!{d #{value.strftime("%Y-%m-%d")}}!
         | 
| 586 | 
            -
             | 
| 641 | 
            +
                        %Q!'#{value.strftime("%Y-%m-%d")}'!
         | 
| 587 642 | 
             
                      end
         | 
| 588 643 | 
             
                    end
         | 
| 589 644 |  | 
| @@ -876,7 +931,7 @@ begin | |
| 876 931 | 
             
                    def default_sequence_name(table, column)
         | 
| 877 932 | 
             
                      @logger.unknown("ODBCAdapter#default_sequence_name>") if @@trace
         | 
| 878 933 | 
             
                      @logger.unknown("args=[#{table}|#{column}]") if @@trace
         | 
| 879 | 
            -
             | 
| 934 | 
            +
                      "#{table}_seq"
         | 
| 880 935 | 
             
                    end
         | 
| 881 936 |  | 
| 882 937 | 
             
                    # Set the sequence to the max value of the table�s column.
         | 
| @@ -894,18 +949,41 @@ begin | |
| 894 949 | 
             
                    #
         | 
| 895 950 | 
             
                    # see: abstract/schema_statements.rb
         | 
| 896 951 |  | 
| 897 | 
            -
                     | 
| 898 | 
            -
             | 
| 899 | 
            -
             | 
| 952 | 
            +
                    def create_database(name)
         | 
| 953 | 
            +
                      @logger.unknown("ODBCAdapter#create_database>") if @trace
         | 
| 954 | 
            +
                      @logger.unknown("args=[#{name}]") if @trace            
         | 
| 955 | 
            +
                      raise NotImplementedError, "create_database is not implemented"
         | 
| 956 | 
            +
                    rescue Exception => e
         | 
| 957 | 
            +
                      @logger.unknown("exception=#{e}") if @trace
         | 
| 958 | 
            +
                      raise
         | 
| 959 | 
            +
                    end
         | 
| 900 960 |  | 
| 901 | 
            -
                     | 
| 902 | 
            -
             | 
| 903 | 
            -
             | 
| 961 | 
            +
                    def drop_database(name)
         | 
| 962 | 
            +
                      @logger.unknown("ODBCAdapter#drop_database>") if @trace
         | 
| 963 | 
            +
                      @logger.unknown("args=[#{name}]") if @trace            
         | 
| 964 | 
            +
                      raise NotImplementedError, "drop_database is not implemented"
         | 
| 965 | 
            +
                    rescue Exception => e
         | 
| 966 | 
            +
                      @logger.unknown("exception=#{e}") if @trace
         | 
| 967 | 
            +
                      raise
         | 
| 968 | 
            +
                    end
         | 
| 904 969 |  | 
| 905 | 
            -
                     | 
| 906 | 
            -
                    # | 
| 907 | 
            -
                     | 
| 970 | 
            +
                    #--
         | 
| 971 | 
            +
                    # Required by db:test:purge Rake task (see databases.rake)
         | 
| 972 | 
            +
                    def recreate_database(name, fail_quietly = false)
         | 
| 973 | 
            +
                      @logger.unknown("ODBCAdapter#recreate_database>") if @@trace
         | 
| 974 | 
            +
                      @logger.unknown("args=[#{name}|#{fail_quietly}]") if @@trace
         | 
| 975 | 
            +
                      begin
         | 
| 976 | 
            +
                        drop_database(name)
         | 
| 977 | 
            +
                        create_database(name)
         | 
| 978 | 
            +
                      rescue Exception => e
         | 
| 979 | 
            +
                        raise unless fail_quietly
         | 
| 980 | 
            +
                      end
         | 
| 981 | 
            +
                    end
         | 
| 908 982 |  | 
| 983 | 
            +
                    def current_database
         | 
| 984 | 
            +
                      @dsInfo.info[ODBC::SQL_DATABASE_NAME].strip
         | 
| 985 | 
            +
                    end
         | 
| 986 | 
            +
             | 
| 909 987 | 
             
                    # The maximum length a table alias can be.
         | 
| 910 988 | 
             
                    def table_alias_length
         | 
| 911 989 | 
             
                      maxIdentLen = @dsInfo.info[ODBC::SQL_MAX_IDENTIFIER_LEN]
         | 
| @@ -950,6 +1028,13 @@ begin | |
| 950 1028 | 
             
                      table_name = table_name.to_s if table_name.class == Symbol
         | 
| 951 1029 |  | 
| 952 1030 | 
             
                      getDbTypeInfo
         | 
| 1031 | 
            +
                      begin
         | 
| 1032 | 
            +
                        booleanColSurrogate = @emulate_booleans ? @@dbmsLookups.get_info(@dbmsName, @dbmsMajorVer, :boolean_col_surrogate) : nil
         | 
| 1033 | 
            +
                      rescue Exception
         | 
| 1034 | 
            +
                        # No boolean column surrogate defined for target database in lookup table
         | 
| 1035 | 
            +
                        booleanColSurrogate = nil
         | 
| 1036 | 
            +
                        @emulate_booleans = false
         | 
| 1037 | 
            +
                      end  
         | 
| 953 1038 | 
             
                      cols = []
         | 
| 954 1039 | 
             
                      stmt = @connection.columns(dbmsIdentCase(table_name))
         | 
| 955 1040 | 
             
                      resultSet = stmt.fetch_all || []
         | 
| @@ -959,6 +1044,7 @@ begin | |
| 959 1044 | 
             
                        colSqlType = col[4] # SQLColumns: DATA_TYPE
         | 
| 960 1045 | 
             
                        colNativeType = col[5] # SQLColumns: TYPE_NAME
         | 
| 961 1046 | 
             
                        colLimit = col[6] # SQLColumns: COLUMN_SIZE
         | 
| 1047 | 
            +
                        colScale = col[8] # SQLColumns: DECIMAL_DIGITS
         | 
| 962 1048 |  | 
| 963 1049 | 
             
                        odbcIsNullable = col[17] # SQLColumns: IS_NULLABLE
         | 
| 964 1050 | 
             
                        odbcNullable = col[10] # SQLColumns: NULLABLE
         | 
| @@ -979,9 +1065,10 @@ begin | |
| 979 1065 | 
             
                        elsif colDefault =~ /^\((.*)\)$/ # SQL Server numeric default
         | 
| 980 1066 | 
             
                          colDefault = $1
         | 
| 981 1067 | 
             
                          # ODBC drivers should return string column defaults in quotes
         | 
| 982 | 
            -
                          # -  | 
| 1068 | 
            +
                          # - strip off the quotes
         | 
| 1069 | 
            +
                          # - Oracle may include a trailing space.
         | 
| 983 1070 | 
             
                          # - PostgreSQL may return '<default>::character varying'
         | 
| 984 | 
            -
                        elsif colDefault =~ /^'(.*)'[ :] | 
| 1071 | 
            +
                        elsif colDefault =~ /^'(.*)'([ :].*)*$/
         | 
| 985 1072 | 
             
                          colDefault = $1
         | 
| 986 1073 | 
             
            	        #TODO: HACKS for Progress
         | 
| 987 1074 | 
             
                        elsif @dbmsName == :progress || @dbmsName == :progress89
         | 
| @@ -995,7 +1082,7 @@ begin | |
| 995 1082 | 
             
                        end
         | 
| 996 1083 | 
             
                        cols << ODBCColumn.new(activeRecIdentCase(colName), table_name, 
         | 
| 997 1084 | 
             
                        colDefault, colSqlType, colNativeType, colNullable, colLimit, 
         | 
| 998 | 
            -
                        @odbcExtFile+"_col",  | 
| 1085 | 
            +
                        colScale, @odbcExtFile+"_col", booleanColSurrogate, native_database_types())
         | 
| 999 1086 | 
             
                      end
         | 
| 1000 1087 | 
             
                      stmt.drop
         | 
| 1001 1088 | 
             
                      cols
         | 
| @@ -1012,7 +1099,7 @@ begin | |
| 1012 1099 | 
             
                      indexes = []
         | 
| 1013 1100 | 
             
                      indexCols = indexName = isUnique = nil
         | 
| 1014 1101 |  | 
| 1015 | 
            -
                      stmt = @connection.indexes(dbmsIdentCase(table_name))
         | 
| 1102 | 
            +
                      stmt = @connection.indexes(dbmsIdentCase(table_name.to_s))
         | 
| 1016 1103 | 
             
                      rs = stmt.fetch_all || []
         | 
| 1017 1104 | 
             
                      rs.each_index do |iRow|
         | 
| 1018 1105 | 
             
                        row = rs[iRow]
         | 
| @@ -1064,6 +1151,7 @@ begin | |
| 1064 1151 | 
             
                        :string      => nil,
         | 
| 1065 1152 | 
             
                        :text        => nil,
         | 
| 1066 1153 | 
             
                        :integer     => nil,
         | 
| 1154 | 
            +
                        :decimal     => nil,
         | 
| 1067 1155 | 
             
                        :float       => nil,
         | 
| 1068 1156 | 
             
                        :datetime    => nil,
         | 
| 1069 1157 | 
             
                        :timestamp   => nil,
         | 
| @@ -1109,6 +1197,16 @@ begin | |
| 1109 1197 | 
             
                        end
         | 
| 1110 1198 | 
             
                        @logger.unknown("WARNING: No suitable DBMS type for abstract type #{abstractType.to_s}") if !isSupported && @@trace
         | 
| 1111 1199 | 
             
                      end
         | 
| 1200 | 
            +
             | 
| 1201 | 
            +
                      begin                    
         | 
| 1202 | 
            +
                        booleanColSurrogate = @emulate_booleans ? @@dbmsLookups.get_info(@dbmsName, @dbmsMajorVer, :boolean_col_surrogate) : nil
         | 
| 1203 | 
            +
                      rescue Exception
         | 
| 1204 | 
            +
                        # No boolean column surrogate defined for target database in lookup table
         | 
| 1205 | 
            +
                        booleanColSurrogate = nil
         | 
| 1206 | 
            +
                        @emulate_booleans = false              
         | 
| 1207 | 
            +
                      end
         | 
| 1208 | 
            +
                      @abstract2NativeTypeMap[:boolean] = {:name => booleanColSurrogate} if booleanColSurrogate
         | 
| 1209 | 
            +
                      
         | 
| 1112 1210 | 
             
                      {}.merge(@abstract2NativeTypeMap)
         | 
| 1113 1211 | 
             
                    rescue Exception => e
         | 
| 1114 1212 | 
             
                      @logger.unknown("exception=#{e}") if @@trace
         | 
| @@ -1137,10 +1235,10 @@ begin | |
| 1137 1235 | 
             
                    end
         | 
| 1138 1236 |  | 
| 1139 1237 | 
             
                    # Drops a table from the database.
         | 
| 1140 | 
            -
                    def drop_table(name)
         | 
| 1238 | 
            +
                    def drop_table(name, options = {})
         | 
| 1141 1239 | 
             
                      @logger.unknown("ODBCAdapter#drop_table>") if @@trace
         | 
| 1142 1240 | 
             
                      @logger.unknown("args=[#{name}]") if @@trace
         | 
| 1143 | 
            -
                      super(name)
         | 
| 1241 | 
            +
                      super(name, options)
         | 
| 1144 1242 | 
             
                    rescue Exception => e
         | 
| 1145 1243 | 
             
                      @logger.unknown("exception=#{e}") if @@trace
         | 
| 1146 1244 | 
             
                      raise ActiveRecordError, e.message
         | 
| @@ -1252,8 +1350,8 @@ begin | |
| 1252 1350 | 
             
                      @logger.unknown("ODBCAdapter#transaction>") if @@trace
         | 
| 1253 1351 | 
             
                      super(start_db_transaction)
         | 
| 1254 1352 | 
             
                    rescue Exception => e
         | 
| 1255 | 
            -
                      @logger.unknown(" | 
| 1256 | 
            -
                      raise | 
| 1353 | 
            +
                      @logger.unknown("#{e.class}: #{e}") if @@trace
         | 
| 1354 | 
            +
                      raise
         | 
| 1257 1355 | 
             
                    end
         | 
| 1258 1356 |  | 
| 1259 1357 | 
             
                    # Alias for #add_limit_offset!
         | 
| @@ -1286,45 +1384,43 @@ begin | |
| 1286 1384 | 
             
                    end
         | 
| 1287 1385 |  | 
| 1288 1386 | 
             
                    #--
         | 
| 1289 | 
            -
                    #  | 
| 1290 | 
            -
                    #  | 
| 1291 | 
            -
                    #  | 
| 1292 | 
            -
                    #  | 
| 1387 | 
            +
                    # If the index is not explicitly named using the :name option, 
         | 
| 1388 | 
            +
                    # there's a risk the generated index name could exceed the maximum
         | 
| 1389 | 
            +
                    # length supported by the database. 
         | 
| 1390 | 
            +
                    # i.e. dsInfo.info[ODBC::SQL_MAX_IDENTIFIER_LEN]
         | 
| 1293 1391 | 
             
                    def index_name(table_name, options) # :nodoc:
         | 
| 1294 1392 | 
             
                      @logger.unknown("ODBCAdapter#index_name>") if @@trace
         | 
| 1295 1393 | 
             
                      @logger.unknown("args=[#{table_name}]") if @@trace
         | 
| 1296 | 
            -
                       | 
| 1297 | 
            -
                      if Hash === options # legacy support
         | 
| 1298 | 
            -
                        if options[:name]
         | 
| 1299 | 
            -
                          return options[:name] # error if name length > max index length
         | 
| 1300 | 
            -
                        elsif options[:column]
         | 
| 1301 | 
            -
                          col_name = options[:column]
         | 
| 1302 | 
            -
                        else
         | 
| 1303 | 
            -
                          raise ArgumentError, "You must specify the index name"
         | 
| 1304 | 
            -
                        end
         | 
| 1305 | 
            -
                      else
         | 
| 1306 | 
            -
                        col_name = options
         | 
| 1307 | 
            -
                      end
         | 
| 1308 | 
            -
                      idx_name = "#{table_name}_#{col_name}_index"
         | 
| 1309 | 
            -
                      if idx_name.length > maxIndxNameLen
         | 
| 1310 | 
            -
                        cMax = ((maxIndxNameLen - 5)/2).to_i
         | 
| 1311 | 
            -
                        idx_name = "#{table_name.to_s[0,cMax]}_#{col_name.to_s[0,cMax]}_idx"
         | 
| 1312 | 
            -
                      end
         | 
| 1313 | 
            -
                      idx_name          
         | 
| 1394 | 
            +
                      super
         | 
| 1314 1395 | 
             
                    rescue Exception => e
         | 
| 1315 1396 | 
             
                      @logger.unknown("exception=#{e}") if @@trace
         | 
| 1316 1397 | 
             
                      raise ActiveRecordError, e.message
         | 
| 1317 1398 | 
             
                    end
         | 
| 1318 1399 |  | 
| 1319 | 
            -
                    def type_to_sql(type, limit = nil) # :nodoc:
         | 
| 1400 | 
            +
                    def type_to_sql(type, limit = nil, precision = nil, scale = nil) # :nodoc:
         | 
| 1320 1401 | 
             
                      @logger.unknown("ODBCAdapter#type_to_sql>") if @@trace
         | 
| 1321 | 
            -
                      @logger.unknown("args=[#{type}|#{limit}]") if @@trace
         | 
| 1402 | 
            +
                      @logger.unknown("args=[#{type}|#{limit}|#{precision}|#{scale}]") if @@trace
         | 
| 1322 1403 | 
             
                      native = native_database_types[type]
         | 
| 1323 | 
            -
                      column_type_sql = String.new( | 
| 1324 | 
            -
                       | 
| 1325 | 
            -
             | 
| 1326 | 
            -
             | 
| 1327 | 
            -
             | 
| 1404 | 
            +
                      column_type_sql = String.new(native.is_a?(Hash) ? native[:name] : native)
         | 
| 1405 | 
            +
                      if type == :decimal # ignore limit, use precision and scale
         | 
| 1406 | 
            +
                        precision ||= native[:precision]
         | 
| 1407 | 
            +
                        scale ||= native[:scale]
         | 
| 1408 | 
            +
                        if precision
         | 
| 1409 | 
            +
                          if scale
         | 
| 1410 | 
            +
                            column_type_sql << "(#{precision},#{scale})"
         | 
| 1411 | 
            +
                          else
         | 
| 1412 | 
            +
                            column_type_sql << "(#{precision})"
         | 
| 1413 | 
            +
                          end
         | 
| 1414 | 
            +
                        else
         | 
| 1415 | 
            +
                          raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale if specified" if scale
         | 
| 1416 | 
            +
                        end
         | 
| 1417 | 
            +
                        column_type_sql          
         | 
| 1418 | 
            +
                      else
         | 
| 1419 | 
            +
                        # if there's no limit in the type definition, assume that the type 
         | 
| 1420 | 
            +
                        # doesn't support a length qualifier
         | 
| 1421 | 
            +
                        column_type_sql << "(#{limit || native[:limit]})" if native[:limit]
         | 
| 1422 | 
            +
                        column_type_sql        																											
         | 
| 1423 | 
            +
                      end
         | 
| 1328 1424 | 
             
                    rescue Exception => e
         | 
| 1329 1425 | 
             
                      @logger.unknown("exception=#{e}") if @@trace
         | 
| 1330 1426 | 
             
                      raise ActiveRecordError, e.message
         | 
| @@ -1350,7 +1446,7 @@ begin | |
| 1350 1446 | 
             
                    end
         | 
| 1351 1447 |  | 
| 1352 1448 | 
             
                    # ==================================================================
         | 
| 1353 | 
            -
             | 
| 1449 | 
            +
             | 
| 1354 1450 | 
             
                    private
         | 
| 1355 1451 |  | 
| 1356 1452 | 
             
                    # Maps a DBMS name to a symbol.
         | 
| @@ -1405,6 +1501,7 @@ begin | |
| 1405 1501 | 
             
                        :string => [ODBC::SQL_VARCHAR],
         | 
| 1406 1502 | 
             
                        :text => [ODBC::SQL_LONGVARCHAR, ODBC::SQL_VARCHAR],
         | 
| 1407 1503 | 
             
                        :integer => [ODBC::SQL_INTEGER, ODBC::SQL_SMALLINT],
         | 
| 1504 | 
            +
                        :decimal => [ ODBC::SQL_NUMERIC, ODBC::SQL_DECIMAL],
         | 
| 1408 1505 | 
             
                        :float => [ODBC::SQL_DOUBLE, ODBC::SQL_REAL],
         | 
| 1409 1506 | 
             
                        :datetime => [ODBC::SQL_TYPE_TIMESTAMP, ODBC::SQL_TIMESTAMP],
         | 
| 1410 1507 | 
             
                        :timestamp => [ODBC::SQL_TYPE_TIMESTAMP, ODBC::SQL_TIMESTAMP],
         | 
| @@ -1466,12 +1563,10 @@ begin | |
| 1466 1563 |  | 
| 1467 1564 | 
             
                        res[:name] = nativeTypeDesc[0] # SQLGetTypeInfo: TYPE_NAME
         | 
| 1468 1565 | 
             
                        createParams = nativeTypeDesc[5]
         | 
| 1469 | 
            -
                        #  | 
| 1470 | 
            -
                        #  | 
| 1471 | 
            -
                         | 
| 1472 | 
            -
             | 
| 1473 | 
            -
                        # creation parameter.
         | 
| 1474 | 
            -
                        if (createParams && createParams.strip.length > 0)
         | 
| 1566 | 
            +
                        # Depending on the column type, the CREATE_PARAMS keywords can
         | 
| 1567 | 
            +
                        # include length, precision or scale.
         | 
| 1568 | 
            +
                        if (createParams && createParams.strip.length > 0 &&
         | 
| 1569 | 
            +
                            ![:decimal].include?(abstractType))
         | 
| 1475 1570 | 
             
                          unless @dbmsName == :db2 && ["BLOB", "CLOB"].include?(res[:name])
         | 
| 1476 1571 | 
             
                            # HACK: 
         | 
| 1477 1572 | 
             
                            # Omit the :limit option for DB2's CLOB and BLOB types, as the
         | 
| @@ -1515,7 +1610,7 @@ begin | |
| 1515 1610 | 
             
                      # SQL_TYPE_DATE, SQL_TYPE_TIME and SQL_TYPE_TIMESTAMP.
         | 
| 1516 1611 | 
             
                      #
         | 
| 1517 1612 | 
             
                      # The conversions below are consistent with the mappings in
         | 
| 1518 | 
            -
                      # ODBCColumn# | 
| 1613 | 
            +
                      # ODBCColumn#mapSqlTypeToGenericType and Column#klass.
         | 
| 1519 1614 | 
             
                      res = value
         | 
| 1520 1615 | 
             
                      case value
         | 
| 1521 1616 | 
             
                      when ODBC::TimeStamp
         | 
| @@ -1610,8 +1705,8 @@ begin | |
| 1610 1705 | 
             
                  class ODBCColumn < Column #:nodoc:
         | 
| 1611 1706 |  | 
| 1612 1707 | 
             
                    def initialize (name, tableName, default, odbcSqlType, nativeType, 
         | 
| 1613 | 
            -
                                    null = true, limit = nil,  | 
| 1614 | 
            -
                      
         | 
| 1708 | 
            +
                                    null = true, limit = nil, scale = nil, dbExt = nil, 
         | 
| 1709 | 
            +
                                    booleanColSurrogate = nil, nativeTypes = nil)          
         | 
| 1615 1710 | 
             
                      begin
         | 
| 1616 1711 | 
             
                        require "#{dbExt}"
         | 
| 1617 1712 | 
             
                        self.extend ODBCColumnExt
         | 
| @@ -1621,24 +1716,15 @@ begin | |
| 1621 1716 |  | 
| 1622 1717 | 
             
                      @name, @null = name, null
         | 
| 1623 1718 |  | 
| 1624 | 
            -
                       | 
| 1625 | 
            -
                       | 
| 1626 | 
            -
                       | 
| 1627 | 
            -
                        typeInfo.each do |row|
         | 
| 1628 | 
            -
                          dbmsType = row[0] #SQLGetTypeInfo: TYPE_NAME
         | 
| 1629 | 
            -
                          if dbmsType.casecmp(nativeType) == 0
         | 
| 1630 | 
            -
                            createParams = row[5]
         | 
| 1631 | 
            -
                            nativeTypeTakesCreateParams = (createParams && createParams.strip.length > 0)
         | 
| 1632 | 
            -
                            break;
         | 
| 1633 | 
            -
                          end
         | 
| 1634 | 
            -
                        end        
         | 
| 1635 | 
            -
                      end
         | 
| 1636 | 
            -
                      @limit = nativeTypeTakesCreateParams ? limit : nil
         | 
| 1719 | 
            +
                      @precision = extract_precision(odbcSqlType, limit)
         | 
| 1720 | 
            +
                      @scale = extract_scale(odbcSqlType, scale)          
         | 
| 1721 | 
            +
                      @limit = limit
         | 
| 1637 1722 |  | 
| 1638 1723 | 
             
                      # nativeType is DBMS type used for column definition
         | 
| 1639 1724 | 
             
                      # sql_type assigned here excludes any length specification
         | 
| 1640 1725 | 
             
                      @sql_type = @nativeType = String.new(nativeType)
         | 
| 1641 | 
            -
                      @type =  | 
| 1726 | 
            +
                      @type = mapSqlTypeToGenericType(odbcSqlType, @nativeType, @scale, booleanColSurrogate, limit,
         | 
| 1727 | 
            +
                                  nativeTypes)
         | 
| 1642 1728 | 
             
                      # type_cast uses #type so @type must be set first
         | 
| 1643 1729 |  | 
| 1644 1730 | 
             
                      # The MS SQL Native Client ODBC driver wraps defaults in parentheses 
         | 
| @@ -1652,21 +1738,17 @@ begin | |
| 1652 1738 |  | 
| 1653 1739 | 
             
                      @default = type_cast(default)
         | 
| 1654 1740 | 
             
                      @table = tableName
         | 
| 1655 | 
            -
                      @text = [:string, :text].include? @type
         | 
| 1656 | 
            -
                      @number = [:float, :integer].include? @type
         | 
| 1657 1741 | 
             
                      @primary = nil
         | 
| 1658 1742 | 
             
                      @autounique = self.respond_to?(:autoUnique?, true) ? autoUnique? : false
         | 
| 1659 1743 | 
             
                    end
         | 
| 1660 1744 |  | 
| 1661 | 
            -
                    # Casts a value  | 
| 1662 | 
            -
                    # abstract type associated  | 
| 1745 | 
            +
                    # Casts a value (which is a String) to the Ruby class 
         | 
| 1746 | 
            +
                    # corresponding to the ActiveRecord abstract type associated 
         | 
| 1747 | 
            +
                    # with the column.
         | 
| 1663 1748 | 
             
                    #
         | 
| 1664 1749 | 
             
                    # See Column#klass for the Ruby class corresponding to each 
         | 
| 1665 1750 | 
             
                    # ActiveRecord abstract type.
         | 
| 1666 1751 | 
             
                    #
         | 
| 1667 | 
            -
                    # This method is not just called by the ODBCColumn constructor, so
         | 
| 1668 | 
            -
                    # value may be something other than a String.
         | 
| 1669 | 
            -
                    #
         | 
| 1670 1752 | 
             
                    # When casting a column's default value:
         | 
| 1671 1753 | 
             
                    #   nil => no default value specified
         | 
| 1672 1754 | 
             
                    #   "'<value>'" => string default value
         | 
| @@ -1679,67 +1761,9 @@ begin | |
| 1679 1761 | 
             
                    def type_cast(value)
         | 
| 1680 1762 | 
             
                      return nil if value.nil? || value =~ 
         | 
| 1681 1763 | 
             
            						/(^\s*[(]*\s*null\s*[)]*\s*$)|(^\s*truncated\s*$)/i
         | 
| 1682 | 
            -
                       | 
| 1683 | 
            -
                      when :string then value.to_s
         | 
| 1684 | 
            -
                      when :text then value.to_s
         | 
| 1685 | 
            -
                      when :integer then value.to_i
         | 
| 1686 | 
            -
                      when :float then value.to_f
         | 
| 1687 | 
            -
                      when :boolean then self.class.value_to_boolean(value)
         | 
| 1688 | 
            -
                      when :binary then value.to_s
         | 
| 1689 | 
            -
                      when :datetime then self.class.value_to_time(value)
         | 
| 1690 | 
            -
                      when :timestamp then self.class.value_to_time(value)        
         | 
| 1691 | 
            -
                      when :time then self.class.value_to_time(value)
         | 
| 1692 | 
            -
                      when :date then self.class.value_to_date(value)
         | 
| 1693 | 
            -
                      else
         | 
| 1694 | 
            -
                        raise  ActiveRecordError, "Unknown ActiveRecord abstract type"
         | 
| 1695 | 
            -
                      end
         | 
| 1696 | 
            -
                    end
         | 
| 1697 | 
            -
                    
         | 
| 1698 | 
            -
                    def self.value_to_time(value)
         | 
| 1699 | 
            -
                      # If we received a time literal without a date component, pad the 
         | 
| 1700 | 
            -
                      # resulting array with dummy date information.
         | 
| 1701 | 
            -
                      #
         | 
| 1702 | 
            -
                      # See Column#string_to_dummy_time and 
         | 
| 1703 | 
            -
                      # BasicsTest#test_attributes_on_dummy_time. Both assume the dummy 
         | 
| 1704 | 
            -
                      # date component will be 2000-01-01.
         | 
| 1705 | 
            -
                      if value.is_a?(Time)
         | 
| 1706 | 
            -
                        if value.year != 0 and value.month != 0 and value.day != 0
         | 
| 1707 | 
            -
                          return value
         | 
| 1708 | 
            -
                        else
         | 
| 1709 | 
            -
                          return Time.mktime(2000, 1, 1, value.hour, value.min, value.sec) rescue nil
         | 
| 1710 | 
            -
                        end
         | 
| 1711 | 
            -
                      elsif value.is_a?(String)
         | 
| 1712 | 
            -
                        time = ParseDate.parsedate(value)
         | 
| 1713 | 
            -
                        if time[0].nil? && time[1].nil? && time[2].nil?
         | 
| 1714 | 
            -
                          time[0] = 2000; time[1] = 1; time[2] = 1;
         | 
| 1715 | 
            -
                        end
         | 
| 1716 | 
            -
                        Time.send(Base.default_timezone, *time) rescue nil
         | 
| 1717 | 
            -
                      else
         | 
| 1718 | 
            -
                        raise  ActiveRecordError, "Unexpected type (#{value.class})"
         | 
| 1719 | 
            -
                      end
         | 
| 1720 | 
            -
                    end
         | 
| 1721 | 
            -
                    
         | 
| 1722 | 
            -
                    def self.value_to_date(value)
         | 
| 1723 | 
            -
                      if value.is_a?(Date)
         | 
| 1724 | 
            -
                        return value
         | 
| 1725 | 
            -
                      elsif value.is_a?(String)
         | 
| 1726 | 
            -
                        begin
         | 
| 1727 | 
            -
                          date = ParseDate.parsedate(value)
         | 
| 1728 | 
            -
                          Date.new(date[0], date[1], date[2])        
         | 
| 1729 | 
            -
                        rescue
         | 
| 1730 | 
            -
                          raise ActiveRecordError, "Cannot convert supplied String value to Date (#{value})"
         | 
| 1731 | 
            -
                        end
         | 
| 1732 | 
            -
                      elsif value.is_a?(Time)
         | 
| 1733 | 
            -
                        begin
         | 
| 1734 | 
            -
                          Date.new(value.year, value.month, value.day)
         | 
| 1735 | 
            -
                        rescue
         | 
| 1736 | 
            -
                          raise ActiveRecordError, "Cannot convert supplied Time value to Date (#{value})"
         | 
| 1737 | 
            -
                        end
         | 
| 1738 | 
            -
                      else
         | 
| 1739 | 
            -
                        raise  ActiveRecordError, "Unexpected type (#{value.class})"
         | 
| 1740 | 
            -
                      end
         | 
| 1764 | 
            +
                      super
         | 
| 1741 1765 | 
             
                    end
         | 
| 1742 | 
            -
             | 
| 1766 | 
            +
                            
         | 
| 1743 1767 | 
             
                    private
         | 
| 1744 1768 |  | 
| 1745 1769 | 
             
                    # Maps an ODBC SQL type to an ActiveRecord abstract data type
         | 
| @@ -1750,36 +1774,39 @@ begin | |
| 1750 1774 | 
             
                    # See also:
         | 
| 1751 1775 | 
             
                    # Column#klass (schema_definitions.rb) for the Ruby class corresponding
         | 
| 1752 1776 | 
             
                    # to each abstract data type.
         | 
| 1753 | 
            -
                    def  | 
| 1777 | 
            +
                    def mapSqlTypeToGenericType (odbcSqlType, nativeType, scale, 
         | 
| 1778 | 
            +
                        booleanColSurrogate, rawPrecision, nativeTypes)
         | 
| 1779 | 
            +
                      if booleanColSurrogate && booleanColSurrogate.upcase.index(nativeType.upcase)
         | 
| 1780 | 
            +
                        fullType = nativeType.dup
         | 
| 1781 | 
            +
                        if booleanColSurrogate =~ /\(\d+(,\d+)?\)/ && rawPrecision
         | 
| 1782 | 
            +
                          fullType << "(#{rawPrecision}"
         | 
| 1783 | 
            +
                          fullType << ",#{scale}" if $1 && scale
         | 
| 1784 | 
            +
                          fullType << ")"
         | 
| 1785 | 
            +
                        end
         | 
| 1786 | 
            +
                        return :boolean if fullType.casecmp(booleanColSurrogate) == 0
         | 
| 1787 | 
            +
                      end
         | 
| 1788 | 
            +
                      
         | 
| 1754 1789 | 
             
                      case odbcSqlType
         | 
| 1755 | 
            -
                      when ODBC::SQL_BIT then :boolean
         | 
| 1756 | 
            -
                        
         | 
| 1790 | 
            +
                      when ODBC::SQL_BIT then :boolean            
         | 
| 1757 1791 | 
             
                      when ODBC::SQL_CHAR, ODBC::SQL_VARCHAR then :string
         | 
| 1758 1792 | 
             
                      when ODBC::SQL_LONGVARCHAR then :text
         | 
| 1759 | 
            -
             | 
| 1760 1793 | 
             
                      when ODBC::SQL_WCHAR, ODBC::SQL_WVARCHAR then :string
         | 
| 1761 | 
            -
                      when ODBC::SQL_WLONGVARCHAR then :text
         | 
| 1762 | 
            -
                        
         | 
| 1794 | 
            +
                      when ODBC::SQL_WLONGVARCHAR then :text            
         | 
| 1763 1795 | 
             
                      when ODBC::SQL_TINYINT, ODBC::SQL_SMALLINT, ODBC::SQL_INTEGER, 
         | 
| 1764 | 
            -
                        ODBC::SQL_BIGINT then :integer
         | 
| 1765 | 
            -
                        
         | 
| 1796 | 
            +
                        ODBC::SQL_BIGINT then :integer            
         | 
| 1766 1797 | 
             
                      when ODBC::SQL_REAL, ODBC::SQL_FLOAT, ODBC::SQL_DOUBLE then :float
         | 
| 1767 | 
            -
             | 
| 1768 | 
            -
                       | 
| 1769 | 
            -
             | 
| 1770 | 
            -
                         | 
| 1771 | 
            -
                        
         | 
| 1798 | 
            +
                      # If SQLGetTypeInfo output of ODBC driver doesn't include a mapping 
         | 
| 1799 | 
            +
                      # to a native type from SQL_DECIMAL/SQL_NUMERIC, map to :float
         | 
| 1800 | 
            +
                      when ODBC::SQL_DECIMAL, ODBC::SQL_NUMERIC then scale.nil? || scale == 0 ? :integer : 
         | 
| 1801 | 
            +
                        nativeTypes[:decimal].nil? ? :float : :decimal             
         | 
| 1772 1802 | 
             
                      when ODBC::SQL_BINARY, ODBC::SQL_VARBINARY, 
         | 
| 1773 | 
            -
                        ODBC::SQL_LONGVARBINARY then :binary
         | 
| 1774 | 
            -
             | 
| 1775 | 
            -
                        # SQL_DATETIME is an alias for SQL_DATE in ODBC's sql.h & sqlext.h
         | 
| 1803 | 
            +
                        ODBC::SQL_LONGVARBINARY then :binary            
         | 
| 1804 | 
            +
                      # SQL_DATETIME is an alias for SQL_DATE in ODBC's sql.h & sqlext.h
         | 
| 1776 1805 | 
             
                      when ODBC::SQL_DATE, ODBC::SQL_TYPE_DATE, 
         | 
| 1777 1806 | 
             
                        ODBC::SQL_DATETIME then :date
         | 
| 1778 1807 | 
             
                      when ODBC::SQL_TIME, ODBC::SQL_TYPE_TIME then :time
         | 
| 1779 | 
            -
                      when ODBC::SQL_TIMESTAMP, ODBC::SQL_TYPE_TIMESTAMP then :timestamp
         | 
| 1780 | 
            -
             | 
| 1781 | 
            -
                      when ODBC::SQL_GUID then :string					
         | 
| 1782 | 
            -
                        
         | 
| 1808 | 
            +
                      when ODBC::SQL_TIMESTAMP, ODBC::SQL_TYPE_TIMESTAMP then :timestamp            
         | 
| 1809 | 
            +
                      when ODBC::SQL_GUID then :string					            
         | 
| 1783 1810 | 
             
                      else
         | 
| 1784 1811 | 
             
                        # when SQL_UNKNOWN_TYPE
         | 
| 1785 1812 | 
             
                        # (ruby-odbc driver doesn't support following ODBC SQL types:
         | 
| @@ -1788,6 +1815,22 @@ begin | |
| 1788 1815 | 
             
                        raise ActiveRecordError, msg
         | 
| 1789 1816 | 
             
                      end
         | 
| 1790 1817 | 
             
                    end
         | 
| 1818 | 
            +
             | 
| 1819 | 
            +
                    def extract_precision(odbcSqlType, odbcPrecision)
         | 
| 1820 | 
            +
                      # Ignore the ODBC precision of SQL types which don't take
         | 
| 1821 | 
            +
                      # an explicit precision when defining a column
         | 
| 1822 | 
            +
                      case odbcSqlType
         | 
| 1823 | 
            +
                        when ODBC::SQL_DECIMAL, ODBC::SQL_NUMERIC then odbcPrecision
         | 
| 1824 | 
            +
                      end
         | 
| 1825 | 
            +
                    end
         | 
| 1826 | 
            +
             | 
| 1827 | 
            +
                    def extract_scale(odbcSqlType, odbcScale)
         | 
| 1828 | 
            +
                      # Ignore the ODBC scale of SQL types which don't take
         | 
| 1829 | 
            +
                      # an explicit scale when defining a column
         | 
| 1830 | 
            +
                      case odbcSqlType
         | 
| 1831 | 
            +
                        when ODBC::SQL_DECIMAL, ODBC::SQL_NUMERIC then odbcScale ? odbcScale : 0
         | 
| 1832 | 
            +
                      end
         | 
| 1833 | 
            +
                    end
         | 
| 1791 1834 |  | 
| 1792 1835 | 
             
                  end # class ODBCColumn
         | 
| 1793 1836 |  |