activerecord-jdbc-adapter 50.4-java → 50.5-java
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 +4 -4
 - data/README.md +11 -9
 - data/Rakefile +29 -3
 - data/activerecord-jdbc-adapter.gemspec +1 -1
 - data/lib/arjdbc/abstract/core.rb +2 -2
 - data/lib/arjdbc/abstract/database_statements.rb +6 -0
 - data/lib/arjdbc/jdbc.rb +0 -4
 - data/lib/arjdbc/jdbc/column.rb +5 -11
 - data/lib/arjdbc/postgresql/column.rb +6 -3
 - data/lib/arjdbc/version.rb +1 -1
 - data/rakelib/02-test.rake +0 -3
 - data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +12 -1
 - data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +259 -14
 - data/src/java/arjdbc/util/DateTimeUtils.java +14 -1
 - metadata +3 -14
 - data/lib/active_record/connection_adapters/mssql_adapter.rb +0 -1
 - data/lib/active_record/connection_adapters/sqlserver_adapter.rb +0 -1
 - data/lib/arjdbc/mssql.rb +0 -7
 - data/lib/arjdbc/mssql/adapter.rb +0 -804
 - data/lib/arjdbc/mssql/column.rb +0 -200
 - data/lib/arjdbc/mssql/connection_methods.rb +0 -79
 - data/lib/arjdbc/mssql/explain_support.rb +0 -99
 - data/lib/arjdbc/mssql/limit_helpers.rb +0 -231
 - data/lib/arjdbc/mssql/lock_methods.rb +0 -77
 - data/lib/arjdbc/mssql/types.rb +0 -343
 - data/lib/arjdbc/mssql/utils.rb +0 -82
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: c4366763684412c337ad138f87ebc65f8da2d6fdaf34f4c8241eadefdb124376
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: bae02c5c8a94999cdc54dd5b570fb189b30835cbea0f5acffa2821904fed7336
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 58b61ac6c9a05c6b3a573e4c566491b61d3855f1f1285f357dc2bfc43e1db236c4224412d68afcfabc61f0cf4af71c6d56fa2b8f9cece6c7b92711cafbbeb3da
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 110de6454bcc56300fdef4d67fa449694ca78f448a211fa54f4d71711080e544be3384512fb04ad1ce383d30806f036a2c9ae188b6bd2d2a87d178753d010974
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -5,15 +5,16 @@ 
     | 
|
| 
       5 
5 
     | 
    
         
             
            ActiveRecord-JDBC-Adapter (AR-JDBC) is the main database adapter for Rails'
         
     | 
| 
       6 
6 
     | 
    
         
             
            *ActiveRecord* component that can be used with [JRuby][0].
         
     | 
| 
       7 
7 
     | 
    
         
             
            ActiveRecord-JDBC-Adapter provides full or nearly full support for:
         
     | 
| 
       8 
     | 
    
         
            -
            **MySQL**, **PostgreSQL**, **SQLite3 
     | 
| 
       9 
     | 
    
         
            -
            add support **MSSQL**. Unless we get more contributions we will not be going
         
     | 
| 
       10 
     | 
    
         
            -
            beyond these four adapters.  Note that the amount of work needed to get
         
     | 
| 
       11 
     | 
    
         
            -
            another adapter is not huge but the amount of testing required to make sure
         
     | 
| 
       12 
     | 
    
         
            -
            that adapter continues to work is not something we can do with the resources
         
     | 
| 
       13 
     | 
    
         
            -
            we currently have.
         
     | 
| 
      
 8 
     | 
    
         
            +
            **MySQL**, **PostgreSQL**, **SQLite3** and **MSSQL*** (SQLServer).
         
     | 
| 
       14 
9 
     | 
    
         | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
      
 10 
     | 
    
         
            +
            Unless we get more contributions we will not be supporting more adapters.
         
     | 
| 
      
 11 
     | 
    
         
            +
            Note that the amount of work needed to get another adapter is not huge but
         
     | 
| 
      
 12 
     | 
    
         
            +
            the amount of testing required to make sure that adapter continues to work
         
     | 
| 
      
 13 
     | 
    
         
            +
            is not something we can do with the resources we currently have.
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            - for **Oracle** database users you are encouraged to use
         
     | 
| 
      
 16 
     | 
    
         
            +
              https://github.com/rsim/oracle-enhanced
         
     | 
| 
      
 17 
     | 
    
         
            +
            - **MSSQL** adapter's gem parts reside in a [separate repository][8]
         
     | 
| 
       17 
18 
     | 
    
         | 
| 
       18 
19 
     | 
    
         
             
            Version **50.x** supports Rails version 5.0.x and it lives on branch 50-stable.
         
     | 
| 
       19 
20 
     | 
    
         
             
            Version **51.x** supports Rails version 5.1.x and is currently on master until
         
     | 
| 
         @@ -32,6 +33,7 @@ adapters are available: 
     | 
|
| 
       32 
33 
     | 
    
         
             
              - MySQL (`activerecord-jdbcmysql-adapter`)
         
     | 
| 
       33 
34 
     | 
    
         
             
              - PostgreSQL (`activerecord-jdbcpostgresql-adapter`)
         
     | 
| 
       34 
35 
     | 
    
         
             
              - SQLite3 (`activerecord-jdbcsqlite3-adapter`)
         
     | 
| 
      
 36 
     | 
    
         
            +
              - MSSQL (`activerecord-jdbcsqlserver-adapter`)
         
     | 
| 
       35 
37 
     | 
    
         | 
| 
       36 
38 
     | 
    
         
             
            2. If you're generating a new Rails application, use the following command:
         
     | 
| 
       37 
39 
     | 
    
         | 
| 
         @@ -166,4 +168,4 @@ license the database's drivers are licensed. See each driver gem's LICENSE.txt. 
     | 
|
| 
       166 
168 
     | 
    
         
             
            [5]: https://github.com/jruby/activerecord-jdbc-adapter/wiki
         
     | 
| 
       167 
169 
     | 
    
         
             
            [6]: https://webchat.freenode.net/?channels=#jruby
         
     | 
| 
       168 
170 
     | 
    
         
             
            [7]: http://badge.fury.io/rb/activerecord-jdbc-adapter
         
     | 
| 
       169 
     | 
    
         
            -
            [8]: https://github.com/jruby/activerecord- 
     | 
| 
      
 171 
     | 
    
         
            +
            [8]: https://github.com/jruby/activerecord-jdbcsqlserver-adapter
         
     | 
    
        data/Rakefile
    CHANGED
    
    | 
         @@ -1,3 +1,29 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Common usage
         
     | 
| 
      
 2 
     | 
    
         
            +
            #
         
     | 
| 
      
 3 
     | 
    
         
            +
            #   rake build:adapters - to build all specific adapter gems and the base gem
         
     | 
| 
      
 4 
     | 
    
         
            +
            #   rake release:do - build:adapters + git tag + push gems
         
     | 
| 
      
 5 
     | 
    
         
            +
            #
         
     | 
| 
      
 6 
     | 
    
         
            +
            # Environment variables used by this Rakefile:
         
     | 
| 
      
 7 
     | 
    
         
            +
            #
         
     | 
| 
      
 8 
     | 
    
         
            +
            # INCLUDE_JAR_IN_GEM [default task - false, other taks - true]:
         
     | 
| 
      
 9 
     | 
    
         
            +
            #   Note: This is something you should not normally have to set.
         
     | 
| 
      
 10 
     | 
    
         
            +
            #   For local development we always will end up including the jar file
         
     | 
| 
      
 11 
     | 
    
         
            +
            #   in any task which generates our main gem.  The wrinkle to this
         
     | 
