activerecord-jdbc-alt-adapter 50.3.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (198) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +35 -0
  3. data/.travis.yml +100 -0
  4. data/.yardopts +4 -0
  5. data/CONTRIBUTING.md +50 -0
  6. data/Gemfile +92 -0
  7. data/History.md +1191 -0
  8. data/LICENSE.txt +26 -0
  9. data/README.md +240 -0
  10. data/RUNNING_TESTS.md +127 -0
  11. data/Rakefile +336 -0
  12. data/Rakefile.jdbc +20 -0
  13. data/activerecord-jdbc-adapter.gemspec +55 -0
  14. data/activerecord-jdbc-alt-adapter.gemspec +56 -0
  15. data/lib/active_record/connection_adapters/as400_adapter.rb +2 -0
  16. data/lib/active_record/connection_adapters/db2_adapter.rb +1 -0
  17. data/lib/active_record/connection_adapters/derby_adapter.rb +1 -0
  18. data/lib/active_record/connection_adapters/firebird_adapter.rb +1 -0
  19. data/lib/active_record/connection_adapters/h2_adapter.rb +1 -0
  20. data/lib/active_record/connection_adapters/hsqldb_adapter.rb +1 -0
  21. data/lib/active_record/connection_adapters/informix_adapter.rb +1 -0
  22. data/lib/active_record/connection_adapters/jdbc_adapter.rb +1 -0
  23. data/lib/active_record/connection_adapters/jndi_adapter.rb +1 -0
  24. data/lib/active_record/connection_adapters/mariadb_adapter.rb +1 -0
  25. data/lib/active_record/connection_adapters/mssql_adapter.rb +1 -0
  26. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -0
  27. data/lib/active_record/connection_adapters/mysql_adapter.rb +1 -0
  28. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -0
  29. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -0
  30. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +1 -0
  31. data/lib/activerecord-jdbc-adapter.rb +1 -0
  32. data/lib/arel/visitors/compat.rb +60 -0
  33. data/lib/arel/visitors/db2.rb +137 -0
  34. data/lib/arel/visitors/derby.rb +112 -0
  35. data/lib/arel/visitors/firebird.rb +79 -0
  36. data/lib/arel/visitors/h2.rb +25 -0
  37. data/lib/arel/visitors/hsqldb.rb +32 -0
  38. data/lib/arel/visitors/postgresql_jdbc.rb +6 -0
  39. data/lib/arel/visitors/sql_server.rb +225 -0
  40. data/lib/arel/visitors/sql_server/ng42.rb +294 -0
  41. data/lib/arel/visitors/sqlserver.rb +214 -0
  42. data/lib/arjdbc.rb +19 -0
  43. data/lib/arjdbc/abstract/connection_management.rb +35 -0
  44. data/lib/arjdbc/abstract/core.rb +74 -0
  45. data/lib/arjdbc/abstract/database_statements.rb +64 -0
  46. data/lib/arjdbc/abstract/statement_cache.rb +58 -0
  47. data/lib/arjdbc/abstract/transaction_support.rb +86 -0
  48. data/lib/arjdbc/db2.rb +4 -0
  49. data/lib/arjdbc/db2/adapter.rb +789 -0
  50. data/lib/arjdbc/db2/as400.rb +130 -0
  51. data/lib/arjdbc/db2/column.rb +167 -0
  52. data/lib/arjdbc/db2/connection_methods.rb +44 -0
  53. data/lib/arjdbc/derby.rb +3 -0
  54. data/lib/arjdbc/derby/active_record_patch.rb +13 -0
  55. data/lib/arjdbc/derby/adapter.rb +540 -0
  56. data/lib/arjdbc/derby/connection_methods.rb +20 -0
  57. data/lib/arjdbc/derby/schema_creation.rb +15 -0
  58. data/lib/arjdbc/discover.rb +104 -0
  59. data/lib/arjdbc/firebird.rb +4 -0
  60. data/lib/arjdbc/firebird/adapter.rb +434 -0
  61. data/lib/arjdbc/firebird/connection_methods.rb +23 -0
  62. data/lib/arjdbc/h2.rb +3 -0
  63. data/lib/arjdbc/h2/adapter.rb +303 -0
  64. data/lib/arjdbc/h2/connection_methods.rb +27 -0
  65. data/lib/arjdbc/hsqldb.rb +3 -0
  66. data/lib/arjdbc/hsqldb/adapter.rb +297 -0
  67. data/lib/arjdbc/hsqldb/connection_methods.rb +28 -0
  68. data/lib/arjdbc/hsqldb/explain_support.rb +35 -0
  69. data/lib/arjdbc/hsqldb/schema_creation.rb +11 -0
  70. data/lib/arjdbc/informix.rb +5 -0
  71. data/lib/arjdbc/informix/adapter.rb +162 -0
  72. data/lib/arjdbc/informix/connection_methods.rb +9 -0
  73. data/lib/arjdbc/jdbc.rb +59 -0
  74. data/lib/arjdbc/jdbc/adapter.rb +475 -0
  75. data/lib/arjdbc/jdbc/adapter_require.rb +46 -0
  76. data/lib/arjdbc/jdbc/base_ext.rb +15 -0
  77. data/lib/arjdbc/jdbc/callbacks.rb +53 -0
  78. data/lib/arjdbc/jdbc/column.rb +97 -0
  79. data/lib/arjdbc/jdbc/connection.rb +14 -0
  80. data/lib/arjdbc/jdbc/connection_methods.rb +37 -0
  81. data/lib/arjdbc/jdbc/error.rb +65 -0
  82. data/lib/arjdbc/jdbc/extension.rb +59 -0
  83. data/lib/arjdbc/jdbc/java.rb +13 -0
  84. data/lib/arjdbc/jdbc/railtie.rb +2 -0
  85. data/lib/arjdbc/jdbc/rake_tasks.rb +3 -0
  86. data/lib/arjdbc/jdbc/serialized_attributes_helper.rb +3 -0
  87. data/lib/arjdbc/jdbc/type_cast.rb +166 -0
  88. data/lib/arjdbc/jdbc/type_converter.rb +142 -0
  89. data/lib/arjdbc/mssql.rb +7 -0
  90. data/lib/arjdbc/mssql/adapter.rb +384 -0
  91. data/lib/arjdbc/mssql/column.rb +29 -0
  92. data/lib/arjdbc/mssql/connection_methods.rb +79 -0
  93. data/lib/arjdbc/mssql/database_statements.rb +134 -0
  94. data/lib/arjdbc/mssql/errors.rb +6 -0
  95. data/lib/arjdbc/mssql/explain_support.rb +129 -0
  96. data/lib/arjdbc/mssql/extensions.rb +36 -0
  97. data/lib/arjdbc/mssql/limit_helpers.rb +231 -0
  98. data/lib/arjdbc/mssql/lock_methods.rb +77 -0
  99. data/lib/arjdbc/mssql/old_adapter.rb +804 -0
  100. data/lib/arjdbc/mssql/old_column.rb +200 -0
  101. data/lib/arjdbc/mssql/quoting.rb +101 -0
  102. data/lib/arjdbc/mssql/schema_creation.rb +31 -0
  103. data/lib/arjdbc/mssql/schema_definitions.rb +74 -0
  104. data/lib/arjdbc/mssql/schema_statements.rb +329 -0
  105. data/lib/arjdbc/mssql/transaction.rb +69 -0
  106. data/lib/arjdbc/mssql/types.rb +52 -0
  107. data/lib/arjdbc/mssql/types/binary_types.rb +33 -0
  108. data/lib/arjdbc/mssql/types/date_and_time_types.rb +134 -0
  109. data/lib/arjdbc/mssql/types/deprecated_types.rb +40 -0
  110. data/lib/arjdbc/mssql/types/numeric_types.rb +71 -0
  111. data/lib/arjdbc/mssql/types/string_types.rb +56 -0
  112. data/lib/arjdbc/mssql/utils.rb +66 -0
  113. data/lib/arjdbc/mysql.rb +3 -0
  114. data/lib/arjdbc/mysql/adapter.rb +140 -0
  115. data/lib/arjdbc/mysql/connection_methods.rb +166 -0
  116. data/lib/arjdbc/oracle/adapter.rb +863 -0
  117. data/lib/arjdbc/postgresql.rb +3 -0
  118. data/lib/arjdbc/postgresql/adapter.rb +687 -0
  119. data/lib/arjdbc/postgresql/base/array_decoder.rb +26 -0
  120. data/lib/arjdbc/postgresql/base/array_encoder.rb +25 -0
  121. data/lib/arjdbc/postgresql/base/array_parser.rb +95 -0
  122. data/lib/arjdbc/postgresql/base/pgconn.rb +11 -0
  123. data/lib/arjdbc/postgresql/column.rb +51 -0
  124. data/lib/arjdbc/postgresql/connection_methods.rb +67 -0
  125. data/lib/arjdbc/postgresql/name.rb +24 -0
  126. data/lib/arjdbc/postgresql/oid_types.rb +266 -0
  127. data/lib/arjdbc/railtie.rb +11 -0
  128. data/lib/arjdbc/sqlite3.rb +3 -0
  129. data/lib/arjdbc/sqlite3/adapter.rb +678 -0
  130. data/lib/arjdbc/sqlite3/connection_methods.rb +59 -0
  131. data/lib/arjdbc/sybase.rb +2 -0
  132. data/lib/arjdbc/sybase/adapter.rb +47 -0
  133. data/lib/arjdbc/tasks.rb +13 -0
  134. data/lib/arjdbc/tasks/database_tasks.rb +31 -0
  135. data/lib/arjdbc/tasks/databases.rake +48 -0
  136. data/lib/arjdbc/tasks/db2_database_tasks.rb +104 -0
  137. data/lib/arjdbc/tasks/derby_database_tasks.rb +95 -0
  138. data/lib/arjdbc/tasks/h2_database_tasks.rb +31 -0
  139. data/lib/arjdbc/tasks/hsqldb_database_tasks.rb +70 -0
  140. data/lib/arjdbc/tasks/jdbc_database_tasks.rb +169 -0
  141. data/lib/arjdbc/tasks/mssql_database_tasks.rb +46 -0
  142. data/lib/arjdbc/util/quoted_cache.rb +60 -0
  143. data/lib/arjdbc/util/serialized_attributes.rb +98 -0
  144. data/lib/arjdbc/util/table_copier.rb +110 -0
  145. data/lib/arjdbc/version.rb +3 -0
  146. data/lib/generators/jdbc/USAGE +9 -0
  147. data/lib/generators/jdbc/jdbc_generator.rb +17 -0
  148. data/lib/jdbc_adapter.rb +2 -0
  149. data/lib/jdbc_adapter/rake_tasks.rb +4 -0
  150. data/lib/jdbc_adapter/version.rb +4 -0
  151. data/pom.xml +114 -0
  152. data/rails_generators/jdbc_generator.rb +15 -0
  153. data/rails_generators/templates/config/initializers/jdbc.rb +10 -0
  154. data/rails_generators/templates/lib/tasks/jdbc.rake +11 -0
  155. data/rakelib/01-tomcat.rake +51 -0
  156. data/rakelib/02-test.rake +132 -0
  157. data/rakelib/bundler_ext.rb +11 -0
  158. data/rakelib/db.rake +75 -0
  159. data/rakelib/rails.rake +223 -0
  160. data/src/java/arjdbc/ArJdbcModule.java +276 -0
  161. data/src/java/arjdbc/db2/DB2Module.java +76 -0
  162. data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +126 -0
  163. data/src/java/arjdbc/derby/DerbyModule.java +178 -0
  164. data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +152 -0
  165. data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +174 -0
  166. data/src/java/arjdbc/h2/H2Module.java +50 -0
  167. data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +85 -0
  168. data/src/java/arjdbc/hsqldb/HSQLDBModule.java +73 -0
  169. data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +75 -0
  170. data/src/java/arjdbc/jdbc/AdapterJavaService.java +43 -0
  171. data/src/java/arjdbc/jdbc/Callable.java +44 -0
  172. data/src/java/arjdbc/jdbc/ConnectionFactory.java +45 -0
  173. data/src/java/arjdbc/jdbc/DataSourceConnectionFactory.java +156 -0
  174. data/src/java/arjdbc/jdbc/DriverConnectionFactory.java +63 -0
  175. data/src/java/arjdbc/jdbc/DriverWrapper.java +119 -0
  176. data/src/java/arjdbc/jdbc/JdbcResult.java +130 -0
  177. data/src/java/arjdbc/jdbc/RubyConnectionFactory.java +61 -0
  178. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +3979 -0
  179. data/src/java/arjdbc/mssql/MSSQLModule.java +90 -0
  180. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +508 -0
  181. data/src/java/arjdbc/mysql/MySQLModule.java +152 -0
  182. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +294 -0
  183. data/src/java/arjdbc/oracle/OracleModule.java +80 -0
  184. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +455 -0
  185. data/src/java/arjdbc/postgresql/ByteaUtils.java +157 -0
  186. data/src/java/arjdbc/postgresql/PgDateTimeUtils.java +52 -0
  187. data/src/java/arjdbc/postgresql/PostgreSQLModule.java +77 -0
  188. data/src/java/arjdbc/postgresql/PostgreSQLResult.java +192 -0
  189. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +948 -0
  190. data/src/java/arjdbc/sqlite3/SQLite3Module.java +73 -0
  191. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +525 -0
  192. data/src/java/arjdbc/util/CallResultSet.java +826 -0
  193. data/src/java/arjdbc/util/DateTimeUtils.java +699 -0
  194. data/src/java/arjdbc/util/ObjectSupport.java +65 -0
  195. data/src/java/arjdbc/util/QuotingUtils.java +137 -0
  196. data/src/java/arjdbc/util/StringCache.java +63 -0
  197. data/src/java/arjdbc/util/StringHelper.java +145 -0
  198. metadata +269 -0
