Skip to content

Commit

Permalink
Merge pull request #7 from localytics/dbms-consolidation
Browse files Browse the repository at this point in the history
Consolidate logic onto DatabaseMetadata
  • Loading branch information
kddnewton authored Feb 3, 2017
2 parents fb28e94 + 468b41f commit 6fb4c1e
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 49 deletions.
14 changes: 7 additions & 7 deletions lib/active_record/connection_adapters/odbc_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

require 'odbc_adapter/column'
require 'odbc_adapter/column_metadata'
require 'odbc_adapter/dbms'
require 'odbc_adapter/database_metadata'
require 'odbc_adapter/registry'
require 'odbc_adapter/type_caster'
require 'odbc_adapter/version'
Expand All @@ -30,8 +30,8 @@ def odbc_connection(config) # :nodoc:
raise ArgumentError, "No data source name (:dsn) or connection string (:conn_str) specified."
end

dbms = ::ODBCAdapter::DBMS.new(connection)
dbms.adapter_class.new(connection, logger, dbms)
database_metadata = ::ODBCAdapter::DatabaseMetadata.new(connection)
database_metadata.adapter_class.new(connection, logger, database_metadata)
end

private
Expand Down Expand Up @@ -78,12 +78,12 @@ class ODBCAdapter < AbstractAdapter
BOOLEAN_TYPE = 'BOOLEAN'.freeze
ERR_DUPLICATE_KEY_VALUE = 23505

attr_reader :dbms
attr_reader :database_metadata

def initialize(connection, logger, dbms)
def initialize(connection, logger, database_metadata)
super(connection, logger)
@connection = connection
@dbms = dbms
@connection = connection
@database_metadata = database_metadata
end

# Returns the human-readable name of the adapter. Use mixed case - one
Expand Down
4 changes: 2 additions & 2 deletions lib/odbc_adapter/database_limits.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ module ODBCAdapter
module DatabaseLimits
# Returns the maximum length of a table name.
def table_alias_length
max_identifier_length = dbms.field_for(ODBC::SQL_MAX_IDENTIFIER_LEN)
max_table_name_length = dbms.field_for(ODBC::SQL_MAX_TABLE_NAME_LEN)
max_identifier_length = database_metadata.max_identifier_len
max_table_name_length = database_metadata.max_table_name_len
[max_identifier_length, max_table_name_length].max
end
end
Expand Down
44 changes: 44 additions & 0 deletions lib/odbc_adapter/database_metadata.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
module ODBCAdapter
# Caches SQLGetInfo output
class DatabaseMetadata
FIELDS = %i[
SQL_DBMS_NAME
SQL_DBMS_VER
SQL_IDENTIFIER_CASE
SQL_QUOTED_IDENTIFIER_CASE
SQL_IDENTIFIER_QUOTE_CHAR
SQL_MAX_IDENTIFIER_LEN
SQL_MAX_TABLE_NAME_LEN
SQL_USER_NAME
SQL_DATABASE_NAME
]

attr_reader :values

def initialize(connection)
@values = Hash[FIELDS.map { |field| [field, connection.get_info(ODBC.const_get(field))] }]
end

def adapter_class
ODBCAdapter.adapter_for(dbms_name)
end

def upcase_identifiers?
@upcase_identifiers ||= (identifier_case == ODBC::SQL_IC_UPPER)
end

# A little bit of metaprogramming magic here to create accessors for each of
# the fields reported on by the DBMS.
FIELDS.each do |field|
define_method(field.to_s.downcase.gsub('sql_', '')) do
value_for(field)
end
end

private

def value_for(field)
values[field]
end
end
end
6 changes: 2 additions & 4 deletions lib/odbc_adapter/database_statements.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,7 @@ def dbms_type_cast(columns, values)

# Assume received identifier is in DBMS's data dictionary case.
def format_case(identifier)
case dbms.field_for(ODBC::SQL_IDENTIFIER_CASE)
when ODBC::SQL_IC_UPPER
if database_metadata.upcase_identifiers?
identifier =~ /[a-z]/ ? identifier : identifier.downcase
else
identifier
Expand All @@ -114,8 +113,7 @@ def format_case(identifier)
# Converts an identifier to the case conventions used by the DBMS.
# Assume received identifier is in ActiveRecord case.
def native_case(identifier)
case dbms.field_for(ODBC::SQL_IDENTIFIER_CASE)
when ODBC::SQL_IC_UPPER
if database_metadata.upcase_identifiers?
identifier =~ /[A-Z]/ ? identifier : identifier.upcase
else
identifier
Expand Down
30 changes: 0 additions & 30 deletions lib/odbc_adapter/dbms.rb

This file was deleted.

7 changes: 3 additions & 4 deletions lib/odbc_adapter/quoting.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,16 @@ def quote_string(string)
# Returns a quoted form of the column name.
def quote_column_name(name)
name = name.to_s
quote_char = dbms.field_for(ODBC::SQL_IDENTIFIER_QUOTE_CHAR).to_s.strip
quote_char = database_metadata.identifier_quote_char.to_s.strip

return name if quote_char.length.zero?
quote_char = quote_char[0]

# Avoid quoting any already quoted name
return name if name[0] == quote_char && name[-1] == quote_char

# If DBMS's SQL_IDENTIFIER_CASE = SQL_IC_UPPER, only quote mixed
# case names.
if dbms.field_for(ODBC::SQL_IDENTIFIER_CASE) == ODBC::SQL_IC_UPPER
# If upcase identifiers, only quote mixed case names.
if database_metadata.upcase_identifiers?
return name unless (name =~ /([A-Z]+[a-z])|([a-z]+[A-Z])/)
end

Expand Down
4 changes: 2 additions & 2 deletions lib/odbc_adapter/schema_statements.rb
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,12 @@ def primary_key(table_name)
# Ensure it's shorter than the maximum identifier length for the current
# dbms
def index_name(table_name, options)
maximum = dbms.field_for(ODBC::SQL_MAX_IDENTIFIER_LEN) || 255
maximum = database_metadata.max_identifier_len || 255
super(table_name, options)[0...maximum]
end

def current_database
dbms.field_for(ODBC::SQL_DATABASE_NAME).strip
database_metadata.database_name.strip
end
end
end

0 comments on commit 6fb4c1e

Please sign in to comment.