From 7e27df4852b66ef1b2a80ff08eab4ee7026b9065 Mon Sep 17 00:00:00 2001 From: Brett Warminski Date: Thu, 17 Jan 2019 16:51:32 -0500 Subject: [PATCH] Reenable Rubocop, add encoding config parameter (#29) Reenable Rubocop, add utf8 encoding config parameter --- .rubocop.yml | 1 + Rakefile | 3 +-- docker/test.sh | 3 ++- .../connection_adapters/odbc_adapter.rb | 27 ++++++++++++------- lib/odbc_adapter/database_metadata.rb | 11 ++++++-- lib/odbc_adapter/version.rb | 2 +- odbc_adapter.gemspec | 2 +- test/test_helper.rb | 2 +- 8 files changed, 34 insertions(+), 17 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 34c28c16..9055a997 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,6 +1,7 @@ AllCops: DisplayCopNames: true DisplayStyleGuide: true + TargetRubyVersion: 2.1 Exclude: - 'vendor/**/*' diff --git a/Rakefile b/Rakefile index 2d7bced8..6af9c2b8 100644 --- a/Rakefile +++ b/Rakefile @@ -9,7 +9,6 @@ Rake::TestTask.new(:test) do |t| end RuboCop::RakeTask.new(:rubocop) -# Temporarily removing as a prereq to get tests back up and working -# Rake::Task[:test].prerequisites << :rubocop +Rake::Task[:test].prerequisites << :rubocop task default: :test diff --git a/docker/test.sh b/docker/test.sh index adcd1a62..067de0c3 100755 --- a/docker/test.sh +++ b/docker/test.sh @@ -1,4 +1,5 @@ #!/bin/bash echo "Testing mysql" && CONN_STR='DRIVER=MySQL;SERVER=localhost;DATABASE=odbc_test;USER=root;PASSWORD=;' bundle exec rake && \ - echo "Testing postgres" && CONN_STR='DRIVER={PostgreSQL ANSI};SERVER=localhost;PORT=5432;DATABASE=odbc_test;UID=postgres;' bundle exec rake \ No newline at end of file + echo "Testing postgres" && CONN_STR='DRIVER={PostgreSQL ANSI};SERVER=localhost;PORT=5432;DATABASE=odbc_test;UID=postgres;' bundle exec rake && \ + echo "Testing postgres utf8" && CONN_STR='DRIVER={PostgreSQL UNICODE};SERVER=localhost;PORT=5432;DATABASE=odbc_test;UID=postgres;ENCODING=utf8' bundle exec rake \ No newline at end of file diff --git a/lib/active_record/connection_adapters/odbc_adapter.rb b/lib/active_record/connection_adapters/odbc_adapter.rb index 672c5db1..33f900a2 100644 --- a/lib/active_record/connection_adapters/odbc_adapter.rb +++ b/lib/active_record/connection_adapters/odbc_adapter.rb @@ -1,6 +1,7 @@ require 'active_record' require 'arel/visitors/bind_visitor' require 'odbc' +require 'odbc_utf8' require 'odbc_adapter/database_limits' require 'odbc_adapter/database_statements' @@ -30,7 +31,7 @@ def odbc_connection(config) raise ArgumentError, 'No data source name (:dsn) or connection string (:conn_str) specified.' end - database_metadata = ::ODBCAdapter::DatabaseMetadata.new(connection) + database_metadata = ::ODBCAdapter::DatabaseMetadata.new(connection, config[:encoding_bug]) database_metadata.adapter_class.new(connection, logger, config, database_metadata) end @@ -40,8 +41,11 @@ def odbc_connection(config) def odbc_dsn_connection(config) username = config[:username] ? config[:username].to_s : nil password = config[:password] ? config[:password].to_s : nil - connection = ODBC.connect(config[:dsn], username, password) - [connection, config.merge(username: username, password: password)] + odbc_module = config[:encoding] == 'utf8' ? ODBC_UTF8 : ODBC + connection = odbc_module.connect(config[:dsn], username, password) + + # encoding_bug indicates that the driver is using non ASCII and has the issue referenced here https://github.com/larskanis/ruby-odbc/issues/2 + [connection, config.merge(username: username, password: password, encoding_bug: config[:encoding] == 'utf8')] end # Connect using ODBC connection string @@ -49,12 +53,15 @@ def odbc_dsn_connection(config) # e.g. "DSN=virt5;UID=rails;PWD=rails" # "DRIVER={OpenLink Virtuoso};HOST=carlmbp;UID=rails;PWD=rails" def odbc_conn_str_connection(config) - driver = ODBC::Driver.new + attrs = config[:conn_str].split(';').map { |option| option.split('=', 2) }.to_h + odbc_module = attrs['ENCODING'] == 'utf8' ? ODBC_UTF8 : ODBC + driver = odbc_module::Driver.new driver.name = 'odbc' - driver.attrs = config[:conn_str].split(';').map { |option| option.split('=', 2) }.to_h + driver.attrs = attrs - connection = ODBC::Database.new.drvconnect(driver) - [connection, config.merge(driver: driver)] + connection = odbc_module::Database.new.drvconnect(driver) + # encoding_bug indicates that the driver is using non ASCII and has the issue referenced here https://github.com/larskanis/ruby-odbc/issues/2 + [connection, config.merge(driver: driver, encoding: attrs['ENCODING'], encoding_bug: attrs['ENCODING'] == 'utf8')] end end end @@ -107,11 +114,12 @@ def active? # new connection with the database. def reconnect! disconnect! + odbc_module = @config[:encoding] == 'utf8' ? ODBC_UTF8 : ODBC @connection = if @config.key?(:dsn) - ODBC.connect(@config[:dsn], @config[:username], @config[:password]) + odbc_module.connect(@config[:dsn], @config[:username], @config[:password]) else - ODBC::Database.new.drvconnect(@config[:driver]) + odbc_module::Database.new.drvconnect(@config[:driver]) end configure_time_options(@connection) super @@ -134,6 +142,7 @@ def new_column(name, default, sql_type_metadata, null, table_name, default_funct protected # Build the type map for ActiveRecord + # Here, ODBC and ODBC_UTF8 constants are interchangeable def initialize_type_map(map) map.register_type 'boolean', Type::Boolean.new map.register_type ODBC::SQL_CHAR, Type::String.new diff --git a/lib/odbc_adapter/database_metadata.rb b/lib/odbc_adapter/database_metadata.rb index f3572e9c..11fa9255 100644 --- a/lib/odbc_adapter/database_metadata.rb +++ b/lib/odbc_adapter/database_metadata.rb @@ -15,8 +15,15 @@ class DatabaseMetadata attr_reader :values - def initialize(connection) - @values = Hash[FIELDS.map { |field| [field, connection.get_info(ODBC.const_get(field))] }] + # has_encoding_bug refers to https://github.com/larskanis/ruby-odbc/issues/2 where ruby-odbc in UTF8 mode + # returns incorrectly encoded responses to getInfo + def initialize(connection, has_encoding_bug = false) + @values = Hash[FIELDS.map do |field| + info = connection.get_info(ODBC.const_get(field)) + info = info.encode(Encoding.default_external, 'UTF-16LE') if info.is_a?(String) && has_encoding_bug + + [field, info] + end] end def adapter_class diff --git a/lib/odbc_adapter/version.rb b/lib/odbc_adapter/version.rb index 693cb713..fdebf9fb 100644 --- a/lib/odbc_adapter/version.rb +++ b/lib/odbc_adapter/version.rb @@ -1,3 +1,3 @@ module ODBCAdapter - VERSION = '5.0.3'.freeze + VERSION = '5.0.4'.freeze end diff --git a/odbc_adapter.gemspec b/odbc_adapter.gemspec index d0bcd61c..4bf0142d 100644 --- a/odbc_adapter.gemspec +++ b/odbc_adapter.gemspec @@ -24,6 +24,6 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'bundler', '~> 1.14' spec.add_development_dependency 'minitest', '~> 5.10' spec.add_development_dependency 'rake', '~> 12.0' - spec.add_development_dependency 'rubocop', '~> 0.48' + spec.add_development_dependency 'rubocop', '0.48.1' spec.add_development_dependency 'simplecov', '~> 0.14' end diff --git a/test/test_helper.rb b/test/test_helper.rb index 65cc6d52..623b1960 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -42,7 +42,7 @@ class User < ActiveRecord::Base { first_name: 'Jason', last_name: 'Dsouza', letters: 11 }, { first_name: 'Ash', last_name: 'Hepburn', letters: 10 }, { first_name: 'Sharif', last_name: 'Younes', letters: 12 }, - { first_name: 'Ryan', last_name: 'Brown', letters: 9 } + { first_name: 'Ryan', last_name: 'Brüwn', letters: 9 } ] ) end