@@ -0,0 +1,142 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ # I want to use JDBC's DatabaseMetaData#getTypeInfo to choose the best native types to
4
+ # use for ActiveRecord's Adapter#native_database_types in a database-independent way,
5
+ # but apparently a database driver can return multiple types for a given
6
+ # java.sql.Types constant. So this type converter uses some heuristics to try to pick
7
+ # the best (most common) type to use. It's not great, it would be better to just
8
+ # delegate to each database's existing AR adapter's native_database_types method, but I
9
+ # wanted to try to do this in a way that didn't pull in all the other adapters as
10
+ # dependencies. Improvements appreciated.
11
+ class JdbcTypeConverter
12
+
13
+ # @private
14
+ TEXT_TYPES = [ Jdbc::Types::LONGVARCHAR, Jdbc::Types::CLOB ]
15
+ private_constant :TEXT_TYPES if respond_to? :private_constant
16
+
17
+ # @private
18
+ FLOAT_TYPES = [ Jdbc::Types::FLOAT, Jdbc::Types::DOUBLE, Jdbc::Types::REAL ]
19
+ private_constant :FLOAT_TYPES if respond_to? :private_constant
20
+
21
+ # @private
22
+ BINARY_TYPES = [ Jdbc::Types::LONGVARBINARY,Jdbc::Types::BINARY,Jdbc::Types::BLOB ]
23
+ private_constant :BINARY_TYPES if respond_to? :private_constant
24
+
25
+ # The basic ActiveRecord types, mapped to an array of procs that are used to #select
26
+ # the best type. The procs are used as selectors in order until there is only one
27
+ # type left. If all the selectors are applied and there is still more than one
28
+ # type, an exception will be raised.
29
+ AR_TO_JDBC_TYPES = {
30
+ :string => [ lambda {|r| Jdbc::Types::VARCHAR == r['data_type'].to_i},
31
+ lambda {|r| r['type_name'] =~ /^varchar/i},
32
+ lambda {|r| r['type_name'] =~ /^varchar$/i},
33
+ lambda {|r| r['type_name'] =~ /varying/i}],
34
+ :text => [ lambda {|r| TEXT_TYPES.include?(r['data_type'].to_i)},
35
+ lambda {|r| r['type_name'] =~ /^text$/i}, # For Informix
36
+ lambda {|r| r['type_name'] =~ /sub_type 1$/i}, # For FireBird
37
+ lambda {|r| r['type_name'] =~ /^(text|clob)$/i},
38
+ lambda {|r| r['type_name'] =~ /^character large object$/i},
39
+ lambda {|r| r['sql_data_type'] == 2005}],
40
+ :integer => [ lambda {|r| Jdbc::Types::INTEGER == r['data_type'].to_i},
41
+ lambda {|r| r['type_name'] =~ /^integer$/i},
42
+ lambda {|r| r['type_name'] =~ /^int4$/i},
43
+ lambda {|r| r['type_name'] =~ /^int$/i}],
44
+ :decimal => [ lambda {|r| Jdbc::Types::DECIMAL == r['data_type'].to_i},
45
+ lambda {|r| r['type_name'] =~ /^decimal$/i},
46
+ lambda {|r| r['type_name'] =~ /^numeric$/i},
47
+ lambda {|r| r['type_name'] =~ /^number$/i},
48
+ lambda {|r| r['type_name'] =~ /^real$/i},
49
+ lambda {|r| r['precision'] == '38'},
50
+ lambda {|r| r['data_type'].to_i == Jdbc::Types::DECIMAL}],
51
+ :float => [ lambda {|r| FLOAT_TYPES.include?(r['data_type'].to_i)},
52
+ lambda {|r| r['data_type'].to_i == Jdbc::Types::REAL}, #Prefer REAL to DOUBLE for Postgresql
53
+ lambda {|r| r['type_name'] =~ /^float/i},
54
+ lambda {|r| r['type_name'] =~ /^double$/i},
55
+ lambda {|r| r['type_name'] =~ /^real$/i},
56
+ lambda {|r| r['precision'] == '15'}],
57
+ :datetime => [ lambda {|r| Jdbc::Types::TIMESTAMP == r['data_type'].to_i},
58
+ lambda {|r| r['type_name'] =~ /^datetime$/i},
59
+ lambda {|r| r['type_name'] =~ /^timestamp$/i},
60
+ lambda {|r| r['type_name'] =~ /^datetime.+/i},
61
+ lambda {|r| r['type_name'] =~ /^date/i},
62
+ lambda {|r| r['type_name'] =~ /^integer/i}], #Num of milliseconds for SQLite3 JDBC Driver
63
+ :timestamp => [ lambda {|r| Jdbc::Types::TIMESTAMP == r['data_type'].to_i},
64
+ lambda {|r| r['type_name'] =~ /^timestamp$/i},
65
+ lambda {|r| r['type_name'] =~ /^datetime$/i},
66
+ lambda {|r| r['type_name'] =~ /^datetime.+/i},
67
+ lambda {|r| r['type_name'] =~ /^date/i},
68
+ lambda {|r| r['type_name'] =~ /^integer/i}], #Num of milliseconds for SQLite3 JDBC Driver
69
+ :time => [ lambda {|r| Jdbc::Types::TIME == r['data_type'].to_i},
70
+ lambda {|r| r['type_name'] =~ /^time$/i},
71
+ lambda {|r| r['type_name'] =~ /^datetime$/i},
72
+ lambda {|r| r['type_name'] =~ /^datetime.+/i}, # For Informix
73
+ lambda {|r| r['type_name'] =~ /^date/i},
74
+ lambda {|r| r['type_name'] =~ /^integer/i}], #Num of milliseconds for SQLite3 JDBC Driver
75
+ :date => [ lambda {|r| Jdbc::Types::DATE == r['data_type'].to_i},
76
+ lambda {|r| r['type_name'] =~ /^date$/i},
77
+ lambda {|r| r['type_name'] =~ /^date/i},
78
+ lambda {|r| r['type_name'] =~ /^integer/i}], #Num of milliseconds for SQLite3 JDBC Driver3
79
+ :binary => [ lambda {|r| BINARY_TYPES.include?(r['data_type'].to_i)},
80
+ lambda {|r| r['type_name'] =~ /^blob/i},
81
+ lambda {|r| r['type_name'] =~ /sub_type 0$/i}, # For FireBird
82
+ lambda {|r| r['type_name'] =~ /^varbinary$/i}, # We want this sucker for Mimer
83
+ lambda {|r| r['type_name'] =~ /^binary$/i}, ],
84
+ :boolean => [ lambda {|r| Jdbc::Types::BIT == r['data_type'].to_i && r['precision'].to_i == 1},
85
+ lambda {|r| Jdbc::Types::TINYINT == r['data_type'].to_i},
86
+ lambda {|r| r['type_name'] =~ /^bool/i},
87
+ lambda {|r| r['data_type'].to_i == Jdbc::Types::BIT},
88
+ lambda {|r| r['type_name'] =~ /^tinyint$/i},
89
+ lambda {|r| r['type_name'] =~ /^decimal$/i},
90
+ lambda {|r| r['type_name'] =~ /^integer$/i}]
91
+ }
92
+
93
+ def initialize(types)
94
+ @types = types
95
+ @types.each {|t| t['type_name'] ||= t['local_type_name']} # Sybase driver seems to want 'local_type_name'
96
+ end
97
+
98
+ def choose_best_types
99
+ type_map = {}
100
+ @types.each do |row|
101
+ name = row['type_name'].downcase
102
+ k = name.to_sym
103
+ type_map[k] = { :name => name }
104
+ set_limit_to_nonzero_precision(type_map[k], row)
105
+ end
106
+
107
+ AR_TO_JDBC_TYPES.keys.each do |ar_type|
108
+ typerow = choose_type(ar_type)
109
+ type_map[ar_type] = { :name => typerow['type_name'].downcase }
110
+ case ar_type
111
+ when :integer, :string, :decimal
112
+ set_limit_to_nonzero_precision(type_map[ar_type], typerow)
113
+ when :boolean
114
+ type_map[ar_type][:limit] = 1
115
+ end
116
+ end
117
+ type_map
118
+ end
119
+
120
+ def choose_type(ar_type)
121
+ types = @types
122
+ AR_TO_JDBC_TYPES[ar_type].each do |proc|
123
+ new_types = types.reject {|r| r["data_type"].to_i == Jdbc::Types::OTHER}
124
+ new_types = new_types.select(&proc)
125
+ new_types = new_types.inject([]) do |typs,t|
126
+ typs << t unless typs.detect {|el| el['type_name'] == t['type_name']}
127
+ typs
128
+ end
129
+ return new_types.first if new_types.length == 1
130
+ types = new_types if new_types.length > 0
131
+ end
132
+ raise "unable to choose type for #{ar_type} from:\n#{types.collect{|t| t['type_name']}.inspect}"
133
+ end
134
+
135
+ def set_limit_to_nonzero_precision(map, row)
136
+ if row['precision'] && row['precision'].to_i > 0
137
+ map[:limit] = row['precision'].to_i
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,7 @@
1
+ require 'arjdbc'
2
+ require 'arjdbc/mssql/adapter'
3
+ require 'arjdbc/mssql/connection_methods'
4
+ module ArJdbc
5
+ MsSQL = MSSQL # compatibility with 1.2
6
+ end
7
+ ArJdbc.warn_unsupported_adapter 'mssql', [5, 0] # warns on AR >= 4.2
@@ -0,0 +1,384 @@
1
+ # frozen_string_literal: false
2
+
3
+ ArJdbc.load_java_part :MSSQL
4
+
5
+ require 'arel'
6
+ require 'arel/visitors/bind_visitor'
7
+ require 'arel/visitors/sqlserver'
8
+ require 'active_record/connection_adapters/abstract_adapter'
9
+
10
+ require 'arjdbc/abstract/core'
11
+ require 'arjdbc/abstract/connection_management'
12
+ require 'arjdbc/abstract/database_statements'
13
+ require 'arjdbc/abstract/statement_cache'
14
+ require 'arjdbc/abstract/transaction_support'
15
+
16
+ require 'arjdbc/mssql/column'
17
+ require 'arjdbc/mssql/types'
18
+ require 'arjdbc/mssql/quoting'
19
+ require 'arjdbc/mssql/schema_definitions'
20
+ require 'arjdbc/mssql/schema_statements'
21
+ require 'arjdbc/mssql/database_statements'
22
+ require 'arjdbc/mssql/explain_support'
23
+ require 'arjdbc/mssql/extensions'
24
+ require 'arjdbc/mssql/transaction'
25
+ require 'arjdbc/mssql/errors'
26
+ require 'arjdbc/mssql/schema_creation'
27
+
28
+ module ActiveRecord
29
+ module ConnectionAdapters
30
+ # MSSQL (SQLServer) adapter class definition
31
+ class MSSQLAdapter < AbstractAdapter
32
+ ADAPTER_NAME = 'MSSQL'.freeze
33
+
34
+ MSSQL_VERSION_YEAR = {
35
+ 8 => '2000',
36
+ 9 => '2005',
37
+ 10 => '2008',
38
+ 11 => '2012',
39
+ 12 => '2014',
40
+ 13 => '2016',
41
+ 14 => '2017',
42
+ 15 => '2019'
43
+ }.freeze
44
+
45
+ include Jdbc::ConnectionPoolCallbacks
46
+ include ArJdbc::Abstract::Core
47
+ include ArJdbc::Abstract::ConnectionManagement
48
+ include ArJdbc::Abstract::DatabaseStatements
49
+ include ArJdbc::Abstract::StatementCache
50
+ include ArJdbc::Abstract::TransactionSupport
51
+
52
+ include MSSQL::Quoting
53
+ include MSSQL::SchemaStatements
54
+ include MSSQL::DatabaseStatements
55
+ include MSSQL::ExplainSupport
56
+
57
+ @cs_equality_operator = 'COLLATE Latin1_General_CS_AS_WS'
58
+
59
+ class << self
60
+ attr_accessor :cs_equality_operator
61
+ end
62
+
63
+ def initialize(connection, logger, _connection_parameters, config = {})
64
+ # configure_connection happens in super
65
+ super(connection, logger, config)
66
+
67
+ unless mssql_major_version >= 11
68
+ raise "Your MSSQL #{mssql_version_year} is too old. This adapter supports MSSQL >= 2012."
69
+ end
70
+ end
71
+
72
+ # Returns the (JDBC) connection class to be used for this adapter.
73
+ # The class is defined in the java part
74
+ def jdbc_connection_class(_spec)
75
+ ::ActiveRecord::ConnectionAdapters::MSSQLJdbcConnection
76
+ end
77
+
78
+ # Returns the (JDBC) `ActiveRecord` column class for this adapter.
79
+ # Used in the java part.
80
+ def jdbc_column_class
81
+ ::ActiveRecord::ConnectionAdapters::MSSQLColumn
82
+ end
83
+
84
+ # Can this adapter determine the primary key for tables not attached
85
+ # to an Active Record class, such as join tables?
86
+ def supports_primary_key?
87
+ true
88
+ end
89
+
90
+ # Does this adapter support creating foreign key constraints?
91
+ def supports_foreign_keys?
92
+ true
93
+ end
94
+
95
+ # Does this adapter support migrations?
96
+ def supports_migrations?
97
+ true
98
+ end
99
+
100
+ # Does this adapter support setting the isolation level for a transaction?
101
+ def supports_transaction_isolation?
102
+ true
103
+ end
104
+
105
+ # The MSSQL datetime type doe have precision.
106
+ def supports_datetime_with_precision?
107
+ true
108
+ end
109
+
110
+ # Overrides abstract method which always returns false
111
+ def valid_type?(type)
112
+ !native_database_types[type].nil?
113
+ end
114
+
115
+ # FIXME: to be reviewed.
116
+ def clear_cache!
117
+ reload_type_map
118
+ super
119
+ end
120
+
121
+ def disable_referential_integrity
122
+ tables = tables_with_referential_integrity
123
+
124
+ tables.each do |table_name|
125
+ execute "ALTER TABLE #{table_name} NOCHECK CONSTRAINT ALL"
126
+ end
127
+ yield
128
+ ensure
129
+ tables.each do |table_name|
130
+ execute "ALTER TABLE #{table_name} CHECK CONSTRAINT ALL"
131
+ end
132
+ end
133
+
134
+ # Overrides the method in abstract adapter to set the limit and offset
135
+ # in the right order. (SQLServer specific)
136
+ # Called by bound_attributes
137
+ def combine_bind_parameters(
138
+ from_clause: [],
139
+ join_clause: [],
140
+ where_clause: [],
141
+ having_clause: [],
142
+ limit: nil,
143
+ offset: nil
144
+ )
145
+
146
+ result = from_clause + join_clause + where_clause + having_clause
147
+ result << offset if offset
148
+ result << limit if limit
149
+ result
150
+ end
151
+
152
+ def arel_visitor # :nodoc:
153
+ ::Arel::Visitors::SQLServer.new(self)
154
+ end
155
+
156
+ def schema_creation # :nodoc:
157
+ MSSQL::SchemaCreation.new(self)
158
+ end
159
+
160
+ def create_table_definition(*args) # :nodoc:
161
+ MSSQL::TableDefinition.new(*args)
162
+ end
163
+
164
+ def update_table_definition(table_name, base) #:nodoc:
165
+ MSSQL::Table.new(table_name, base)
166
+ end
167
+
168
+ # Returns the name of the current security context
169
+ def current_user
170
+ @current_user ||= select_value('SELECT CURRENT_USER')
171
+ end
172
+
173
+ # Returns the default schema (to be used for table resolution)
174
+ # used for the {#current_user}.
175
+ def default_schema
176
+ @default_schema ||= select_value('SELECT default_schema_name FROM sys.database_principals WHERE name = CURRENT_USER')
177
+ end
178
+
179
+ alias_method :current_schema, :default_schema
180
+
181
+ # Allows for changing of the default schema.
182
+ # (to be used during unqualified table name resolution).
183
+ def default_schema=(default_schema)
184
+ execute("ALTER #{current_user} WITH DEFAULT_SCHEMA=#{default_schema}")
185
+ @default_schema = nil if defined?(@default_schema)
186
+ end
187
+
188
+ alias_method :current_schema=, :default_schema=
189
+
190
+ # Overrides method in abstract adapter
191
+ def case_sensitive_comparison(table, attribute, column, value)
192
+ if value.nil?
193
+ table[attribute].eq(value)
194
+ elsif value.acts_like?(:string)
195
+ table[attribute].eq(Arel::Nodes::Bin.new(Arel::Nodes::BindParam.new))
196
+ else
197
+ table[attribute].eq(Arel::Nodes::BindParam.new)
198
+ end
199
+ end
200
+
201
+ def configure_connection
202
+ execute("SET LOCK_TIMEOUT #{lock_timeout}")
203
+
204
+ set_session_transaction_isolation
205
+ end
206
+
207
+ def lock_timeout
208
+ timeout = config[:lock_timeout].to_i
209
+
210
+ if timeout.positive?
211
+ timeout
212
+ else
213
+ 5_000
214
+ end
215
+ end
216
+
217
+ def set_session_transaction_isolation
218
+ isolation_level = config[:transaction_isolation]
219
+
220
+ self.transaction_isolation = isolation_level if isolation_level
221
+ end
222
+
223
+ def mssql?
224
+ true
225
+ end
226
+
227
+ def mssql_major_version
228
+ return @mssql_major_version if defined? @mssql_major_version
229
+
230
+ @mssql_major_version = @connection.database_major_version
231
+ end
232
+
233
+ def mssql_version_year
234
+ MSSQL_VERSION_YEAR[mssql_major_version.to_i]
235
+ end
236
+
237
+ def tables_with_referential_integrity
238
+ schema_and_tables_sql = %(
239
+ SELECT s.name, o.name
240
+ FROM sys.foreign_keys i
241
+ INNER JOIN sys.objects o ON i.parent_object_id = o.OBJECT_ID
242
+ INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
243
+ ).squish
244
+
245
+ schemas_and_tables = select_rows(schema_and_tables_sql)
246
+
247
+ schemas_and_tables.map do |schema_table|
248
+ schema, table = schema_table
249
+ "#{quote_name_part(schema)}.#{quote_name_part(table)}"
250
+ end
251
+ end
252
+
253
+ protected
254
+
255
+ def translate_exception(e, message)
256
+ case message
257
+ when /(cannot insert duplicate key .* with unique index) | (violation of unique key constraint)/i
258
+ RecordNotUnique.new(message)
259
+ when /Lock request time out period exceeded/i
260
+ LockTimeout.new(message)
261
+ when /The .* statement conflicted with the FOREIGN KEY constraint/
262
+ ActiveRecord::InvalidForeignKey.new(message)
263
+ when /(String or binary data would be truncated)/i
264
+ ActiveRecord::ValueTooLong.new(message)
265
+ else
266
+ super
267
+ end
268
+ end
269
+
270
+ # This method is called indirectly by the abstract method
271
+ # 'fetch_type_metadata' which then it is called by the java part when
272
+ # calculating a table's columns.
273
+ def initialize_type_map(map)
274
+ # Build the type mapping from SQL Server to ActiveRecord
275
+
276
+ # Integer types.
277
+ map.register_type 'int', MSSQL::Type::Integer.new(limit: 4)
278
+ map.register_type 'tinyint', MSSQL::Type::TinyInteger.new(limit: 1)
279
+ map.register_type 'smallint', MSSQL::Type::SmallInteger.new(limit: 2)
280
+ map.register_type 'bigint', MSSQL::Type::BigInteger.new(limit: 8)
281
+
282
+ # Exact Numeric types.
283
+ map.register_type %r{\Adecimal}i do |sql_type|
284
+ scale = extract_scale(sql_type)
285
+ precision = extract_precision(sql_type)
286
+ if scale == 0
287
+ MSSQL::Type::DecimalWithoutScale.new(precision: precision)
288
+ else
289
+ MSSQL::Type::Decimal.new(precision: precision, scale: scale)
290
+ end
291
+ end
292
+ map.register_type %r{\Amoney\z}i, MSSQL::Type::Money.new
293
+ map.register_type %r{\Asmallmoney\z}i, MSSQL::Type::SmallMoney.new
294
+
295
+ # Approximate Numeric types.
296
+ map.register_type %r{\Afloat\z}i, MSSQL::Type::Float.new
297
+ map.register_type %r{\Areal\z}i, MSSQL::Type::Real.new
298
+
299
+ # Character strings CHAR and VARCHAR (it can become Unicode UTF-8)
300
+ map.register_type 'varchar(max)', MSSQL::Type::VarcharMax.new
301
+ map.register_type %r{\Avarchar\(\d+\)} do |sql_type|
302
+ limit = extract_limit(sql_type)
303
+ MSSQL::Type::Varchar.new(limit: limit)
304
+ end
305
+ map.register_type %r{\Achar\(\d+\)} do |sql_type|
306
+ limit = extract_limit(sql_type)
307
+ MSSQL::Type::Char.new(limit: limit)
308
+ end
309
+
310
+ # Character strings NCHAR and NVARCHAR (by default Unicode UTF-16)
311
+ map.register_type %r{\Anvarchar\(\d+\)} do |sql_type|
312
+ limit = extract_limit(sql_type)
313
+ MSSQL::Type::Nvarchar.new(limit: limit)
314
+ end
315
+ map.register_type %r{\Anchar\(\d+\)} do |sql_type|
316
+ limit = extract_limit(sql_type)
317
+ MSSQL::Type::Nchar.new(limit: limit)
318
+ end
319
+ map.register_type 'nvarchar(max)', MSSQL::Type::NvarcharMax.new
320
+ map.register_type 'nvarchar(4000)', MSSQL::Type::Nvarchar.new
321
+
322
+ # Binary data types.
323
+ map.register_type 'varbinary(max)', MSSQL::Type::VarbinaryMax.new
324
+ register_class_with_limit map, %r{\Abinary\(\d+\)}, MSSQL::Type::BinaryBasic
325
+ register_class_with_limit map, %r{\Avarbinary\(\d+\)}, MSSQL::Type::Varbinary
326
+
327
+ # Miscellaneous types, Boolean, XML, UUID
328
+ # FIXME The xml data needs to be reviewed and fixed
329
+ map.register_type 'bit', MSSQL::Type::Boolean.new
330
+ map.register_type %r{\Auniqueidentifier\z}i, MSSQL::Type::UUID.new
331
+ map.register_type %r{\Axml\z}i, MSSQL::Type::XML.new
332
+
333
+ # Date and time types
334
+ map.register_type 'date', MSSQL::Type::Date.new
335
+ map.register_type 'datetime', MSSQL::Type::DateTime.new
336
+ map.register_type 'smalldatetime', MSSQL::Type::SmallDateTime.new
337
+ register_class_with_precision map, %r{\Atime\(\d+\)}i, MSSQL::Type::Time
338
+ map.register_type 'time(7)', MSSQL::Type::Time.new
339
+ register_class_with_precision map, %r{\Adatetime2\(\d+\)}i, MSSQL::Type::DateTime2
340
+ map.register_type 'datetime2(7)', MSSQL::Type::DateTime2.new
341
+
342
+ # aliases
343
+ map.alias_type 'int identity', 'int'
344
+ map.alias_type 'bigint identity', 'bigint'
345
+ map.alias_type 'integer', 'int'
346
+ map.alias_type 'integer', 'int'
347
+ map.alias_type 'INTEGER', 'int'
348
+ map.alias_type 'TINYINT', 'tinyint'
349
+ map.alias_type 'SMALLINT', 'smallint'
350
+ map.alias_type 'BIGINT', 'bigint'
351
+ map.alias_type %r{\Anumeric}i, 'decimal'
352
+ map.alias_type %r{\Anumber}i, 'decimal'
353
+ map.alias_type %r{\Adouble\z}i, 'float'
354
+ map.alias_type 'string', 'nvarchar(4000)'
355
+ map.alias_type %r{\Aboolean\z}i, 'bit'
356
+ map.alias_type 'DATE', 'date'
357
+ map.alias_type 'DATETIME', 'datetime'
358
+ map.alias_type 'SMALLDATETIME', 'smalldatetime'
359
+ map.alias_type %r{\Atime\z}i, 'time(7)'
360
+ map.alias_type %r{\Abinary\z}i, 'varbinary(max)'
361
+ map.alias_type %r{\Ablob\z}i, 'varbinary(max)'
362
+ map.alias_type %r{\Adatetime2\z}i, 'datetime2(7)'
363
+
364
+ # Deprecated SQL Server types.
365
+ map.register_type 'text', MSSQL::Type::Text.new
366
+ map.register_type 'ntext', MSSQL::Type::Ntext.new
367
+ map.register_type 'image', MSSQL::Type::Image.new
368
+ end
369
+ end
370
+ end
371
+ end
372
+
373
+ # FIXME: this is not used by the adapter anymore, it is here because
374
+ # it is a dependency of old tests that needs to be reviewed
375
+ module ArJdbc
376
+ module MSSQL
377
+ require 'arjdbc/mssql/utils'
378
+ require 'arjdbc/mssql/limit_helpers'
379
+ require 'arjdbc/mssql/lock_methods'
380
+
381
+ include LimitHelpers
382
+ include Utils
383
+ end
384
+ end