odbc_adapter 3.2.0

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.
@@ -0,0 +1,50 @@
1
+ module ODBCAdapter
2
+ # Caches SQLGetInfo output
3
+ class DBMS
4
+ FIELDS = [
5
+ ODBC::SQL_DBMS_NAME,
6
+ ODBC::SQL_DBMS_VER,
7
+ ODBC::SQL_IDENTIFIER_CASE,
8
+ ODBC::SQL_QUOTED_IDENTIFIER_CASE,
9
+ ODBC::SQL_IDENTIFIER_QUOTE_CHAR,
10
+ ODBC::SQL_MAX_IDENTIFIER_LEN,
11
+ ODBC::SQL_MAX_TABLE_NAME_LEN,
12
+ ODBC::SQL_USER_NAME,
13
+ ODBC::SQL_DATABASE_NAME
14
+ ]
15
+
16
+ attr_reader :fields
17
+
18
+ def initialize(connection)
19
+ @fields = Hash[FIELDS.map { |field| [field, connection.get_info(field)] }]
20
+ end
21
+
22
+ def adapter_class
23
+ return adapter unless adapter.is_a?(Symbol)
24
+ require "odbc_adapter/adapters/#{adapter.downcase}_odbc_adapter"
25
+ Adapters.const_get(:"#{adapter}ODBCAdapter")
26
+ end
27
+
28
+ def field_for(field)
29
+ fields[field]
30
+ end
31
+
32
+ private
33
+
34
+ # Maps a DBMS name to a symbol
35
+ # Different ODBC drivers might return different names for the same DBMS
36
+ def adapter
37
+ @adapter ||=
38
+ begin
39
+ reported = field_for(ODBC::SQL_DBMS_NAME).downcase.gsub(/\s/, '')
40
+ found =
41
+ ODBCAdapter.dbms_registry.detect do |pattern, adapter|
42
+ adapter if reported =~ pattern
43
+ end
44
+
45
+ raise ArgumentError, "ODBCAdapter: Unsupported database (#{reported})" if found.nil?
46
+ found.last
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,81 @@
1
+ module ODBCAdapter
2
+ module Quoting
3
+ # Quotes the column value to help prevent
4
+ # {SQL injection attacks}[http://en.wikipedia.org/wiki/SQL_injection].
5
+ def quote(value, column = nil)
6
+ # records are quoted as their primary key
7
+ return value.quoted_id if value.respond_to?(:quoted_id)
8
+
9
+ case value
10
+ when String, ActiveSupport::Multibyte::Chars
11
+ value = value.to_s
12
+ return "'#{quote_string(value)}'" unless column
13
+
14
+ case column.type
15
+ when :binary then "'#{quote_string(column.string_to_binary(value))}'"
16
+ when :integer then value.to_i.to_s
17
+ when :float then value.to_f.to_s
18
+ else
19
+ "'#{quote_string(value)}'"
20
+ end
21
+
22
+ when true, false
23
+ if column && column.type == :integer
24
+ value ? '1' : '0'
25
+ else
26
+ value ? quoted_true : quoted_false
27
+ end
28
+ # BigDecimals need to be put in a non-normalized form and quoted.
29
+ when nil then "NULL"
30
+ when BigDecimal then value.to_s('F')
31
+ when Numeric then value.to_s
32
+ when Symbol then "'#{quote_string(value.to_s)}'"
33
+ else
34
+ if value.acts_like?(:date) || value.acts_like?(:time)
35
+ quoted_date(value)
36
+ else
37
+ super
38
+ end
39
+ end
40
+ end
41
+
42
+ # Quotes a string, escaping any ' (single quote) characters.
43
+ def quote_string(string)
44
+ string.gsub(/\'/, "''")
45
+ end
46
+
47
+ # Returns a quoted form of the column name.
48
+ def quote_column_name(name)
49
+ name = name.to_s
50
+ quote_char = dbms.field_for(ODBC::SQL_IDENTIFIER_QUOTE_CHAR).to_s.strip
51
+
52
+ return name if quote_char.length.zero?
53
+ quote_char = quote_char[0]
54
+
55
+ # Avoid quoting any already quoted name
56
+ return name if name[0] == quote_char && name[-1] == quote_char
57
+
58
+ # If DBMS's SQL_IDENTIFIER_CASE = SQL_IC_UPPER, only quote mixed
59
+ # case names.
60
+ if dbms.field_for(ODBC::SQL_IDENTIFIER_CASE) == ODBC::SQL_IC_UPPER
61
+ return name unless (name =~ /([A-Z]+[a-z])|([a-z]+[A-Z])/)
62
+ end
63
+
64
+ "#{quote_char.chr}#{name}#{quote_char.chr}"
65
+ end
66
+
67
+ def quoted_true
68
+ '1'
69
+ end
70
+
71
+ # Ideally, we'd return an ODBC date or timestamp literal escape
72
+ # sequence, but not all ODBC drivers support them.
73
+ def quoted_date(value)
74
+ if value.acts_like?(:time) # Time, DateTime
75
+ "'#{value.strftime("%Y-%m-%d %H:%M:%S")}'"
76
+ else # Date
77
+ "'#{value.strftime("%Y-%m-%d")}'"
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,16 @@
1
+ module ODBCAdapter
2
+ module SchemaStatements
3
+ # Returns a Hash of mappings from the abstract data types to the native
4
+ # database types. See TableDefinition#column for details on the recognized
5
+ # abstract data types.
6
+ def native_database_types
7
+ @native_database_types ||= ColumnMetadata.new(self).native_database_types
8
+ end
9
+
10
+ # Ensure it's shorter than the maximum identifier length for the current dbms
11
+ def index_name(table_name, options)
12
+ maximum = dbms.field_for(ODBC::SQL_MAX_IDENTIFIER_LEN) || 255
13
+ super(table_name, options)[0...maximum]
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,42 @@
1
+ module ODBCAdapter
2
+ class TypeCaster
3
+ # When fetching a result set, the Ruby ODBC driver converts all ODBC
4
+ # SQL types to an equivalent Ruby type; with the exception of
5
+ # SQL_DATE, SQL_TIME and SQL_TIMESTAMP.
6
+ TYPES = [
7
+ ODBC::SQL_DATE,
8
+ ODBC::SQL_TIME,
9
+ ODBC::SQL_TIMESTAMP
10
+ ]
11
+
12
+ attr_reader :idx
13
+
14
+ def initialize(idx)
15
+ @idx = idx
16
+ end
17
+
18
+ def cast(value)
19
+ case value
20
+ when ODBC::TimeStamp
21
+ Time.gm(value.year, value.month, value.day, value.hour, value.minute, value.second)
22
+ when ODBC::Time
23
+ now = DateTime.now
24
+ Time.gm(now.year, now.month, now.day, value.hour, value.minute, value.second)
25
+ when ODBC::Date
26
+ Date.new(value.year, value.month, value.day)
27
+ else
28
+ value
29
+ end
30
+ rescue
31
+ # Handle pre-epoch dates
32
+ DateTime.new(value.year, value.month, value.day, value.hour, value.minute, value.second)
33
+ end
34
+
35
+ # Build a list of casters from a list of columns
36
+ def self.build_from(columns)
37
+ columns.each_with_index.each_with_object([]) do |(column, idx), casters|
38
+ casters << new(idx) if TYPES.include?(column.type)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,3 @@
1
+ module ODBCAdapter
2
+ VERSION = '3.2.0'
3
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'odbc_adapter/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'odbc_adapter'
8
+ spec.version = ODBCAdapter::VERSION
9
+ spec.authors = ['Localytics']
10
+ spec.email = ['oss@localytics.com']
11
+
12
+ spec.summary = 'An ActiveRecord ODBC adapter'
13
+ spec.homepage = 'https://github.com/localytics/odbc_adapter'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = 'exe'
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ['lib']
22
+
23
+ spec.add_dependency 'ruby-odbc', '~> 0.9'
24
+
25
+ spec.add_development_dependency 'bundler', '~> 1.13'
26
+ spec.add_development_dependency 'rake', '~> 10.0'
27
+ spec.add_development_dependency 'minitest', '~> 5.0'
28
+ end
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: odbc_adapter
3
+ version: !ruby/object:Gem::Version
4
+ version: 3.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Localytics
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-01-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ruby-odbc
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.9'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.9'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.13'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.13'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '5.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '5.0'
69
+ description:
70
+ email:
71
+ - oss@localytics.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".travis.yml"
78
+ - Gemfile
79
+ - LICENSE
80
+ - README.md
81
+ - Rakefile
82
+ - bin/ci-setup
83
+ - bin/console
84
+ - bin/setup
85
+ - lib/active_record/connection_adapters/odbc_adapter.rb
86
+ - lib/odbc_adapter.rb
87
+ - lib/odbc_adapter/adapters/mysql_odbc_adapter.rb
88
+ - lib/odbc_adapter/adapters/postgresql_odbc_adapter.rb
89
+ - lib/odbc_adapter/column.rb
90
+ - lib/odbc_adapter/column_metadata.rb
91
+ - lib/odbc_adapter/database_limits.rb
92
+ - lib/odbc_adapter/database_statements.rb
93
+ - lib/odbc_adapter/dbms.rb
94
+ - lib/odbc_adapter/quoting.rb
95
+ - lib/odbc_adapter/schema_statements.rb
96
+ - lib/odbc_adapter/type_caster.rb
97
+ - lib/odbc_adapter/version.rb
98
+ - odbc_adapter.gemspec
99
+ homepage: https://github.com/localytics/odbc_adapter
100
+ licenses:
101
+ - MIT
102
+ metadata: {}
103
+ post_install_message:
104
+ rdoc_options: []
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ requirements: []
118
+ rubyforge_project:
119
+ rubygems_version: 2.5.1
120
+ signing_key:
121
+ specification_version: 4
122
+ summary: An ActiveRecord ODBC adapter
123
+ test_files: []