odbc_adapter 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []