odbc_adapter 4.2.3 → 5.0.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.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/lib/active_record/connection_adapters/odbc_adapter.rb +6 -6
- data/lib/odbc_adapter/adapters/mysql_odbc_adapter.rb +15 -1
- data/lib/odbc_adapter/adapters/postgresql_odbc_adapter.rb +4 -4
- data/lib/odbc_adapter/column.rb +2 -17
- data/lib/odbc_adapter/database_statements.rb +17 -36
- data/lib/odbc_adapter/schema_statements.rb +45 -35
- data/lib/odbc_adapter/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a82f638f836342da6b1ef70597ad205ad869e796
|
|
4
|
+
data.tar.gz: e2f9e57124fa42ebd816ba4e3446d68c2fc06d74
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c1766ac63ef69f279469a25c47c18495e8e2aac3c9dce4a73c0b2ca73987446fef18fb91492231a8c60dd5b1ca30613744576c6f93ccd6dcb4dc41944bf04fe2
|
|
7
|
+
data.tar.gz: dc416dc3d4d359f7a6e5e5bac66fec0f08b567ffa576bbf56446d51d20dfa85836236a58cfb05811114a1d56f6fcf63ae43528d4eac4f5f697308fffea881e4a
|
data/Gemfile
CHANGED
|
@@ -83,7 +83,6 @@ module ActiveRecord
|
|
|
83
83
|
super(connection, logger)
|
|
84
84
|
@connection = connection
|
|
85
85
|
@dbms = dbms
|
|
86
|
-
@visitor = self.class::BindSubstitution.new(self)
|
|
87
86
|
end
|
|
88
87
|
|
|
89
88
|
# Returns the human-readable name of the adapter. Use mixed case - one
|
|
@@ -127,10 +126,14 @@ module ActiveRecord
|
|
|
127
126
|
@connection.disconnect if @connection.connected?
|
|
128
127
|
end
|
|
129
128
|
|
|
129
|
+
def new_column(name, default, sql_type_metadata, null, table_name, default_function = nil, collation = nil, native_type = nil)
|
|
130
|
+
::ODBCAdapter::Column.new(name, default, sql_type_metadata, null, table_name, default_function, collation, native_type)
|
|
131
|
+
end
|
|
132
|
+
|
|
130
133
|
protected
|
|
131
134
|
|
|
132
135
|
def initialize_type_map(map)
|
|
133
|
-
map.register_type
|
|
136
|
+
map.register_type 'boolean', Type::Boolean.new
|
|
134
137
|
map.register_type ODBC::SQL_CHAR, Type::String.new
|
|
135
138
|
map.register_type ODBC::SQL_LONGVARCHAR, Type::Text.new
|
|
136
139
|
map.register_type ODBC::SQL_TINYINT, Type::Integer.new(limit: 4)
|
|
@@ -149,6 +152,7 @@ module ActiveRecord
|
|
|
149
152
|
map.register_type ODBC::SQL_TIMESTAMP, Type::DateTime.new
|
|
150
153
|
map.register_type ODBC::SQL_GUID, Type::String.new
|
|
151
154
|
|
|
155
|
+
alias_type map, ODBC::SQL_BIT, 'boolean'
|
|
152
156
|
alias_type map, ODBC::SQL_VARCHAR, ODBC::SQL_CHAR
|
|
153
157
|
alias_type map, ODBC::SQL_WCHAR, ODBC::SQL_CHAR
|
|
154
158
|
alias_type map, ODBC::SQL_WVARCHAR, ODBC::SQL_CHAR
|
|
@@ -169,10 +173,6 @@ module ActiveRecord
|
|
|
169
173
|
end
|
|
170
174
|
end
|
|
171
175
|
|
|
172
|
-
def new_column(name, default, cast_type, sql_type = nil, null = true, native_type = nil, scale = nil, limit = nil)
|
|
173
|
-
::ODBCAdapter::Column.new(name, default, cast_type, sql_type, null, native_type, scale, limit)
|
|
174
|
-
end
|
|
175
|
-
|
|
176
176
|
private
|
|
177
177
|
|
|
178
178
|
def alias_type(map, new_type, old_type)
|
|
@@ -3,11 +3,25 @@ module ODBCAdapter
|
|
|
3
3
|
# Overrides specific to MySQL. Mostly taken from
|
|
4
4
|
# ActiveRecord::ConnectionAdapters::MySQLAdapter
|
|
5
5
|
class MySQLODBCAdapter < ActiveRecord::ConnectionAdapters::ODBCAdapter
|
|
6
|
+
PRIMARY_KEY = 'INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY'.freeze
|
|
7
|
+
|
|
6
8
|
class BindSubstitution < Arel::Visitors::MySQL
|
|
7
9
|
include Arel::Visitors::BindVisitor
|
|
8
10
|
end
|
|
9
11
|
|
|
10
|
-
|
|
12
|
+
def arel_visitor
|
|
13
|
+
BindSubstitution.new(self)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Explicitly turning off prepared statements in the MySQL adapter because
|
|
17
|
+
# of a weird bug with SQLDescribeParam returning a string type for LIMIT
|
|
18
|
+
# parameters. This is blocking them from running with an error:
|
|
19
|
+
#
|
|
20
|
+
# You have an error in your SQL syntax; ...
|
|
21
|
+
# ... right syntax to use near ''1'' at line 1: ...
|
|
22
|
+
def prepared_statements
|
|
23
|
+
false
|
|
24
|
+
end
|
|
11
25
|
|
|
12
26
|
def truncate(table_name, name = nil)
|
|
13
27
|
execute("TRUNCATE TABLE #{quote_table_name(table_name)}", name)
|
|
@@ -3,10 +3,6 @@ module ODBCAdapter
|
|
|
3
3
|
# Overrides specific to PostgreSQL. Mostly taken from
|
|
4
4
|
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
|
|
5
5
|
class PostgreSQLODBCAdapter < ActiveRecord::ConnectionAdapters::ODBCAdapter
|
|
6
|
-
class BindSubstitution < Arel::Visitors::PostgreSQL
|
|
7
|
-
include Arel::Visitors::BindVisitor
|
|
8
|
-
end
|
|
9
|
-
|
|
10
6
|
BOOLEAN_TYPE = 'bool'.freeze
|
|
11
7
|
PRIMARY_KEY = 'SERIAL PRIMARY KEY'.freeze
|
|
12
8
|
|
|
@@ -15,6 +11,10 @@ module ODBCAdapter
|
|
|
15
11
|
@native_database_types ||= super.merge(boolean: { name: 'bool' })
|
|
16
12
|
end
|
|
17
13
|
|
|
14
|
+
def arel_visitor
|
|
15
|
+
Arel::Visitors::PostgreSQL.new(self)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
18
|
# Filter for ODBCAdapter#tables
|
|
19
19
|
# Omits table from #tables if table_filter returns true
|
|
20
20
|
def table_filter(schema_name, table_type)
|
data/lib/odbc_adapter/column.rb
CHANGED
|
@@ -2,24 +2,9 @@ module ODBCAdapter
|
|
|
2
2
|
class Column < ActiveRecord::ConnectionAdapters::Column
|
|
3
3
|
attr_reader :native_type
|
|
4
4
|
|
|
5
|
-
def initialize(name, default,
|
|
6
|
-
|
|
7
|
-
@default = default
|
|
8
|
-
@cast_type = cast_type
|
|
9
|
-
@sql_type = sql_type
|
|
10
|
-
@null = null
|
|
5
|
+
def initialize(name, default, sql_type_metadata = nil, null = true, table_name = nil, native_type = nil, default_function = nil, collation = nil)
|
|
6
|
+
super(name, default, sql_type_metadata, null, table_name, default_function, collation)
|
|
11
7
|
@native_type = native_type
|
|
12
|
-
|
|
13
|
-
if [ODBC::SQL_DECIMAL, ODBC::SQL_NUMERIC].include?(sql_type)
|
|
14
|
-
set_numeric_params(scale, limit)
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
private
|
|
19
|
-
|
|
20
|
-
def set_numeric_params(scale, limit)
|
|
21
|
-
@cast_type.instance_variable_set(:@scale, scale || 0)
|
|
22
|
-
@cast_type.instance_variable_set(:@precision, limit)
|
|
23
8
|
end
|
|
24
9
|
end
|
|
25
10
|
end
|
|
@@ -5,32 +5,30 @@ module ODBCAdapter
|
|
|
5
5
|
SQL_NULLABLE = 1
|
|
6
6
|
SQL_NULLABLE_UNKNOWN = 2
|
|
7
7
|
|
|
8
|
-
# Returns an array of arrays containing the field values.
|
|
9
|
-
# Order is the same as that returned by #columns.
|
|
10
|
-
def select_rows(sql, name = nil)
|
|
11
|
-
log(sql, name) do
|
|
12
|
-
stmt = @connection.run(sql)
|
|
13
|
-
result = stmt.fetch_all
|
|
14
|
-
stmt.drop
|
|
15
|
-
result
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
8
|
# Executes the SQL statement in the context of this connection.
|
|
20
9
|
# Returns the number of rows affected.
|
|
21
|
-
# TODO: Currently ignoring binds until we can get prepared statements working.
|
|
22
10
|
def execute(sql, name = nil, binds = [])
|
|
23
11
|
log(sql, name) do
|
|
24
|
-
|
|
12
|
+
if prepared_statements
|
|
13
|
+
@connection.do(sql, *prepared_binds(binds))
|
|
14
|
+
else
|
|
15
|
+
@connection.do(sql)
|
|
16
|
+
end
|
|
25
17
|
end
|
|
26
18
|
end
|
|
27
19
|
|
|
28
20
|
# Executes +sql+ statement in the context of this connection using
|
|
29
21
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
|
30
22
|
# the executed +sql+ statement.
|
|
31
|
-
def exec_query(sql, name = 'SQL', binds = [])
|
|
23
|
+
def exec_query(sql, name = 'SQL', binds = [], prepare: false)
|
|
32
24
|
log(sql, name) do
|
|
33
|
-
stmt
|
|
25
|
+
stmt =
|
|
26
|
+
if prepared_statements
|
|
27
|
+
@connection.run(sql, *prepared_binds(binds))
|
|
28
|
+
else
|
|
29
|
+
@connection.run(sql)
|
|
30
|
+
end
|
|
31
|
+
|
|
34
32
|
columns = stmt.columns
|
|
35
33
|
values = stmt.to_a
|
|
36
34
|
stmt.drop
|
|
@@ -81,33 +79,12 @@ module ODBCAdapter
|
|
|
81
79
|
"#{table}_seq"
|
|
82
80
|
end
|
|
83
81
|
|
|
84
|
-
protected
|
|
85
|
-
|
|
86
|
-
# Returns the last auto-generated ID from the affected table.
|
|
87
|
-
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
|
|
88
|
-
begin
|
|
89
|
-
stmt = log(sql, name) { @connection.run(sql) }
|
|
90
|
-
table = extract_table_ref_from_insert_sql(sql)
|
|
91
|
-
|
|
92
|
-
seq = sequence_name || default_sequence_name(table, pk)
|
|
93
|
-
res = id_value || last_insert_id(table, seq, stmt)
|
|
94
|
-
ensure
|
|
95
|
-
stmt.drop unless stmt.nil?
|
|
96
|
-
end
|
|
97
|
-
res
|
|
98
|
-
end
|
|
99
|
-
|
|
100
82
|
private
|
|
101
83
|
|
|
102
84
|
def dbms_type_cast(columns, values)
|
|
103
85
|
values
|
|
104
86
|
end
|
|
105
87
|
|
|
106
|
-
def extract_table_ref_from_insert_sql(sql)
|
|
107
|
-
sql[/into\s+([^\(]*).*values\s*\(/i]
|
|
108
|
-
$1.strip if $1
|
|
109
|
-
end
|
|
110
|
-
|
|
111
88
|
# Assume received identifier is in DBMS's data dictionary case.
|
|
112
89
|
def format_case(identifier)
|
|
113
90
|
case dbms.field_for(ODBC::SQL_IDENTIFIER_CASE)
|
|
@@ -155,5 +132,9 @@ module ODBCAdapter
|
|
|
155
132
|
# So force nullability of 'id' columns
|
|
156
133
|
col_name == 'id' ? false : result
|
|
157
134
|
end
|
|
135
|
+
|
|
136
|
+
def prepared_binds(binds)
|
|
137
|
+
prepare_binds_for_database(binds).map { |bind| _type_cast(bind) }
|
|
138
|
+
end
|
|
158
139
|
end
|
|
159
140
|
end
|
|
@@ -7,16 +7,6 @@ module ODBCAdapter
|
|
|
7
7
|
@native_database_types ||= ColumnMetadata.new(self).native_database_types
|
|
8
8
|
end
|
|
9
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
|
-
|
|
16
|
-
def current_database
|
|
17
|
-
dbms.field_for(ODBC::SQL_DATABASE_NAME).strip
|
|
18
|
-
end
|
|
19
|
-
|
|
20
10
|
# Returns an array of table names, for database tables visible on the
|
|
21
11
|
# current connection.
|
|
22
12
|
def tables(_name = nil)
|
|
@@ -31,31 +21,9 @@ module ODBCAdapter
|
|
|
31
21
|
end
|
|
32
22
|
end
|
|
33
23
|
|
|
34
|
-
# Returns an array of
|
|
35
|
-
def
|
|
36
|
-
|
|
37
|
-
result = stmt.fetch_all || []
|
|
38
|
-
stmt.drop
|
|
39
|
-
|
|
40
|
-
result.each_with_object([]) do |col, cols|
|
|
41
|
-
col_name = col[3] # SQLColumns: COLUMN_NAME
|
|
42
|
-
col_default = col[12] # SQLColumns: COLUMN_DEF
|
|
43
|
-
col_sql_type = col[4] # SQLColumns: DATA_TYPE
|
|
44
|
-
col_native_type = col[5] # SQLColumns: TYPE_NAME
|
|
45
|
-
col_limit = col[6] # SQLColumns: COLUMN_SIZE
|
|
46
|
-
col_scale = col[8] # SQLColumns: DECIMAL_DIGITS
|
|
47
|
-
|
|
48
|
-
# SQLColumns: IS_NULLABLE, SQLColumns: NULLABLE
|
|
49
|
-
col_nullable = nullability(col_name, col[17], col[10])
|
|
50
|
-
|
|
51
|
-
cast_type =
|
|
52
|
-
if col_native_type == self.class::BOOLEAN_TYPE
|
|
53
|
-
ActiveRecord::Type::Boolean.new
|
|
54
|
-
else
|
|
55
|
-
lookup_cast_type(col_sql_type)
|
|
56
|
-
end
|
|
57
|
-
cols << new_column(format_case(col_name), col_default, cast_type, col_sql_type, col_nullable, col_native_type, col_scale, col_limit)
|
|
58
|
-
end
|
|
24
|
+
# Returns an array of view names defined in the database.
|
|
25
|
+
def views
|
|
26
|
+
[]
|
|
59
27
|
end
|
|
60
28
|
|
|
61
29
|
# Returns an array of indexes for the given table.
|
|
@@ -88,6 +56,37 @@ module ODBCAdapter
|
|
|
88
56
|
end
|
|
89
57
|
end
|
|
90
58
|
|
|
59
|
+
# Returns an array of Column objects for the table specified by
|
|
60
|
+
# +table_name+.
|
|
61
|
+
def columns(table_name, name = nil)
|
|
62
|
+
stmt = @connection.columns(native_case(table_name.to_s))
|
|
63
|
+
result = stmt.fetch_all || []
|
|
64
|
+
stmt.drop
|
|
65
|
+
|
|
66
|
+
result.each_with_object([]) do |col, cols|
|
|
67
|
+
col_name = col[3] # SQLColumns: COLUMN_NAME
|
|
68
|
+
col_default = col[12] # SQLColumns: COLUMN_DEF
|
|
69
|
+
col_sql_type = col[4] # SQLColumns: DATA_TYPE
|
|
70
|
+
col_native_type = col[5] # SQLColumns: TYPE_NAME
|
|
71
|
+
col_limit = col[6] # SQLColumns: COLUMN_SIZE
|
|
72
|
+
col_scale = col[8] # SQLColumns: DECIMAL_DIGITS
|
|
73
|
+
|
|
74
|
+
# SQLColumns: IS_NULLABLE, SQLColumns: NULLABLE
|
|
75
|
+
col_nullable = nullability(col_name, col[17], col[10])
|
|
76
|
+
|
|
77
|
+
args = { sql_type: col_sql_type, type: col_sql_type, limit: col_limit }
|
|
78
|
+
args[:sql_type] = 'boolean' if col_native_type == self.class::BOOLEAN_TYPE
|
|
79
|
+
|
|
80
|
+
if [ODBC::SQL_DECIMAL, ODBC::SQL_NUMERIC].include?(col_sql_type)
|
|
81
|
+
args[:scale] = col_scale || 0
|
|
82
|
+
args[:precision] = col_limit
|
|
83
|
+
end
|
|
84
|
+
sql_type_metadata = ActiveRecord::ConnectionAdapters::SqlTypeMetadata.new(**args)
|
|
85
|
+
|
|
86
|
+
cols << new_column(format_case(col_name), col_default, sql_type_metadata, col_nullable, table_name, col_native_type)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
91
90
|
# Returns just a table's primary key
|
|
92
91
|
def primary_key(table_name)
|
|
93
92
|
stmt = @connection.primary_keys(native_case(table_name.to_s))
|
|
@@ -95,5 +94,16 @@ module ODBCAdapter
|
|
|
95
94
|
stmt.drop unless stmt.nil?
|
|
96
95
|
result[0] && result[0][3]
|
|
97
96
|
end
|
|
97
|
+
|
|
98
|
+
# Ensure it's shorter than the maximum identifier length for the current
|
|
99
|
+
# dbms
|
|
100
|
+
def index_name(table_name, options)
|
|
101
|
+
maximum = dbms.field_for(ODBC::SQL_MAX_IDENTIFIER_LEN) || 255
|
|
102
|
+
super(table_name, options)[0...maximum]
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def current_database
|
|
106
|
+
dbms.field_for(ODBC::SQL_DATABASE_NAME).strip
|
|
107
|
+
end
|
|
98
108
|
end
|
|
99
109
|
end
|
data/lib/odbc_adapter/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: odbc_adapter
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 5.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Localytics
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2017-01-
|
|
11
|
+
date: 2017-01-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ruby-odbc
|