| 
      
 12 
     | 
    
         
            +
            #   is when we do a custom github link in bundler:
         
     | 
| 
      
 13 
     | 
    
         
            +
            #
         
     | 
| 
      
 14 
     | 
    
         
            +
            #      gem 'ar-jdbc', github: '...'
         
     | 
| 
      
 15 
     | 
    
         
            +
            #
         
     | 
| 
      
 16 
     | 
    
         
            +
            #   Because we stopped committing a .jar file for every change and so when
         
     | 
| 
      
 17 
     | 
    
         
            +
            #   we  include a gem like this it clones the repository and does a default
         
     | 
| 
      
 18 
     | 
    
         
            +
            #   build in rake.  This in turn will end up forcing a compile to generate
         
     | 
| 
      
 19 
     | 
    
         
            +
            #   that jar (similar to how c-extensions compile at the time of install).
         
     | 
| 
      
 20 
     | 
    
         
            +
            #   For shipped gems we do include the jar so that people do not require
         
     | 
| 
      
 21 
     | 
    
         
            +
            #   this compile step.
         
     | 
| 
      
 22 
     | 
    
         
            +
            #
         
     | 
| 
      
 23 
     | 
    
         
            +
            # NOOP [release:do - false]
         
     | 
| 
      
 24 
     | 
    
         
            +
            #
         
     | 
| 
      
 25 
     | 
    
         
            +
            #   No commands or gem pushing during a release.
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
       1 
27 
     | 
    
         
             
            require 'rake/clean'
         
     | 
| 
       2 
28 
     | 
    
         | 
| 
       3 
29 
     | 
    
         
             
            CLEAN.include 'derby*', 'test.db.*', '*test.sqlite3', 'test/reports'
         
     | 
| 
         @@ -38,7 +64,8 @@ rake = lambda { |task| ruby "-S", "rake", task } 
     | 
|
| 
       38 
64 
     | 
    
         | 
| 
       39 
65 
     | 
    
         
             
            desc "Build #{gem_name} gem into the pkg directory."
         
     | 
| 
       40 
66 
     | 
    
         
             
            task :build => :jar do
         
     | 
| 
       41 
     | 
    
         
            -
               
     | 
| 
      
 67 
     | 
    
         
            +
              include_jar = ENV['INCLUDE_JAR_IN_GEM'] || 'true'
         
     | 
| 
      
 68 
     | 
    
         
            +
              sh("INCLUDE_JAR_IN_GEM=#{include_jar} gem build -V '#{gemspec_path}'") do
         
     | 
| 
       42 
69 
     | 
    
         
             
                gem_path = built_gem_path.call
         
     | 
| 
       43 
70 
     | 
    
         
             
                file_name = File.basename(gem_path)
         
     | 
| 
       44 
71 
     | 
    
         
             
                FileUtils.mkdir_p(File.join(base_dir, 'pkg'))
         
     | 
| 
         @@ -58,7 +85,6 @@ end 
     | 
|
| 
       58 
85 
     | 
    
         | 
| 
       59 
86 
     | 
    
         
             
            desc "Releasing AR-JDBC gems (use NOOP=true to disable gem pushing)"
         
     | 
| 
       60 
87 
     | 
    
         
             
            task 'release:do' do
         
     | 
| 
       61 
     | 
    
         
            -
              ENV['RELEASE'] = 'true' # so that .gemspec is built with adapter_java.jar
         
     | 
| 
       62 
88 
     | 
    
         
             
              Rake::Task['build'].invoke
         
     | 
| 
       63 
89 
     | 
    
         
             
              Rake::Task['build:adapters'].invoke
         
     | 
| 
       64 
90 
     | 
    
         | 
| 
         @@ -297,7 +323,7 @@ if defined? JRUBY_VERSION 
     | 
|
| 
       297 
323 
     | 
    
         
             
                  # class_files.gsub!('$', '\$') unless windows?
         
     | 
| 
       298 
324 
     | 
    
         
             
                  # args = class_files.map { |path| [ "-C #{classes_dir}", path ] }.flatten
         
     | 
| 
       299 
325 
     | 
    
         | 
| 
       300 
     | 
    
         
            -
                  if ENV[' 
     | 
| 
      
 326 
     | 
    
         
            +
                  if ENV['INCLUDE_JAR_IN_GEM'] == 'true'; require 'tempfile'
         
     | 
| 
       301 
327 
     | 
    
         
             
                    manifest  = "Built-Time: #{Time.now.utc.strftime('%Y-%m-%d %H:%M:%S')}\n"
         
     | 
| 
       302 
328 
     | 
    
         
             
                    manifest += "Built-JRuby: #{JRUBY_VERSION}\n"
         
     | 
| 
       303 
329 
     | 
    
         
             
                    manifest += "Specification-Title: ActiveRecord-JDBC\n"
         
     | 
| 
         @@ -27,7 +27,7 @@ Gem::Specification.new do |gem| 
     | 
|
| 
       27 
27 
     | 
    
         
             
                reject { |f| f =~ /^(gemfiles)/ } # no tests - no Gemfile_s appraised ...
         
     | 
| 
       28 
28 
     | 
    
         
             
              gem.files += ['lib/arjdbc/jdbc/adapter_java.jar'] #if ENV['RELEASE'].eql?('true')
         
     | 
| 
       29 
29 
     | 
    
         | 
| 
       30 
     | 
    
         
            -
              if ENV[' 
     | 
| 
      
 30 
     | 
    
         
            +
              if ENV['INCLUDE_JAR_IN_GEM'] != 'true' # @see Rakefile
         
     | 
| 
       31 
31 
     | 
    
         
             
                gem.extensions << 'Rakefile' # to support auto-building .jar with :git paths
         
     | 
| 
       32 
32 
     | 
    
         | 
| 
       33 
33 
     | 
    
         
             
                #gem.add_runtime_dependency 'jar-dependencies', '~> 0.1' # development not enough!
         
     | 
    
        data/lib/arjdbc/abstract/core.rb
    CHANGED
    
    | 
         @@ -22,7 +22,7 @@ module ArJdbc 
     | 
|
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
                    connection.configure_connection # will call us (maybe)
         
     | 
| 
       24 
24 
     | 
    
         
             
                  end
         
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
       26 
26 
     | 
    
         
             
                  # Retrieve the raw `java.sql.Connection` object.
         
     | 
| 
       27 
27 
     | 
    
         
             
                  # The unwrap parameter is useful if an attempt to unwrap a pooled (JNDI)
         
     | 
| 
       28 
28 
     | 
    
         
             
                  # connection should be made - to really return the 'native' JDBC object.
         
     | 
| 
         @@ -54,7 +54,7 @@ module ArJdbc 
     | 
|
| 
       54 
54 
     | 
    
         
             
                    case e
         
     | 
| 
       55 
55 
     | 
    
         
             
                      when SystemExit, SignalException, NoMemoryError then e
         
     | 
| 
       56 
56 
     | 
    
         
             
                      when ActiveModel::RangeError, TypeError, RuntimeError then e
         
     | 
| 
       57 
     | 
    
         
            -
                      else  
     | 
| 
      
 57 
     | 
    
         
            +
                      else super
         
     | 
| 
       58 
58 
     | 
    
         
             
                    end
         
     | 
| 
       59 
59 
     | 
    
         
             
                  end
         
     | 
| 
       60 
60 
     | 
    
         | 
| 
         @@ -10,6 +10,8 @@ module ArJdbc 
     | 
|
| 
       10 
10 
     | 
    
         
             
                  NO_BINDS = [].freeze
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
12 
     | 
    
         
             
                  def exec_insert(sql, name = nil, binds = NO_BINDS, pk = nil, sequence_name = nil)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    binds = convert_legacy_binds_to_attributes(binds) if binds.first.is_a?(Array)
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
       13 
15 
     | 
    
         
             
                    if without_prepared_statement?(binds)
         
     | 
| 
       14 
16 
     | 
    
         
             
                      log(sql, name) { @connection.execute_insert(sql) }
         
     | 
| 
       15 
17 
     | 
    
         
             
                    else
         
     | 
| 
         @@ -22,6 +24,8 @@ module ArJdbc 
     | 
|
| 
       22 
24 
     | 
    
         
             
                  # It appears that at this point (AR 5.0) "prepare" should only ever be true
         
     | 
| 
       23 
25 
     | 
    
         
             
                  # if prepared statements are enabled
         
     | 
| 
       24 
26 
     | 
    
         
             
                  def exec_query(sql, name = nil, binds = NO_BINDS, prepare: false)
         
     | 
| 
      
 27 
     | 
    
         
            +
                    binds = convert_legacy_binds_to_attributes(binds) if binds.first.is_a?(Array)
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
       25 
29 
     | 
    
         
             
                    if without_prepared_statement?(binds)
         
     | 
| 
       26 
30 
     | 
    
         
             
                      log(sql, name) { @connection.execute_query(sql) }
         
     | 
| 
       27 
31 
     | 
    
         
             
                    else
         
     | 
| 
         @@ -34,6 +38,8 @@ module ArJdbc 
     | 
|
| 
       34 
38 
     | 
    
         
             
                  end
         
     | 
| 
       35 
39 
     | 
    
         | 
| 
       36 
40 
     | 
    
         
             
                  def exec_update(sql, name = nil, binds = NO_BINDS)
         
     | 
| 
      
 41 
     | 
    
         
            +
                    binds = convert_legacy_binds_to_attributes(binds) if binds.first.is_a?(Array)
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
       37 
43 
     | 
    
         
             
                    if without_prepared_statement?(binds)
         
     | 
| 
       38 
44 
     | 
    
         
             
                      log(sql, name) { @connection.execute_update(sql) }
         
     | 
| 
       39 
45 
     | 
    
         
             
                    else
         
     | 
    
        data/lib/arjdbc/jdbc.rb
    CHANGED
    
    
    
        data/lib/arjdbc/jdbc/column.rb
    CHANGED
    
    | 
         @@ -26,23 +26,17 @@ module ActiveRecord 
     | 
|
| 
       26 
26 
     | 
    
         
             
                      end
         
     | 
| 
       27 
27 
     | 
    
         
             
                    end
         
     | 
| 
       28 
28 
     | 
    
         | 
| 
       29 
     | 
    
         
            -
                     
     | 
| 
       30 
     | 
    
         
            -
                      default = args[0].cast(default)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    default = args[0].cast(default)
         
     | 
| 
       31 
30 
     | 
    
         | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
      
 31 
     | 
    
         
            +
                    sql_type = args.delete_at(1)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    type = args.delete_at(0)
         
     | 
| 
       34 
33 
     | 
    
         | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
                    elsif ArJdbc::AR42
         
     | 
| 
       37 
     | 
    
         
            -
                      default = args[0].type_cast_from_database(default)
         
     | 
| 
       38 
     | 
    
         
            -
                    else
         
     | 
| 
       39 
     | 
    
         
            -
                      default = default_value(default)
         
     | 
| 
       40 
     | 
    
         
            -
                    end
         
     | 
| 
      
 34 
     | 
    
         
            +
                    args.unshift(SqlTypeMetadata.new(:sql_type => sql_type, :type => type))
         
     | 
| 
       41 
35 
     | 
    
         | 
| 
       42 
36 
     | 
    
         
             
                    # super <= 4.1: (name, default, sql_type = nil, null = true)
         
     | 
| 
       43 
37 
     | 
    
         
             
                    # super >= 4.2: (name, default, cast_type, sql_type = nil, null = true)
         
     | 
| 
       44 
38 
     | 
    
         
             
                    # super >= 5.0: (name, default, sql_type_metadata = nil, null = true)
         
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
       46 
40 
     | 
    
         
             
                    super(name, default, *args)
         
     | 
| 
       47 
41 
     | 
    
         
             
                    init_column(name, default, *args)
         
     | 
| 
       48 
42 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -15,7 +15,7 @@ module ArJdbc 
     | 
|
| 
       15 
15 
     | 
    
         
             
                  end
         
     | 
| 
       16 
16 
     | 
    
         | 
| 
       17 
17 
     | 
    
         
             
                  # Extracts the value from a PostgreSQL column default definition.
         
     | 
| 
       18 
     | 
    
         
            -
                  def extract_value_from_default(default) 
     | 
| 
      
 18 
     | 
    
         
            +
                  def extract_value_from_default(default)
         
     | 
| 
       19 
19 
     | 
    
         
             
                    case default
         
     | 
| 
       20 
20 
     | 
    
         
             
                      # Quoted types
         
     | 
| 
       21 
21 
     | 
    
         
             
                      when /\A[\(B]?'(.*)'.*::"?([\w. ]+)"?(?:\[\])?\z/m
         
     | 
| 
         @@ -41,10 +41,13 @@ module ArJdbc 
     | 
|
| 
       41 
41 
     | 
    
         
             
                    end
         
     | 
| 
       42 
42 
     | 
    
         
             
                  end
         
     | 
| 
       43 
43 
     | 
    
         | 
| 
       44 
     | 
    
         
            -
                  def extract_default_function(default_value, default) 
     | 
| 
       45 
     | 
    
         
            -
                    default if  
     | 
| 
      
 44 
     | 
    
         
            +
                  def extract_default_function(default_value, default)
         
     | 
| 
      
 45 
     | 
    
         
            +
                    default if has_default_function?(default_value, default)
         
     | 
| 
       46 
46 
     | 
    
         
             
                  end
         
     | 
| 
       47 
47 
     | 
    
         | 
| 
      
 48 
     | 
    
         
            +
                  def has_default_function?(default_value, default)
         
     | 
| 
      
 49 
     | 
    
         
            +
                    !default_value && %r{\w+\(.*\)|\(.*\)::\w+|CURRENT_DATE|CURRENT_TIMESTAMP} === default
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end
         
     | 
| 
       48 
51 
     | 
    
         
             
                end
         
     | 
| 
       49 
52 
     | 
    
         | 
| 
       50 
53 
     | 
    
         
             
              end
         
     | 
    
        data/lib/arjdbc/version.rb
    CHANGED
    
    
    
        data/rakelib/02-test.rake
    CHANGED
    
    | 
         @@ -58,7 +58,6 @@ end 
     | 
|
| 
       58 
58 
     | 
    
         
             
            test_task_for :Derby, :desc => 'Run tests against (embedded) DerbyDB'
         
     | 
| 
       59 
59 
     | 
    
         
             
            test_task_for :H2, :desc => 'Run tests against H2 database engine'
         
     | 
| 
       60 
60 
     | 
    
         
             
            test_task_for :HSQLDB, :desc => 'Run tests against HyperSQL (Java) database'
         
     | 
| 
       61 
     | 
    
         
            -
            test_task_for :MSSQL, :driver => :jtds, :database_name => 'MS-SQL (SQLServer)'
         
     | 
| 
       62 
61 
     | 
    
         
             
            test_task_for :MySQL #, :prereqs => 'db:mysql'
         
     | 
| 
       63 
62 
     | 
    
         
             
            task :test_mysql2 => :test_mysql
         
     | 
| 
       64 
63 
     | 
    
         
             
            test_task_for :PostgreSQL, :driver => ENV['JDBC_POSTGRES_VERSION'] || 'postgres' #, :prereqs => 'db:postgresql'
         
     | 
| 
         @@ -76,8 +75,6 @@ end 
     | 
|
| 
       76 
75 
     | 
    
         
             
              test_task_for adapter, :desc => "Run tests against #{adapter} (ensure driver is on class-path)"
         
     | 
| 
       77 
76 
     | 
    
         
             
            end
         
     | 
| 
       78 
77 
     | 
    
         | 
| 
       79 
     | 
    
         
            -
            #test_task_for :MSSQL, :name => 'test_sqlserver', :driver => nil, :database_name => 'MS-SQL using SQLJDBC'
         
     | 
| 
       80 
     | 
    
         
            -
             
     | 
| 
       81 
78 
     | 
    
         
             
            test_task_for :AS400, :desc => "Run tests against AS400 (DB2) (ensure driver is on class-path)",
         
     | 
| 
       82 
79 
     | 
    
         
             
                          :files => FileList["test/db2*_test.rb"] + FileList["test/db/db2/*_test.rb"]
         
     | 
| 
       83 
80 
     | 
    
         | 
| 
         @@ -487,7 +487,7 @@ public class RubyJdbcConnection extends RubyObject { 
     | 
|
| 
       487 
487 
     | 
    
         
             
                            savepoint = ((IRubyObject) savepoint).toJava(Savepoint.class);
         
     | 
| 
       488 
488 
     | 
    
         
             
                        }
         
     | 
| 
       489 
489 
     | 
    
         | 
| 
       490 
     | 
    
         
            -
                         
     | 
| 
      
 490 
     | 
    
         
            +
                        releaseSavepoint(connection, (Savepoint) savepoint);
         
     | 
| 
       491 
491 
     | 
    
         
             
                        return context.nil;
         
     | 
| 
       492 
492 
     | 
    
         
             
                    }
         
     | 
| 
       493 
493 
     | 
    
         
             
                    catch (SQLException e) {
         
     | 
| 
         @@ -495,6 +495,11 @@ public class RubyJdbcConnection extends RubyObject { 
     | 
|
| 
       495 
495 
     | 
    
         
             
                    }
         
     | 
| 
       496 
496 
     | 
    
         
             
                }
         
     | 
| 
       497 
497 
     | 
    
         | 
| 
      
 498 
     | 
    
         
            +
                // MSSQL doesn't support releasing savepoints so we make it possible to override the actual release action
         
     | 
| 
      
 499 
     | 
    
         
            +
                protected void releaseSavepoint(final Connection connection, final Savepoint savepoint) throws SQLException {
         
     | 
| 
      
 500 
     | 
    
         
            +
                    connection.releaseSavepoint(savepoint);
         
     | 
| 
      
 501 
     | 
    
         
            +
                }
         
     | 
| 
      
 502 
     | 
    
         
            +
             
     | 
| 
       498 
503 
     | 
    
         
             
                protected static RuntimeException newSavepointNotSetError(final ThreadContext context, final IRubyObject name, final String op) {
         
     | 
| 
       499 
504 
     | 
    
         
             
                    RubyClass StatementInvalid = ActiveRecord(context).getClass("StatementInvalid");
         
     | 
| 
       500 
505 
     | 
    
         
             
                    return context.runtime.newRaiseException(StatementInvalid, "could not " + op + " savepoint: '" + name + "' (not set)");
         
     | 
| 
         @@ -3913,6 +3918,12 @@ public class RubyJdbcConnection extends RubyObject { 
     | 
|
| 
       3913 
3918 
     | 
    
         
             
                    }
         
     | 
| 
       3914 
3919 
     | 
    
         
             
                }
         
     | 
| 
       3915 
3920 
     | 
    
         | 
| 
      
 3921 
     | 
    
         
            +
                public static void debugMessage(final ThreadContext context, final IRubyObject obj) {
         
     | 
| 
      
 3922 
     | 
    
         
            +
                    if ( isDebug(context.runtime) ) {
         
     | 
| 
      
 3923 
     | 
    
         
            +
                        debugMessage(context.runtime, obj.callMethod(context, "inspect"));
         
     | 
| 
      
 3924 
     | 
    
         
            +
                    }
         
     | 
| 
      
 3925 
     | 
    
         
            +
                }
         
     | 
| 
      
 3926 
     | 
    
         
            +
             
     | 
| 
       3916 
3927 
     | 
    
         
             
                public static void debugMessage(final Ruby runtime, final String msg, final Object e) {
         
     | 
| 
       3917 
3928 
     | 
    
         
             
                    if ( isDebug(runtime) ) {
         
     | 
| 
       3918 
3929 
     | 
    
         
             
                        final PrintStream out = runtime != null ? runtime.getOut() : System.out;
         
     | 
| 
         @@ -28,17 +28,32 @@ package arjdbc.mssql; 
     | 
|
| 
       28 
28 
     | 
    
         
             
            import arjdbc.jdbc.Callable;
         
     | 
| 
       29 
29 
     | 
    
         
             
            import arjdbc.jdbc.RubyJdbcConnection;
         
     | 
| 
       30 
30 
     | 
    
         | 
| 
      
 31 
     | 
    
         
            +
            import java.lang.reflect.InvocationTargetException;
         
     | 
| 
      
 32 
     | 
    
         
            +
            import java.lang.reflect.Method;
         
     | 
| 
       31 
33 
     | 
    
         
             
            import java.sql.Connection;
         
     | 
| 
       32 
34 
     | 
    
         
             
            import java.sql.DatabaseMetaData;
         
     | 
| 
      
 35 
     | 
    
         
            +
            import java.sql.Date;
         
     | 
| 
      
 36 
     | 
    
         
            +
            import java.sql.PreparedStatement;
         
     | 
| 
       33 
37 
     | 
    
         
             
            import java.sql.ResultSet;
         
     | 
| 
      
 38 
     | 
    
         
            +
            import java.sql.Savepoint;
         
     | 
| 
      
 39 
     | 
    
         
            +
            import java.sql.Statement;
         
     | 
| 
       34 
40 
     | 
    
         
             
            import java.sql.SQLException;
         
     | 
| 
      
 41 
     | 
    
         
            +
            import java.sql.Timestamp;
         
     | 
| 
       35 
42 
     | 
    
         
             
            import java.sql.Types;
         
     | 
| 
      
 43 
     | 
    
         
            +
            import java.util.ArrayList;
         
     | 
| 
      
 44 
     | 
    
         
            +
            import java.util.HashMap;
         
     | 
| 
      
 45 
     | 
    
         
            +
            import java.util.List;
         
     | 
| 
      
 46 
     | 
    
         
            +
            import java.util.Map;
         
     | 
| 
       36 
47 
     | 
    
         | 
| 
      
 48 
     | 
    
         
            +
            import arjdbc.util.DateTimeUtils;
         
     | 
| 
      
 49 
     | 
    
         
            +
            import org.joda.time.DateTime;
         
     | 
| 
      
 50 
     | 
    
         
            +
            import org.joda.time.DateTimeZone;
         
     | 
| 
       37 
51 
     | 
    
         
             
            import org.jruby.Ruby;
         
     | 
| 
       38 
52 
     | 
    
         
             
            import org.jruby.RubyArray;
         
     | 
| 
       39 
53 
     | 
    
         
             
            import org.jruby.RubyBoolean;
         
     | 
| 
       40 
54 
     | 
    
         
             
            import org.jruby.RubyClass;
         
     | 
| 
       41 
55 
     | 
    
         
             
            import org.jruby.RubyString;
         
     | 
| 
      
 56 
     | 
    
         
            +
            import org.jruby.RubyTime;
         
     | 
| 
       42 
57 
     | 
    
         
             
            import org.jruby.anno.JRubyMethod;
         
     | 
| 
       43 
58 
     | 
    
         
             
            import org.jruby.runtime.ObjectAllocator;
         
     | 
| 
       44 
59 
     | 
    
         
             
            import org.jruby.runtime.ThreadContext;
         
     | 
| 
         @@ -52,6 +67,53 @@ import org.jruby.util.ByteList; 
     | 
|
| 
       52 
67 
     | 
    
         
             
            public class MSSQLRubyJdbcConnection extends RubyJdbcConnection {
         
     | 
| 
       53 
68 
     | 
    
         
             
                private static final long serialVersionUID = -745716565005219263L;
         
     | 
| 
       54 
69 
     | 
    
         | 
| 
      
 70 
     | 
    
         
            +
                private static final int DATETIMEOFFSET_TYPE;
         
     | 
| 
      
 71 
     | 
    
         
            +
                private static final Method DateTimeOffsetGetMinutesOffsetMethod;
         
     | 
| 
      
 72 
     | 
    
         
            +
                private static final Method DateTimeOffsetGetTimestampMethod;
         
     | 
| 
      
 73 
     | 
    
         
            +
                private static final Method DateTimeOffsetValueOfMethod;
         
     | 
| 
      
 74 
     | 
    
         
            +
                private static final Method PreparedStatementSetDateTimeOffsetMethod;
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                private static final Map<String, Integer> MSSQL_JDBC_TYPE_FOR = new HashMap<String, Integer>(32, 1);
         
     | 
| 
      
 77 
     | 
    
         
            +
                static {
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                    Class<?> DateTimeOffset;
         
     | 
| 
      
 80 
     | 
    
         
            +
                    Class<?> MssqlPreparedStatement;
         
     | 
| 
      
 81 
     | 
    
         
            +
                    Class<?> MssqlTypes;
         
     | 
| 
      
 82 
     | 
    
         
            +
                    try {
         
     | 
| 
      
 83 
     | 
    
         
            +
                        DateTimeOffset = Class.forName("microsoft.sql.DateTimeOffset");
         
     | 
| 
      
 84 
     | 
    
         
            +
                        MssqlPreparedStatement = Class.forName("com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement");
         
     | 
| 
      
 85 
     | 
    
         
            +
                        MssqlTypes = Class.forName("microsoft.sql.Types");
         
     | 
| 
      
 86 
     | 
    
         
            +
                    } catch (ClassNotFoundException e) {
         
     | 
| 
      
 87 
     | 
    
         
            +
                        System.err.println("You must require the Microsoft JDBC driver to use this gem"); // The exception doesn't bubble when ruby is initializing
         
     | 
| 
      
 88 
     | 
    
         
            +
                        throw new RuntimeException("You must require the Microsoft JDBC driver to use this gem");
         
     | 
| 
      
 89 
     | 
    
         
            +
                    }
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                    try {
         
     | 
| 
      
 92 
     | 
    
         
            +
                        DATETIMEOFFSET_TYPE = MssqlTypes.getField("DATETIMEOFFSET").getInt(null);
         
     | 
| 
      
 93 
     | 
    
         
            +
                        DateTimeOffsetGetMinutesOffsetMethod = DateTimeOffset.getDeclaredMethod("getMinutesOffset");
         
     | 
| 
      
 94 
     | 
    
         
            +
                        DateTimeOffsetGetTimestampMethod = DateTimeOffset.getDeclaredMethod("getTimestamp");
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                        Class<?>[] valueOfArgTypes = { Timestamp.class, int.class };
         
     | 
| 
      
 97 
     | 
    
         
            +
                        DateTimeOffsetValueOfMethod = DateTimeOffset.getDeclaredMethod("valueOf", valueOfArgTypes);
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                        Class<?>[] setOffsetArgTypes = { int.class, DateTimeOffset };
         
     | 
| 
      
 100 
     | 
    
         
            +
                        PreparedStatementSetDateTimeOffsetMethod = MssqlPreparedStatement.getDeclaredMethod("setDateTimeOffset", setOffsetArgTypes);
         
     | 
| 
      
 101 
     | 
    
         
            +
                    } catch (Exception e) {
         
     | 
| 
      
 102 
     | 
    
         
            +
                        System.err.println("You must require the Microsoft JDBC driver to use this gem"); // The exception doesn't bubble when ruby is initializing
         
     | 
| 
      
 103 
     | 
    
         
            +
                        throw new RuntimeException("Please make sure you are using the latest version of the Microsoft JDBC driver");
         
     | 
| 
      
 104 
     | 
    
         
            +
                    }
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                    MSSQL_JDBC_TYPE_FOR.put("binary_basic", Types.BINARY);
         
     | 
| 
      
 107 
     | 
    
         
            +
                    MSSQL_JDBC_TYPE_FOR.put("datetimeoffset", DATETIMEOFFSET_TYPE);
         
     | 
| 
      
 108 
     | 
    
         
            +
                    MSSQL_JDBC_TYPE_FOR.put("money", Types.DECIMAL);
         
     | 
| 
      
 109 
     | 
    
         
            +
                    MSSQL_JDBC_TYPE_FOR.put("smalldatetime", Types.TIMESTAMP);
         
     | 
| 
      
 110 
     | 
    
         
            +
                    MSSQL_JDBC_TYPE_FOR.put("smallmoney", Types.DECIMAL);
         
     | 
| 
      
 111 
     | 
    
         
            +
                    MSSQL_JDBC_TYPE_FOR.put("ss_timestamp", Types.BINARY);
         
     | 
| 
      
 112 
     | 
    
         
            +
                    MSSQL_JDBC_TYPE_FOR.put("text_basic", Types.LONGVARCHAR);
         
     | 
| 
      
 113 
     | 
    
         
            +
                    MSSQL_JDBC_TYPE_FOR.put("uuid", Types.CHAR);
         
     | 
| 
      
 114 
     | 
    
         
            +
                    MSSQL_JDBC_TYPE_FOR.put("varchar_max", Types.VARCHAR);
         
     | 
| 
      
 115 
     | 
    
         
            +
                }
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
       55 
117 
     | 
    
         
             
                public MSSQLRubyJdbcConnection(Ruby runtime, RubyClass metaClass) {
         
     | 
| 
       56 
118 
     | 
    
         
             
                    super(runtime, metaClass);
         
     | 
| 
       57 
119 
     | 
    
         
             
                }
         
     | 
| 
         @@ -83,6 +145,136 @@ public class MSSQLRubyJdbcConnection extends RubyJdbcConnection { 
     | 
|
| 
       83 
145 
     | 
    
         
             
                    return context.runtime.newBoolean( startsWithIgnoreCase(sqlBytes, EXEC) );
         
     | 
| 
       84 
146 
     | 
    
         
             
                }
         
     | 
| 
       85 
147 
     | 
    
         | 
| 
      
 148 
     | 
    
         
            +
                // Support multiple result sets for mssql
         
     | 
| 
      
 149 
     | 
    
         
            +
                @Override
         
     | 
| 
      
 150 
     | 
    
         
            +
                @JRubyMethod(name = "execute", required = 1)
         
     | 
| 
      
 151 
     | 
    
         
            +
                public IRubyObject execute(final ThreadContext context, final IRubyObject sql) {
         
     | 
| 
      
 152 
     | 
    
         
            +
                    final String query = sqlString(sql);
         
     | 
| 
      
 153 
     | 
    
         
            +
                    return withConnection(context, new Callable<IRubyObject>() {
         
     | 
| 
      
 154 
     | 
    
         
            +
                        public IRubyObject call(final Connection connection) throws SQLException {
         
     | 
| 
      
 155 
     | 
    
         
            +
                            Statement statement = null;
         
     | 
| 
      
 156 
     | 
    
         
            +
                            try {
         
     | 
| 
      
 157 
     | 
    
         
            +
                                statement = createStatement(context, connection);
         
     | 
| 
      
 158 
     | 
    
         
            +
             
     | 
| 
      
 159 
     | 
    
         
            +
                                // For DBs that do support multiple statements, lets return the last result set
         
     | 
| 
      
 160 
     | 
    
         
            +
                                // to be consistent with AR
         
     | 
| 
      
 161 
     | 
    
         
            +
                                boolean hasResultSet = doExecute(statement, query);
         
     | 
| 
      
 162 
     | 
    
         
            +
                                int updateCount = statement.getUpdateCount();
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
                                final List<IRubyObject> results = new ArrayList<IRubyObject>();
         
     | 
| 
      
 165 
     | 
    
         
            +
                                ResultSet resultSet;
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
                                while (hasResultSet || updateCount != -1) {
         
     | 
| 
      
 168 
     | 
    
         
            +
             
     | 
| 
      
 169 
     | 
    
         
            +
                                    if (hasResultSet) {
         
     | 
| 
      
 170 
     | 
    
         
            +
                                        resultSet = statement.getResultSet();
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
                                        // Unfortunately the result set gets closed when getMoreResults()
         
     | 
| 
      
 173 
     | 
    
         
            +
                                        // is called, so we have to process the result sets as we get them
         
     | 
| 
      
 174 
     | 
    
         
            +
                                        // this shouldn't be an issue in most cases since we're only getting 1 result set anyways
         
     | 
| 
      
 175 
     | 
    
         
            +
                                        results.add(mapExecuteResult(context, connection, resultSet));
         
     | 
| 
      
 176 
     | 
    
         
            +
                                    } else {
         
     | 
| 
      
 177 
     | 
    
         
            +
                                        results.add(context.runtime.newFixnum(updateCount));
         
     | 
| 
      
 178 
     | 
    
         
            +
                                    }
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
                                    // Check to see if there is another result set
         
     | 
| 
      
 181 
     | 
    
         
            +
                                    hasResultSet = statement.getMoreResults();
         
     | 
| 
      
 182 
     | 
    
         
            +
                                    updateCount = statement.getUpdateCount();
         
     | 
| 
      
 183 
     | 
    
         
            +
                                }
         
     | 
| 
      
 184 
     | 
    
         
            +
             
     | 
| 
      
 185 
     | 
    
         
            +
                                if (results.size() == 0) {
         
     | 
| 
      
 186 
     | 
    
         
            +
                                    return context.nil; // If no results, return nil
         
     | 
| 
      
 187 
     | 
    
         
            +
                                } else if (results.size() == 1) {
         
     | 
| 
      
 188 
     | 
    
         
            +
                                    return results.get(0);
         
     | 
| 
      
 189 
     | 
    
         
            +
                                } else {
         
     | 
| 
      
 190 
     | 
    
         
            +
                                    return context.runtime.newArray(results);
         
     | 
| 
      
 191 
     | 
    
         
            +
                                }
         
     | 
| 
      
 192 
     | 
    
         
            +
             
     | 
| 
      
 193 
     | 
    
         
            +
                            } catch (final SQLException e) {
         
     | 
| 
      
 194 
     | 
    
         
            +
                                debugErrorSQL(context, query);
         
     | 
| 
      
 195 
     | 
    
         
            +
                                throw e;
         
     | 
| 
      
 196 
     | 
    
         
            +
                            } finally {
         
     | 
| 
      
 197 
     | 
    
         
            +
                                close(statement);
         
     | 
| 
      
 198 
     | 
    
         
            +
                            }
         
     | 
| 
      
 199 
     | 
    
         
            +
                        }
         
     | 
| 
      
 200 
     | 
    
         
            +
                    });
         
     | 
| 
      
 201 
     | 
    
         
            +
                }
         
     | 
| 
      
 202 
     | 
    
         
            +
             
     | 
| 
      
 203 
     | 
    
         
            +
                @Override
         
     | 
| 
      
 204 
     | 
    
         
            +
                protected Integer jdbcTypeFor(final String type) {
         
     | 
| 
      
 205 
     | 
    
         
            +
             
     | 
| 
      
 206 
     | 
    
         
            +
                    Integer typeValue = MSSQL_JDBC_TYPE_FOR.get(type);
         
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
      
 208 
     | 
    
         
            +
                    if ( typeValue != null ) {
         
     | 
| 
      
 209 
     | 
    
         
            +
                        return typeValue;
         
     | 
| 
      
 210 
     | 
    
         
            +
                    }
         
     | 
| 
      
 211 
     | 
    
         
            +
             
     | 
| 
      
 212 
     | 
    
         
            +
                    return super.jdbcTypeFor(type);
         
     | 
| 
      
 213 
     | 
    
         
            +
                }
         
     | 
| 
      
 214 
     | 
    
         
            +
             
     | 
| 
      
 215 
     | 
    
         
            +
                // Datetimeoffset values also make it into here
         
     | 
| 
      
 216 
     | 
    
         
            +
                @Override
         
     | 
| 
      
 217 
     | 
    
         
            +
                protected void setStringParameter(final ThreadContext context, final Connection connection,
         
     | 
| 
      
 218 
     | 
    
         
            +
                        final PreparedStatement statement, final int index, final IRubyObject value,
         
     | 
| 
      
 219 
     | 
    
         
            +
                        final IRubyObject attribute, final int type) throws SQLException {
         
     | 
| 
      
 220 
     | 
    
         
            +
             
     | 
| 
      
 221 
     | 
    
         
            +
                    // datetimeoffset values also make it in here
         
     | 
| 
      
 222 
     | 
    
         
            +
                    if (type == DATETIMEOFFSET_TYPE) {
         
     | 
| 
      
 223 
     | 
    
         
            +
             
     | 
| 
      
 224 
     | 
    
         
            +
                        Object dto = convertToDateTimeOffset(context, value);
         
     | 
| 
      
 225 
     | 
    
         
            +
             
     | 
| 
      
 226 
     | 
    
         
            +
                        try {
         
     | 
| 
      
 227 
     | 
    
         
            +
             
     | 
| 
      
 228 
     | 
    
         
            +
                            Object[] setStatementArgs = { index, dto };
         
     | 
| 
      
 229 
     | 
    
         
            +
                            PreparedStatementSetDateTimeOffsetMethod.invoke(statement, setStatementArgs);
         
     | 
| 
      
 230 
     | 
    
         
            +
             
     | 
| 
      
 231 
     | 
    
         
            +
                        } catch (IllegalAccessException e) {
         
     | 
| 
      
 232 
     | 
    
         
            +
                            debugMessage(context.runtime, e.getMessage());
         
     | 
| 
      
 233 
     | 
    
         
            +
                            throw new RuntimeException("Please make sure you are using the latest version of the Microsoft JDBC driver");
         
     | 
| 
      
 234 
     | 
    
         
            +
                        } catch (InvocationTargetException e) {
         
     | 
| 
      
 235 
     | 
    
         
            +
                            debugMessage(context.runtime, e.getMessage());
         
     | 
| 
      
 236 
     | 
    
         
            +
                            throw new RuntimeException("Please make sure you are using the latest version of the Microsoft JDBC driver");
         
     | 
| 
      
 237 
     | 
    
         
            +
                        }
         
     | 
| 
      
 238 
     | 
    
         
            +
             
     | 
| 
      
 239 
     | 
    
         
            +
                        return;
         
     | 
| 
      
 240 
     | 
    
         
            +
                    }
         
     | 
| 
      
 241 
     | 
    
         
            +
                    super.setStringParameter(context, connection, statement, index, value, attribute, type);
         
     | 
| 
      
 242 
     | 
    
         
            +
                }
         
     | 
| 
      
 243 
     | 
    
         
            +
             
     | 
| 
      
 244 
     | 
    
         
            +
                // We need higher precision than the default for Time objects (which is milliseconds) so we use a DateTimeOffset object
         
     | 
| 
      
 245 
     | 
    
         
            +
                @Override
         
     | 
| 
      
 246 
     | 
    
         
            +
                protected void setTimeParameter(final ThreadContext context,
         
     | 
| 
      
 247 
     | 
    
         
            +
                    final Connection connection, final PreparedStatement statement,
         
     | 
| 
      
 248 
     | 
    
         
            +
                    final int index, IRubyObject value,
         
     | 
| 
      
 249 
     | 
    
         
            +
                    final IRubyObject attribute, final int type) throws SQLException {
         
     | 
| 
      
 250 
     | 
    
         
            +
             
     | 
| 
      
 251 
     | 
    
         
            +
                    statement.setObject(index, convertToDateTimeOffset(context, value), Types.TIME);
         
     | 
| 
      
 252 
     | 
    
         
            +
             
     | 
| 
      
 253 
     | 
    
         
            +
                }
         
     | 
| 
      
 254 
     | 
    
         
            +
             
     | 
| 
      
 255 
     | 
    
         
            +
                private Object convertToDateTimeOffset(final ThreadContext context, final IRubyObject value) {
         
     | 
| 
      
 256 
     | 
    
         
            +
             
     | 
| 
      
 257 
     | 
    
         
            +
                    RubyTime time = (RubyTime) value;
         
     | 
| 
      
 258 
     | 
    
         
            +
                    DateTime dt = time.getDateTime();
         
     | 
| 
      
 259 
     | 
    
         
            +
                    Timestamp timestamp = new Timestamp(dt.getMillis());
         
     | 
| 
      
 260 
     | 
    
         
            +
                    timestamp.setNanos(timestamp.getNanos() + (int) time.getNSec());
         
     | 
| 
      
 261 
     | 
    
         
            +
                    int offsetMinutes = dt.getZone().getOffset(dt.getMillis()) / 60000;
         
     | 
| 
      
 262 
     | 
    
         
            +
             
     | 
| 
      
 263 
     | 
    
         
            +
                    try {
         
     | 
| 
      
 264 
     | 
    
         
            +
             
     | 
| 
      
 265 
     | 
    
         
            +
                        Object[] dtoArgs = { timestamp, offsetMinutes };
         
     | 
| 
      
 266 
     | 
    
         
            +
                        return DateTimeOffsetValueOfMethod.invoke(null, dtoArgs);
         
     | 
| 
      
 267 
     | 
    
         
            +
             
     | 
| 
      
 268 
     | 
    
         
            +
                    } catch (IllegalAccessException e) {
         
     | 
| 
      
 269 
     | 
    
         
            +
                        debugMessage(context.runtime, e.getMessage());
         
     | 
| 
      
 270 
     | 
    
         
            +
                        throw new RuntimeException("Please make sure you are using the latest version of the Microsoft JDBC driver");
         
     | 
| 
      
 271 
     | 
    
         
            +
                    } catch (InvocationTargetException e) {
         
     | 
| 
      
 272 
     | 
    
         
            +
                        debugMessage(context.runtime, e.getMessage());
         
     | 
| 
      
 273 
     | 
    
         
            +
                        throw new RuntimeException("Please make sure you are using the latest version of the Microsoft JDBC driver");
         
     | 
| 
      
 274 
     | 
    
         
            +
                    }
         
     | 
| 
      
 275 
     | 
    
         
            +
                }
         
     | 
| 
      
 276 
     | 
    
         
            +
             
     | 
| 
      
 277 
     | 
    
         
            +
             
     | 
| 
       86 
278 
     | 
    
         
             
                @Override
         
     | 
| 
       87 
279 
     | 
    
         
             
                protected RubyArray mapTables(final ThreadContext context, final Connection connection,
         
     | 
| 
       88 
280 
     | 
    
         
             
                        final String catalog, final String schemaPattern, final String tablePattern,
         
     | 
| 
         @@ -124,16 +316,79 @@ public class MSSQLRubyJdbcConnection extends RubyJdbcConnection { 
     | 
|
| 
       124 
316 
     | 
    
         | 
| 
       125 
317 
     | 
    
         
             
                /**
         
     | 
| 
       126 
318 
     | 
    
         
             
                 * Treat LONGVARCHAR as CLOB on MSSQL for purposes of converting a JDBC value to Ruby.
         
     | 
| 
      
 319 
     | 
    
         
            +
                 * Also handle datetimeoffset values here
         
     | 
| 
       127 
320 
     | 
    
         
             
                 */
         
     | 
| 
       128 
321 
     | 
    
         
             
                @Override
         
     | 
| 
       129 
322 
     | 
    
         
             
                protected IRubyObject jdbcToRuby(
         
     | 
| 
       130 
323 
     | 
    
         
             
                    final ThreadContext context, final Ruby runtime,
         
     | 
| 
       131 
324 
     | 
    
         
             
                    final int column, int type, final ResultSet resultSet)
         
     | 
| 
       132 
325 
     | 
    
         
             
                    throws SQLException {
         
     | 
| 
       133 
     | 
    
         
            -
             
     | 
| 
      
 326 
     | 
    
         
            +
             
     | 
| 
      
 327 
     | 
    
         
            +
                    if (type == DATETIMEOFFSET_TYPE) {
         
     | 
| 
      
 328 
     | 
    
         
            +
             
     | 
| 
      
 329 
     | 
    
         
            +
                        Object dto = resultSet.getObject(column); // Returns a microsoft.sql.DateTimeOffset
         
     | 
| 
      
 330 
     | 
    
         
            +
             
     | 
| 
      
 331 
     | 
    
         
            +
                        if (dto == null) return context.nil;
         
     | 
| 
      
 332 
     | 
    
         
            +
             
     | 
| 
      
 333 
     | 
    
         
            +
                        try {
         
     | 
| 
      
 334 
     | 
    
         
            +
             
     | 
| 
      
 335 
     | 
    
         
            +
                            int minutes = (int) DateTimeOffsetGetMinutesOffsetMethod.invoke(dto);
         
     | 
| 
      
 336 
     | 
    
         
            +
                            DateTimeZone zone = DateTimeZone.forOffsetHoursMinutes(minutes / 60, minutes % 60);
         
     | 
| 
      
 337 
     | 
    
         
            +
                            Timestamp ts = (Timestamp) DateTimeOffsetGetTimestampMethod.invoke(dto);
         
     | 
| 
      
 338 
     | 
    
         
            +
             
     | 
| 
      
 339 
     | 
    
         
            +
                            int nanos = ts.getNanos(); // max 999-999-999
         
     | 
| 
      
 340 
     | 
    
         
            +
                            nanos = nanos % 1000000;
         
     | 
| 
      
 341 
     | 
    
         
            +
             
     | 
| 
      
 342 
     | 
    
         
            +
                            // We have to do this differently than the newTime helper because the Timestamp loses its zone information when passed around
         
     | 
| 
      
 343 
     | 
    
         
            +
                            DateTime dateTime = new DateTime(ts.getTime(), zone);
         
     | 
| 
      
 344 
     | 
    
         
            +
                            return RubyTime.newTime(context.runtime, dateTime, nanos);
         
     | 
| 
      
 345 
     | 
    
         
            +
             
     | 
| 
      
 346 
     | 
    
         
            +
                        } catch (IllegalAccessException e) {
         
     | 
| 
      
 347 
     | 
    
         
            +
                            debugMessage(runtime, e.getMessage());
         
     | 
| 
      
 348 
     | 
    
         
            +
                            return context.nil;
         
     | 
| 
      
 349 
     | 
    
         
            +
                        } catch (InvocationTargetException e) {
         
     | 
| 
      
 350 
     | 
    
         
            +
                            debugMessage(runtime, e.getMessage());
         
     | 
| 
      
 351 
     | 
    
         
            +
                            return context.nil;
         
     | 
| 
      
 352 
     | 
    
         
            +
                        }
         
     | 
| 
      
 353 
     | 
    
         
            +
                    }
         
     | 
| 
      
 354 
     | 
    
         
            +
             
     | 
| 
      
 355 
     | 
    
         
            +
                    if (type == Types.LONGVARCHAR || type == Types.LONGNVARCHAR) type = Types.CLOB;
         
     | 
| 
       134 
356 
     | 
    
         
             
                    return super.jdbcToRuby(context, runtime, column, type, resultSet);
         
     | 
| 
       135 
357 
     | 
    
         
             
                }
         
     | 
| 
       136 
358 
     | 
    
         | 
| 
      
 359 
     | 
    
         
            +
                /**
         
     | 
| 
      
 360 
     | 
    
         
            +
                 * Converts a JDBC date object to a Ruby date by referencing Date#civil
         
     | 
| 
      
 361 
     | 
    
         
            +
                 * @param context current thread context
         
     | 
| 
      
 362 
     | 
    
         
            +
                 * @param resultSet the jdbc result set to pull the value from
         
     | 
| 
      
 363 
     | 
    
         
            +
                 * @param index the index of the column to convert
         
     | 
| 
      
 364 
     | 
    
         
            +
                 * @return RubyNil if NULL or RubyDate if there is a value
         
     | 
| 
      
 365 
     | 
    
         
            +
                 * @throws SQLException if it fails to retrieve the value from the result set
         
     | 
| 
      
 366 
     | 
    
         
            +
                 */
         
     | 
| 
      
 367 
     | 
    
         
            +
                @Override
         
     | 
| 
      
 368 
     | 
    
         
            +
                protected IRubyObject dateToRuby(ThreadContext context, Ruby runtime, ResultSet resultSet, int index) throws SQLException {
         
     | 
| 
      
 369 
     | 
    
         
            +
             
     | 
| 
      
 370 
     | 
    
         
            +
                    final Date value = resultSet.getDate(index);
         
     | 
| 
      
 371 
     | 
    
         
            +
             
     | 
| 
      
 372 
     | 
    
         
            +
                    if (value == null) return context.nil;
         
     | 
| 
      
 373 
     | 
    
         
            +
             
     | 
| 
      
 374 
     | 
    
         
            +
                    return DateTimeUtils.newDate(context, value);
         
     | 
| 
      
 375 
     | 
    
         
            +
                }
         
     | 
| 
      
 376 
     | 
    
         
            +
             
     | 
| 
      
 377 
     | 
    
         
            +
                /**
         
     | 
| 
      
 378 
     | 
    
         
            +
                 * Converts a JDBC time to a Ruby time. We use timestamp because java.sql.Time doesn't support sub-millisecond values
         
     | 
| 
      
 379 
     | 
    
         
            +
                 * @param context current thread context
         
     | 
| 
      
 380 
     | 
    
         
            +
                 * @param resultSet the jdbc result set to pull the value from
         
     | 
| 
      
 381 
     | 
    
         
            +
                 * @param index the index of the column to convert
         
     | 
| 
      
 382 
     | 
    
         
            +
                 * @return RubyNil if NULL or RubyTime if there is a value
         
     | 
| 
      
 383 
     | 
    
         
            +
                 * @throws SQLException if it fails to retrieve the value from the result set
         
     | 
| 
      
 384 
     | 
    
         
            +
                 */
         
     | 
| 
      
 385 
     | 
    
         
            +
                @Override
         
     | 
| 
      
 386 
     | 
    
         
            +
                protected IRubyObject timeToRuby(final ThreadContext context,final Ruby runtime,
         
     | 
| 
      
 387 
     | 
    
         
            +
                        final ResultSet resultSet, final int column) throws SQLException {
         
     | 
| 
      
 388 
     | 
    
         
            +
             
     | 
| 
      
 389 
     | 
    
         
            +
                    return timestampToRuby(context, runtime, resultSet, column);
         
     | 
| 
      
 390 
     | 
    
         
            +
                }
         
     | 
| 
      
 391 
     | 
    
         
            +
             
     | 
| 
       137 
392 
     | 
    
         
             
                @Override
         
     | 
| 
       138 
393 
     | 
    
         
             
                protected ColumnData[] extractColumns(final ThreadContext context,
         
     | 
| 
       139 
394 
     | 
    
         
             
                    final Connection connection, final ResultSet resultSet,
         
     | 
| 
         @@ -163,19 +418,9 @@ public class MSSQLRubyJdbcConnection extends RubyJdbcConnection { 
     | 
|
| 
       163 
418 
     | 
    
         
             
                    return columns;
         
     | 
| 
       164 
419 
     | 
    
         
             
                }
         
     | 
| 
       165 
420 
     | 
    
         | 
| 
       166 
     | 
    
         
            -
                 
     | 
| 
       167 
     | 
    
         
            -
                 
     | 
| 
       168 
     | 
    
         
            -
             
     | 
| 
       169 
     | 
    
         
            -
                    // "jTDS Type 4 JDBC Driver for MS SQL Server and Sybase"
         
     | 
| 
       170 
     | 
    
         
            -
                    // SQLJDBC: "Microsoft JDBC Driver 4.0 for SQL Server"
         
     | 
| 
       171 
     | 
    
         
            -
                    return withConnection(context, new Callable<RubyBoolean>() {
         
     | 
| 
       172 
     | 
    
         
            -
                        // NOTE: only used in one place for now (on release_savepoint) ...
         
     | 
| 
       173 
     | 
    
         
            -
                        // might get optimized to only happen once since driver won't change
         
     | 
| 
       174 
     | 
    
         
            -
                        public RubyBoolean call(final Connection connection) throws SQLException {
         
     | 
| 
       175 
     | 
    
         
            -
                            final String driver = connection.getMetaData().getDriverName();
         
     | 
| 
       176 
     | 
    
         
            -
                            return context.getRuntime().newBoolean( driver.indexOf("jTDS") >= 0 );
         
     | 
| 
       177 
     | 
    
         
            -
                        }
         
     | 
| 
       178 
     | 
    
         
            -
                    });
         
     | 
| 
      
 421 
     | 
    
         
            +
                @Override
         
     | 
| 
      
 422 
     | 
    
         
            +
                protected void releaseSavepoint(final Connection connection, final Savepoint savepoint) throws SQLException {
         
     | 
| 
      
 423 
     | 
    
         
            +
                    // MSSQL doesn't support releasing savepoints
         
     | 
| 
       179 
424 
     | 
    
         
             
                }
         
     | 
| 
       180 
425 
     | 
    
         | 
| 
       181 
426 
     | 
    
         
             
            }
         
     |