activerecord-jdbc-alt-adapter 50.3.0-java

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.
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