activerecord-jdbc-adapter-ficoh 1.3.21-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 (191) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +35 -0
  3. data/.travis.yml +462 -0
  4. data/.yardopts +4 -0
  5. data/Appraisals +36 -0
  6. data/CONTRIBUTING.md +49 -0
  7. data/Gemfile +68 -0
  8. data/History.md +1191 -0
  9. data/LICENSE.txt +25 -0
  10. data/README.md +277 -0
  11. data/RUNNING_TESTS.md +88 -0
  12. data/Rakefile +298 -0
  13. data/Rakefile.jdbc +20 -0
  14. data/activerecord-jdbc-adapter.gemspec +63 -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/oracle_adapter.rb +1 -0
  29. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -0
  30. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -0
  31. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +1 -0
  32. data/lib/activerecord-jdbc-adapter.rb +1 -0
  33. data/lib/arel/visitors/compat.rb +64 -0
  34. data/lib/arel/visitors/db2.rb +137 -0
  35. data/lib/arel/visitors/derby.rb +112 -0
  36. data/lib/arel/visitors/firebird.rb +79 -0
  37. data/lib/arel/visitors/h2.rb +25 -0
  38. data/lib/arel/visitors/hsqldb.rb +32 -0
  39. data/lib/arel/visitors/postgresql_jdbc.rb +6 -0
  40. data/lib/arel/visitors/sql_server.rb +225 -0
  41. data/lib/arel/visitors/sql_server/ng42.rb +293 -0
  42. data/lib/arjdbc.rb +22 -0
  43. data/lib/arjdbc/db2.rb +4 -0
  44. data/lib/arjdbc/db2/adapter.rb +802 -0
  45. data/lib/arjdbc/db2/as400.rb +137 -0
  46. data/lib/arjdbc/db2/column.rb +177 -0
  47. data/lib/arjdbc/db2/connection_methods.rb +45 -0
  48. data/lib/arjdbc/derby.rb +3 -0
  49. data/lib/arjdbc/derby/active_record_patch.rb +13 -0
  50. data/lib/arjdbc/derby/adapter.rb +567 -0
  51. data/lib/arjdbc/derby/connection_methods.rb +16 -0
  52. data/lib/arjdbc/derby/schema_creation.rb +15 -0
  53. data/lib/arjdbc/discover.rb +104 -0
  54. data/lib/arjdbc/firebird.rb +4 -0
  55. data/lib/arjdbc/firebird/adapter.rb +468 -0
  56. data/lib/arjdbc/firebird/connection_methods.rb +20 -0
  57. data/lib/arjdbc/h2.rb +3 -0
  58. data/lib/arjdbc/h2/adapter.rb +335 -0
  59. data/lib/arjdbc/h2/connection_methods.rb +22 -0
  60. data/lib/arjdbc/hsqldb.rb +3 -0
  61. data/lib/arjdbc/hsqldb/adapter.rb +304 -0
  62. data/lib/arjdbc/hsqldb/connection_methods.rb +23 -0
  63. data/lib/arjdbc/hsqldb/explain_support.rb +35 -0
  64. data/lib/arjdbc/hsqldb/schema_creation.rb +11 -0
  65. data/lib/arjdbc/informix.rb +5 -0
  66. data/lib/arjdbc/informix/adapter.rb +160 -0
  67. data/lib/arjdbc/informix/connection_methods.rb +9 -0
  68. data/lib/arjdbc/jdbc.rb +62 -0
  69. data/lib/arjdbc/jdbc/adapter.rb +997 -0
  70. data/lib/arjdbc/jdbc/adapter_require.rb +46 -0
  71. data/lib/arjdbc/jdbc/arel_support.rb +149 -0
  72. data/lib/arjdbc/jdbc/base_ext.rb +34 -0
  73. data/lib/arjdbc/jdbc/callbacks.rb +52 -0
  74. data/lib/arjdbc/jdbc/column.rb +83 -0
  75. data/lib/arjdbc/jdbc/connection.rb +26 -0
  76. data/lib/arjdbc/jdbc/connection_methods.rb +59 -0
  77. data/lib/arjdbc/jdbc/driver.rb +44 -0
  78. data/lib/arjdbc/jdbc/error.rb +75 -0
  79. data/lib/arjdbc/jdbc/extension.rb +69 -0
  80. data/lib/arjdbc/jdbc/java.rb +13 -0
  81. data/lib/arjdbc/jdbc/type_cast.rb +154 -0
  82. data/lib/arjdbc/jdbc/type_converter.rb +142 -0
  83. data/lib/arjdbc/mssql.rb +7 -0
  84. data/lib/arjdbc/mssql/adapter.rb +822 -0
  85. data/lib/arjdbc/mssql/column.rb +207 -0
  86. data/lib/arjdbc/mssql/connection_methods.rb +72 -0
  87. data/lib/arjdbc/mssql/explain_support.rb +99 -0
  88. data/lib/arjdbc/mssql/limit_helpers.rb +231 -0
  89. data/lib/arjdbc/mssql/lock_methods.rb +77 -0
  90. data/lib/arjdbc/mssql/types.rb +343 -0
  91. data/lib/arjdbc/mssql/utils.rb +82 -0
  92. data/lib/arjdbc/mysql.rb +3 -0
  93. data/lib/arjdbc/mysql/adapter.rb +998 -0
  94. data/lib/arjdbc/mysql/bulk_change_table.rb +150 -0
  95. data/lib/arjdbc/mysql/column.rb +167 -0
  96. data/lib/arjdbc/mysql/connection_methods.rb +137 -0
  97. data/lib/arjdbc/mysql/explain_support.rb +82 -0
  98. data/lib/arjdbc/mysql/schema_creation.rb +58 -0
  99. data/lib/arjdbc/oracle.rb +4 -0
  100. data/lib/arjdbc/oracle/adapter.rb +968 -0
  101. data/lib/arjdbc/oracle/column.rb +136 -0
  102. data/lib/arjdbc/oracle/connection_methods.rb +21 -0
  103. data/lib/arjdbc/postgresql.rb +3 -0
  104. data/lib/arjdbc/postgresql/_bc_time_cast_patch.rb +21 -0
  105. data/lib/arjdbc/postgresql/adapter.rb +1498 -0
  106. data/lib/arjdbc/postgresql/base/array_parser.rb +95 -0
  107. data/lib/arjdbc/postgresql/base/oid.rb +412 -0
  108. data/lib/arjdbc/postgresql/base/pgconn.rb +8 -0
  109. data/lib/arjdbc/postgresql/base/schema_definitions.rb +132 -0
  110. data/lib/arjdbc/postgresql/column.rb +640 -0
  111. data/lib/arjdbc/postgresql/connection_methods.rb +44 -0
  112. data/lib/arjdbc/postgresql/explain_support.rb +53 -0
  113. data/lib/arjdbc/postgresql/oid/bytea.rb +3 -0
  114. data/lib/arjdbc/postgresql/oid_types.rb +265 -0
  115. data/lib/arjdbc/postgresql/schema_creation.rb +60 -0
  116. data/lib/arjdbc/railtie.rb +11 -0
  117. data/lib/arjdbc/sqlite3.rb +3 -0
  118. data/lib/arjdbc/sqlite3/adapter.rb +654 -0
  119. data/lib/arjdbc/sqlite3/connection_methods.rb +36 -0
  120. data/lib/arjdbc/sqlite3/explain_support.rb +29 -0
  121. data/lib/arjdbc/sybase.rb +2 -0
  122. data/lib/arjdbc/sybase/adapter.rb +47 -0
  123. data/lib/arjdbc/tasks.rb +13 -0
  124. data/lib/arjdbc/tasks/database_tasks.rb +66 -0
  125. data/lib/arjdbc/tasks/databases.rake +91 -0
  126. data/lib/arjdbc/tasks/databases3.rake +239 -0
  127. data/lib/arjdbc/tasks/databases4.rake +39 -0
  128. data/lib/arjdbc/tasks/db2_database_tasks.rb +104 -0
  129. data/lib/arjdbc/tasks/derby_database_tasks.rb +95 -0
  130. data/lib/arjdbc/tasks/h2_database_tasks.rb +31 -0
  131. data/lib/arjdbc/tasks/hsqldb_database_tasks.rb +70 -0
  132. data/lib/arjdbc/tasks/jdbc_database_tasks.rb +169 -0
  133. data/lib/arjdbc/tasks/mssql_database_tasks.rb +46 -0
  134. data/lib/arjdbc/tasks/oracle/enhanced_structure_dump.rb +297 -0
  135. data/lib/arjdbc/tasks/oracle_database_tasks.rb +65 -0
  136. data/lib/arjdbc/util/quoted_cache.rb +60 -0
  137. data/lib/arjdbc/util/serialized_attributes.rb +98 -0
  138. data/lib/arjdbc/util/table_copier.rb +108 -0
  139. data/lib/arjdbc/version.rb +8 -0
  140. data/lib/generators/jdbc/USAGE +9 -0
  141. data/lib/generators/jdbc/jdbc_generator.rb +17 -0
  142. data/pom.xml +285 -0
  143. data/rails_generators/jdbc_generator.rb +15 -0
  144. data/rails_generators/templates/config/initializers/jdbc.rb +10 -0
  145. data/rails_generators/templates/lib/tasks/jdbc.rake +11 -0
  146. data/rakelib/01-tomcat.rake +51 -0
  147. data/rakelib/02-test.rake +151 -0
  148. data/rakelib/bundler_ext.rb +11 -0
  149. data/rakelib/db.rake +58 -0
  150. data/rakelib/rails.rake +77 -0
  151. data/src/java/arjdbc/ArJdbcModule.java +288 -0
  152. data/src/java/arjdbc/db2/DB2Module.java +77 -0
  153. data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +128 -0
  154. data/src/java/arjdbc/derby/DerbyModule.java +180 -0
  155. data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +153 -0
  156. data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +190 -0
  157. data/src/java/arjdbc/h2/H2Module.java +50 -0
  158. data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +86 -0
  159. data/src/java/arjdbc/hsqldb/HSQLDBModule.java +74 -0
  160. data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +76 -0
  161. data/src/java/arjdbc/jdbc/AdapterJavaService.java +43 -0
  162. data/src/java/arjdbc/jdbc/Callable.java +44 -0
  163. data/src/java/arjdbc/jdbc/ConnectionFactory.java +77 -0
  164. data/src/java/arjdbc/jdbc/DataSourceConnectionFactory.java +156 -0
  165. data/src/java/arjdbc/jdbc/DriverConnectionFactory.java +63 -0
  166. data/src/java/arjdbc/jdbc/DriverWrapper.java +128 -0
  167. data/src/java/arjdbc/jdbc/JdbcConnectionFactory.java +32 -0
  168. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +4541 -0
  169. data/src/java/arjdbc/jdbc/SQLBlock.java +54 -0
  170. data/src/java/arjdbc/jdbc/WithResultSet.java +37 -0
  171. data/src/java/arjdbc/mssql/MSSQLModule.java +91 -0
  172. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +193 -0
  173. data/src/java/arjdbc/mysql/MySQLModule.java +140 -0
  174. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +456 -0
  175. data/src/java/arjdbc/oracle/OracleModule.java +81 -0
  176. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +477 -0
  177. data/src/java/arjdbc/postgresql/ByteaUtils.java +171 -0
  178. data/src/java/arjdbc/postgresql/DriverImplementation.java +78 -0
  179. data/src/java/arjdbc/postgresql/PGDriverImplementation.java +535 -0
  180. data/src/java/arjdbc/postgresql/PostgreSQLModule.java +189 -0
  181. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +489 -0
  182. data/src/java/arjdbc/sqlite3/SQLite3Module.java +93 -0
  183. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +405 -0
  184. data/src/java/arjdbc/util/CallResultSet.java +826 -0
  185. data/src/java/arjdbc/util/DateTimeUtils.java +517 -0
  186. data/src/java/arjdbc/util/NumberUtils.java +50 -0
  187. data/src/java/arjdbc/util/ObjectSupport.java +65 -0
  188. data/src/java/arjdbc/util/QuotingUtils.java +139 -0
  189. data/src/java/arjdbc/util/StringCache.java +60 -0
  190. data/src/java/arjdbc/util/StringHelper.java +155 -0
  191. metadata +288 -0
@@ -0,0 +1,3 @@
1
+ require 'arjdbc'
2
+ require 'arjdbc/mysql/adapter'
3
+ require 'arjdbc/mysql/connection_methods'
@@ -0,0 +1,998 @@
1
+ ArJdbc.load_java_part :MySQL
2
+
3
+ require 'bigdecimal'
4
+ require 'active_record/connection_adapters/abstract/schema_definitions'
5
+
6
+ module ArJdbc
7
+ module MySQL
8
+
9
+ require 'arjdbc/mysql/column'
10
+ require 'arjdbc/mysql/bulk_change_table'
11
+ require 'arjdbc/mysql/explain_support'
12
+ require 'arjdbc/mysql/schema_creation' # AR 4.x
13
+
14
+ include BulkChangeTable if const_defined? :BulkChangeTable
15
+
16
+ # @private
17
+ ActiveRecordError = ::ActiveRecord::ActiveRecordError
18
+
19
+ JdbcConnection = ::ActiveRecord::ConnectionAdapters::MySQLJdbcConnection
20
+
21
+ # @deprecated
22
+ # @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
23
+ def self.jdbc_connection_class; JdbcConnection end
24
+
25
+ def configure_connection
26
+ unless ( variables = config[:variables] ) == false # AR-JDBC allows disabling
27
+ # as this can be configured with a JDBC pool, defaults executed are :
28
+ # SET NAMES utf8,
29
+ # @@SESSION.sql_auto_is_null = 0,
30
+ # @@SESSION.wait_timeout = 2147483,
31
+ # @@SESSION.sql_mode = 'STRICT_ALL_TABLES'
32
+
33
+ variables ||= {}
34
+ # By default, MySQL 'where id is null' selects the last inserted id. Turn this off.
35
+ variables[:sql_auto_is_null] = 0 # execute "SET SQL_AUTO_IS_NULL=0"
36
+
37
+ # Increase timeout so the server doesn't disconnect us.
38
+ wait_timeout = config[:wait_timeout]
39
+ wait_timeout = self.class.type_cast_config_to_integer(wait_timeout)
40
+ variables[:wait_timeout] = wait_timeout.is_a?(Fixnum) ? wait_timeout : 2147483
41
+
42
+ # Make MySQL reject illegal values rather than truncating or blanking them, see
43
+ # http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html#sqlmode_strict_all_tables
44
+ # If the user has provided another value for sql_mode, don't replace it.
45
+ if strict_mode? && ! variables.has_key?(:sql_mode)
46
+ variables[:sql_mode] = 'STRICT_ALL_TABLES' # SET SQL_MODE='STRICT_ALL_TABLES'
47
+ end
48
+
49
+ # Gather up all of the SET variables...
50
+ variable_assignments = variables.map do |k, v|
51
+ if v == ':default' || v == :default
52
+ "@@SESSION.#{k} = DEFAULT" # Sets the value to the global or compile default
53
+ elsif ! v.nil?
54
+ "@@SESSION.#{k} = #{quote(v)}"
55
+ end
56
+ # or else nil; compact to clear nils out
57
+ end
58
+ variable_assignments.compact!
59
+ end
60
+
61
+ # NAMES does not have an equals sign, see
62
+ # http://dev.mysql.com/doc/refman/5.0/en/set-statement.html#id944430
63
+ # (trailing comma because variable_assignments will always have content)
64
+ if encoding = config[:encoding]
65
+ ( variable_assignments ||= [] ).unshift("NAMES #{encoding}")
66
+ end
67
+
68
+ # ...and send them all in one query
69
+ execute("SET #{variable_assignments.join(', ')}", :skip_logging) if variable_assignments
70
+ end
71
+
72
+ def strict_mode? # strict_mode is default since AR 4.0
73
+ return @strict_mode unless ( @strict_mode ||= nil ).nil?
74
+
75
+ @strict_mode = config.key?(:strict) ?
76
+ self.class.type_cast_config_to_boolean(config[:strict]) :
77
+ AR40 # strict_mode is default since AR 4.0
78
+ end
79
+
80
+ # @private
81
+ @@emulate_booleans = true
82
+
83
+ # Boolean emulation can be disabled using (or using the adapter method) :
84
+ #
85
+ # ArJdbc::MySQL.emulate_booleans = false
86
+ #
87
+ # @see ActiveRecord::ConnectionAdapters::MysqlAdapter#emulate_booleans
88
+ def self.emulate_booleans?; @@emulate_booleans; end
89
+ # @deprecated Use {#emulate_booleans?} instead.
90
+ def self.emulate_booleans; @@emulate_booleans; end
91
+ # @see #emulate_booleans?
92
+ def self.emulate_booleans=(emulate); @@emulate_booleans = emulate; end
93
+
94
+ NATIVE_DATABASE_TYPES = {
95
+ :primary_key => "int(11) auto_increment PRIMARY KEY",
96
+ :string => { :name => "varchar", :limit => 255 },
97
+ :text => { :name => "text" },
98
+ :integer => { :name => "int", :limit => 4 },
99
+ :float => { :name => "float" },
100
+ # :double => { :name=>"double", :limit=>17 }
101
+ # :real => { :name=>"real", :limit=>17 }
102
+ :numeric => { :name => "numeric" }, # :limit => 65
103
+ :decimal => { :name => "decimal" }, # :limit => 65
104
+ :datetime => { :name => "datetime" },
105
+ # TIMESTAMP has varying properties depending on MySQL version (SQL mode)
106
+ :timestamp => { :name => "datetime" },
107
+ :time => { :name => "time" },
108
+ :date => { :name => "date" },
109
+ :binary => { :name => "blob" },
110
+ :boolean => { :name => "tinyint", :limit => 1 },
111
+ # AR-JDBC added :
112
+ :bit => { :name => "bit" }, # :limit => 1
113
+ :enum => { :name => "enum" },
114
+ :set => { :name => "set" }, # :limit => 64
115
+ :char => { :name => "char" }, # :limit => 255
116
+ }
117
+
118
+ # @override
119
+ def native_database_types
120
+ NATIVE_DATABASE_TYPES
121
+ end
122
+
123
+ ADAPTER_NAME = 'MySQL'.freeze
124
+
125
+ # @override
126
+ def adapter_name
127
+ ADAPTER_NAME
128
+ end
129
+
130
+ def self.arel_visitor_type(config = nil)
131
+ ::Arel::Visitors::MySQL
132
+ end
133
+
134
+ # @see ActiveRecord::ConnectionAdapters::JdbcAdapter#bind_substitution
135
+ # @private
136
+ class BindSubstitution < Arel::Visitors::MySQL
137
+ include Arel::Visitors::BindVisitor
138
+ end if defined? Arel::Visitors::BindVisitor
139
+
140
+ def case_sensitive_equality_operator
141
+ "= BINARY"
142
+ end
143
+
144
+ def case_sensitive_modifier(node)
145
+ Arel::Nodes::Bin.new(node)
146
+ end unless AR42
147
+
148
+ def case_sensitive_modifier(node, table_attribute)
149
+ node = Arel::Nodes.build_quoted node, table_attribute
150
+ Arel::Nodes::Bin.new(node)
151
+ end if AR42
152
+
153
+ def case_sensitive_comparison(table, attribute, column, value)
154
+ if column.case_sensitive?
155
+ table[attribute].eq(value)
156
+ else
157
+ super
158
+ end
159
+ end if AR42
160
+
161
+ def case_insensitive_comparison(table, attribute, column, value)
162
+ if column.case_sensitive?
163
+ super
164
+ else
165
+ table[attribute].eq(value)
166
+ end
167
+ end if AR42
168
+
169
+ def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key)
170
+ where_sql
171
+ end
172
+
173
+ def initialize_schema_migrations_table
174
+ if @config[:encoding] == 'utf8mb4'
175
+ ActiveRecord::SchemaMigration.create_table(191)
176
+ else
177
+ ActiveRecord::SchemaMigration.create_table
178
+ end
179
+ end if AR40
180
+
181
+ # HELPER METHODS ===========================================
182
+
183
+ # @private Only for Rails core compatibility.
184
+ def new_column(field, default, type, null, collation, extra = "")
185
+ Column.new(field, default, type, null, collation, strict_mode?, extra)
186
+ end unless AR42
187
+
188
+ # @private Only for Rails core compatibility.
189
+ def new_column(field, default, cast_type, sql_type = nil, null = true, collation = "", extra = "")
190
+ Column.new(field, default, cast_type, sql_type, null, collation, strict_mode?, extra)
191
+ end if AR42
192
+
193
+ # @private Only for Rails core compatibility.
194
+ def error_number(exception)
195
+ exception.error_code if exception.respond_to?(:error_code)
196
+ end
197
+
198
+ # QUOTING ==================================================
199
+
200
+ # @override
201
+ def quote(value, column = nil)
202
+ return value.quoted_id if value.respond_to?(:quoted_id)
203
+ return value if sql_literal?(value)
204
+ return value.to_s if column && column.type == :primary_key
205
+
206
+ if value.kind_of?(String) && column && column.type == :binary
207
+ "x'#{value.unpack("H*")[0]}'"
208
+ elsif value.kind_of?(BigDecimal)
209
+ value.to_s("F")
210
+ else
211
+ super
212
+ end
213
+ end unless AR42
214
+
215
+ # @private since AR 4.2
216
+ def _quote(value)
217
+ if value.is_a?(Type::Binary::Data)
218
+ "x'#{value.hex}'"
219
+ else
220
+ super
221
+ end
222
+ end if AR42
223
+
224
+ # @override
225
+ def quote_column_name(name)
226
+ "`#{name.to_s.gsub('`', '``')}`"
227
+ end
228
+
229
+ # @override
230
+ def quote_table_name(name)
231
+ quote_column_name(name).gsub('.', '`.`')
232
+ end
233
+
234
+ # @override
235
+ def supports_migrations?
236
+ true
237
+ end
238
+
239
+ # @override
240
+ def supports_primary_key?
241
+ true
242
+ end
243
+
244
+ # @override
245
+ def supports_index_sort_order?
246
+ # Technically MySQL allows to create indexes with the sort order syntax
247
+ # but at the moment (5.5) it doesn't yet implement them.
248
+ true
249
+ end
250
+
251
+ # @override
252
+ def supports_indexes_in_create?
253
+ true
254
+ end
255
+
256
+ # @override
257
+ def supports_transaction_isolation?
258
+ # MySQL 4 technically support transaction isolation, but it is affected by
259
+ # a bug where the transaction level gets persisted for the whole session:
260
+ # http://bugs.mysql.com/bug.php?id=39170
261
+ version[0] && version[0] >= 5
262
+ end
263
+
264
+ # @override
265
+ def supports_views?
266
+ version[0] && version[0] >= 5
267
+ end
268
+
269
+ def supports_rename_index?
270
+ return false if mariadb? || ! version[0]
271
+ (version[0] == 5 && version[1] >= 7) || version[0] >= 6
272
+ end
273
+
274
+ def index_algorithms
275
+ { :default => 'ALGORITHM = DEFAULT', :copy => 'ALGORITHM = COPY', :inplace => 'ALGORITHM = INPLACE' }
276
+ end if AR42
277
+
278
+ # @override
279
+ def supports_transaction_isolation?(level = nil)
280
+ version[0] && version[0] >= 5 # MySQL 5+
281
+ end
282
+
283
+ # NOTE: handled by JdbcAdapter only to have statements in logs :
284
+
285
+ # @private
286
+ BEGIN_LOG = '/* BEGIN */ SET autocommit=0'
287
+ private_constant :BEGIN_LOG if respond_to?(:private_constant)
288
+
289
+ # @override
290
+ def begin_db_transaction
291
+ log(BEGIN_LOG) { @connection.begin }
292
+ end
293
+
294
+ # @override
295
+ def commit_db_transaction
296
+ log('COMMIT; SET autocommit=1') { @connection.commit }
297
+ end
298
+
299
+ # @override
300
+ def rollback_db_transaction
301
+ log('ROLLBACK; SET autocommit=1') { @connection.rollback }
302
+ end
303
+
304
+ # Starts a database transaction.
305
+ # @param isolation the transaction isolation to use
306
+ # @since 1.3.0
307
+ # @override on **AR-4.0**
308
+ def begin_isolated_db_transaction(isolation)
309
+ name = isolation.to_s.upcase; name.sub!('_', ' ')
310
+ log("SET TRANSACTION ISOLATION LEVEL #{name}; #{BEGIN_LOG}") do
311
+ @connection.begin(isolation)
312
+ end
313
+ end
314
+
315
+ # @override
316
+ def supports_savepoints?
317
+ true
318
+ end
319
+
320
+ # @override
321
+ def create_savepoint(name = current_savepoint_name(true))
322
+ log("SAVEPOINT #{name}") { @connection.create_savepoint(name) }
323
+ end
324
+
325
+ # @override
326
+ def rollback_to_savepoint(name = current_savepoint_name(true))
327
+ log("ROLLBACK TO SAVEPOINT #{name}") { @connection.rollback_savepoint(name) }
328
+ end
329
+
330
+ # @override
331
+ def release_savepoint(name = current_savepoint_name(false))
332
+ log("RELEASE SAVEPOINT #{name}") { @connection.release_savepoint(name) }
333
+ end
334
+
335
+ def disable_referential_integrity
336
+ fk_checks = select_value("SELECT @@FOREIGN_KEY_CHECKS")
337
+ begin
338
+ update("SET FOREIGN_KEY_CHECKS = 0")
339
+ yield
340
+ ensure
341
+ update("SET FOREIGN_KEY_CHECKS = #{fk_checks}")
342
+ end
343
+ end
344
+
345
+ # @override make it public just like native MySQL adapter does
346
+ def update_sql(sql, name = nil); super end
347
+
348
+ # Returns just a table's primary key.
349
+ # @override
350
+ def primary_key(table)
351
+ #pk_and_sequence = pk_and_sequence_for(table)
352
+ #pk_and_sequence && pk_and_sequence.first
353
+ @connection.primary_keys(table).first
354
+ end
355
+
356
+ # Returns a table's primary key and belonging sequence.
357
+ # @note Not used, only here for potential compatibility with native adapter.
358
+ # @override
359
+ def pk_and_sequence_for(table)
360
+ result = execute("SHOW CREATE TABLE #{quote_table_name(table)}", 'SCHEMA').first
361
+ if result['Create Table'].to_s =~ /PRIMARY KEY\s+(?:USING\s+\w+\s+)?\((.+)\)/
362
+ keys = $1.split(","); keys.map! { |key| key.gsub(/[`"]/, "") }
363
+ return keys.length == 1 ? [ keys.first, nil ] : nil
364
+ else
365
+ return nil
366
+ end
367
+ end
368
+
369
+ # @private
370
+ IndexDefinition = ::ActiveRecord::ConnectionAdapters::IndexDefinition
371
+
372
+ INDEX_TYPES = [ :fulltext, :spatial ] if AR40
373
+ INDEX_USINGS = [ :btree, :hash ] if AR40
374
+
375
+ # Returns an array of indexes for the given table.
376
+ # @override
377
+ def indexes(table_name, name = nil)
378
+ indexes = []
379
+ current_index = nil
380
+ result = execute("SHOW KEYS FROM #{quote_table_name(table_name)}", name || 'SCHEMA')
381
+ result.each do |row|
382
+ key_name = row['Key_name']
383
+ if current_index != key_name
384
+ next if key_name == 'PRIMARY' # skip the primary key
385
+ current_index = key_name
386
+ indexes <<
387
+ if self.class.const_defined?(:INDEX_TYPES) # AR 4.0
388
+ mysql_index_type = row['Index_type'].downcase.to_sym
389
+ index_type = INDEX_TYPES.include?(mysql_index_type) ? mysql_index_type : nil
390
+ index_using = INDEX_USINGS.include?(mysql_index_type) ? mysql_index_type : nil
391
+ IndexDefinition.new(row['Table'], key_name, row['Non_unique'].to_i == 0, [], [], nil, nil, index_type, index_using)
392
+ else
393
+ IndexDefinition.new(row['Table'], key_name, row['Non_unique'].to_i == 0, [], [])
394
+ end
395
+ end
396
+
397
+ indexes.last.columns << row["Column_name"]
398
+ indexes.last.lengths << row["Sub_part"]
399
+ end
400
+ indexes
401
+ end
402
+
403
+ # Returns an array of `Column` objects for the table specified.
404
+ # @override
405
+ def columns(table_name, name = nil)
406
+ sql = "SHOW FULL #{AR40 ? 'FIELDS' : 'COLUMNS'} FROM #{quote_table_name(table_name)}"
407
+ columns = execute(sql, name || 'SCHEMA')
408
+ strict = strict_mode?
409
+ pass_cast_type = respond_to?(:lookup_cast_type)
410
+ columns.map! do |field|
411
+ sql_type = field['Type']
412
+ null = field['Null'] == "YES"
413
+ if pass_cast_type
414
+ cast_type = lookup_cast_type(sql_type)
415
+ Column.new(field['Field'], field['Default'], cast_type, sql_type, null, field['Collation'], strict, field['Extra'])
416
+ else
417
+ Column.new(field['Field'], field['Default'], sql_type, null, field['Collation'], strict, field['Extra'])
418
+ end
419
+ end
420
+ columns
421
+ end
422
+
423
+ if defined? ::ActiveRecord::ConnectionAdapters::AbstractAdapter::SchemaCreation
424
+
425
+ class SchemaCreation < ::ActiveRecord::ConnectionAdapters::AbstractAdapter::SchemaCreation
426
+
427
+ # @private
428
+ def visit_AddColumn(o)
429
+ add_column_position!(super, column_options(o))
430
+ end
431
+
432
+ # @private re-defined since AR 4.1
433
+ def visit_ChangeColumnDefinition(o)
434
+ column = o.column
435
+ options = o.options
436
+ sql_type = type_to_sql(o.type, options[:limit], options[:precision], options[:scale])
437
+ change_column_sql = "CHANGE #{quote_column_name(column.name)} #{quote_column_name(options[:name])} #{sql_type}"
438
+ add_column_options!(change_column_sql, options.merge(:column => column))
439
+ add_column_position!(change_column_sql, options)
440
+ end
441
+
442
+ # @private since AR 4.2
443
+ def visit_DropForeignKey(name)
444
+ "DROP FOREIGN KEY #{name}"
445
+ end
446
+
447
+ # @private since AR 4.2
448
+ def visit_TableDefinition(o)
449
+ name = o.name
450
+ create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE #{quote_table_name(name)} "
451
+
452
+ statements = o.columns.map { |c| accept c }
453
+ statements.concat(o.indexes.map { |column_name, options| index_in_create(name, column_name, options) })
454
+
455
+ create_sql << "(#{statements.join(', ')}) " if statements.present?
456
+ create_sql << "#{o.options}"
457
+ create_sql << " AS #{@conn.to_sql(o.as)}" if o.as
458
+ create_sql
459
+ end if AR42
460
+
461
+ private
462
+
463
+ def add_column_position!(sql, options)
464
+ if options[:first]
465
+ sql << " FIRST"
466
+ elsif options[:after]
467
+ sql << " AFTER #{quote_column_name(options[:after])}"
468
+ end
469
+ sql
470
+ end
471
+
472
+ def column_options(o)
473
+ column_options = {}
474
+ column_options[:null] = o.null unless o.null.nil?
475
+ column_options[:default] = o.default unless o.default.nil?
476
+ column_options[:column] = o
477
+ column_options[:first] = o.first
478
+ column_options[:after] = o.after
479
+ column_options
480
+ end
481
+
482
+ def index_in_create(table_name, column_name, options)
483
+ index_name, index_type, index_columns, index_options, index_algorithm, index_using = @conn.add_index_options(table_name, column_name, options)
484
+ "#{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_options} #{index_algorithm}"
485
+ end
486
+
487
+ end
488
+
489
+ def schema_creation; SchemaCreation.new self end
490
+
491
+ end
492
+
493
+ # @private
494
+ def recreate_database(name, options = {})
495
+ drop_database(name)
496
+ create_database(name, options)
497
+ reconnect!
498
+ end
499
+
500
+ # @override
501
+ def create_database(name, options = {})
502
+ if options[:collation]
503
+ execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}` COLLATE `#{options[:collation]}`"
504
+ else
505
+ execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}`"
506
+ end
507
+ end
508
+
509
+ # @override
510
+ def drop_database(name)
511
+ execute "DROP DATABASE IF EXISTS `#{name}`"
512
+ end
513
+
514
+ def current_database
515
+ select_one("SELECT DATABASE() as db")['db']
516
+ end
517
+
518
+ def truncate(table_name, name = nil)
519
+ execute "TRUNCATE TABLE #{quote_table_name(table_name)}", name
520
+ end
521
+
522
+ # @override
523
+ def create_table(name, options = {})
524
+ super(name, { :options => "ENGINE=InnoDB" }.merge(options))
525
+ end
526
+
527
+ def drop_table(table_name, options = {})
528
+ execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE #{quote_table_name(table_name)}"
529
+ end
530
+
531
+ # @override
532
+ def rename_table(table_name, new_name)
533
+ execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
534
+ rename_table_indexes(table_name, new_name) if respond_to?(:rename_table_indexes) # AR-4.0 SchemaStatements
535
+ end
536
+
537
+ # @override
538
+ def remove_index!(table_name, index_name)
539
+ # missing table_name quoting in AR-2.3
540
+ execute "DROP INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}"
541
+ end
542
+
543
+ # @override
544
+ def rename_index(table_name, old_name, new_name)
545
+ if supports_rename_index?
546
+ validate_index_length!(table_name, new_name) if respond_to?(:validate_index_length!)
547
+ execute "ALTER TABLE #{quote_table_name(table_name)} RENAME INDEX #{quote_table_name(old_name)} TO #{quote_table_name(new_name)}"
548
+ else
549
+ super
550
+ end
551
+ end
552
+
553
+ # @private
554
+ ForeignKeyDefinition = ::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition if ::ActiveRecord::ConnectionAdapters.const_defined? :ForeignKeyDefinition
555
+
556
+ # @override
557
+ def supports_foreign_keys?; true end
558
+
559
+ def foreign_keys(table_name)
560
+ fk_info = select_all "" <<
561
+ "SELECT fk.referenced_table_name as 'to_table' " <<
562
+ ",fk.referenced_column_name as 'primary_key' " <<
563
+ ",fk.column_name as 'column' " <<
564
+ ",fk.constraint_name as 'name' " <<
565
+ "FROM information_schema.key_column_usage fk " <<
566
+ "WHERE fk.referenced_column_name is not null " <<
567
+ "AND fk.table_schema = '#{current_database}' " <<
568
+ "AND fk.table_name = '#{table_name}'"
569
+
570
+ create_table_info = select_one("SHOW CREATE TABLE #{quote_table_name(table_name)}")["Create Table"]
571
+
572
+ fk_info.map! do |row|
573
+ options = {
574
+ :column => row['column'], :name => row['name'], :primary_key => row['primary_key']
575
+ }
576
+ options[:on_update] = extract_foreign_key_action(create_table_info, row['name'], "UPDATE")
577
+ options[:on_delete] = extract_foreign_key_action(create_table_info, row['name'], "DELETE")
578
+
579
+ ForeignKeyDefinition.new(table_name, row['to_table'], options)
580
+ end
581
+ end if defined? ForeignKeyDefinition
582
+
583
+ def extract_foreign_key_action(structure, name, action)
584
+ if structure =~ /CONSTRAINT #{quote_column_name(name)} FOREIGN KEY .* REFERENCES .* ON #{action} (CASCADE|SET NULL|RESTRICT)/
585
+ case $1
586
+ when 'CASCADE'; :cascade
587
+ when 'SET NULL'; :nullify
588
+ end
589
+ end
590
+ end
591
+ private :extract_foreign_key_action
592
+
593
+ # @override
594
+ def add_column(table_name, column_name, type, options = {})
595
+ add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
596
+ add_column_options!(add_column_sql, options)
597
+ add_column_position!(add_column_sql, options)
598
+ execute(add_column_sql)
599
+ end unless const_defined? :SchemaCreation
600
+
601
+ def change_column_default(table_name, column_name, default)
602
+ column = column_for(table_name, column_name)
603
+ change_column table_name, column_name, column.sql_type, :default => default
604
+ end # unless const_defined? :SchemaCreation
605
+
606
+ def change_column_null(table_name, column_name, null, default = nil)
607
+ column = column_for(table_name, column_name)
608
+
609
+ unless null || default.nil?
610
+ execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
611
+ end
612
+
613
+ change_column table_name, column_name, column.sql_type, :null => null
614
+ end # unless const_defined? :SchemaCreation
615
+
616
+ # @override
617
+ def change_column(table_name, column_name, type, options = {})
618
+ column = column_for(table_name, column_name)
619
+
620
+ unless options_include_default?(options)
621
+ # NOTE: no defaults for BLOB/TEXT columns with MySQL
622
+ options[:default] = column.default if type != :text && type != :binary
623
+ end
624
+
625
+ unless options.has_key?(:null)
626
+ options[:null] = column.null
627
+ end
628
+
629
+ change_column_sql = "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
630
+ add_column_options!(change_column_sql, options)
631
+ add_column_position!(change_column_sql, options)
632
+ execute(change_column_sql)
633
+ end
634
+
635
+ # @private
636
+ def change_column(table_name, column_name, type, options = {})
637
+ execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_sql(table_name, column_name, type, options)}")
638
+ end if AR42
639
+
640
+ # @override
641
+ def rename_column(table_name, column_name, new_column_name)
642
+ options = {}
643
+
644
+ if column = columns(table_name).find { |c| c.name == column_name.to_s }
645
+ type = column.type
646
+ options[:default] = column.default if type != :text && type != :binary
647
+ options[:null] = column.null
648
+ else
649
+ raise ActiveRecordError, "No such column: #{table_name}.#{column_name}"
650
+ end
651
+
652
+ current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"]
653
+
654
+ rename_column_sql = "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}"
655
+ add_column_options!(rename_column_sql, options)
656
+ execute(rename_column_sql)
657
+ rename_column_indexes(table_name, column_name, new_column_name) if respond_to?(:rename_column_indexes) # AR-4.0 SchemaStatements
658
+ end
659
+
660
+ def add_column_position!(sql, options)
661
+ if options[:first]
662
+ sql << " FIRST"
663
+ elsif options[:after]
664
+ sql << " AFTER #{quote_column_name(options[:after])}"
665
+ end
666
+ end unless const_defined? :SchemaCreation
667
+
668
+ # @note Only used with (non-AREL) ActiveRecord **2.3**.
669
+ # @see Arel::Visitors::MySQL
670
+ def add_limit_offset!(sql, options)
671
+ limit, offset = options[:limit], options[:offset]
672
+ if limit && offset
673
+ sql << " LIMIT #{offset.to_i}, #{sanitize_limit(limit)}"
674
+ elsif limit
675
+ sql << " LIMIT #{sanitize_limit(limit)}"
676
+ elsif offset
677
+ sql << " OFFSET #{offset.to_i}"
678
+ end
679
+ sql
680
+ end if ::ActiveRecord::VERSION::MAJOR < 3
681
+
682
+ # In the simple case, MySQL allows us to place JOINs directly into the UPDATE
683
+ # query. However, this does not allow for LIMIT, OFFSET and ORDER. To support
684
+ # these, we must use a subquery. However, MySQL is too stupid to create a
685
+ # temporary table for this automatically, so we have to give it some prompting
686
+ # in the form of a subsubquery. Ugh!
687
+ # @private based on mysql_adapter.rb from 3.1-stable
688
+ def join_to_update(update, select)
689
+ if select.limit || select.offset || select.orders.any?
690
+ subsubselect = select.clone
691
+ subsubselect.projections = [update.key]
692
+
693
+ subselect = Arel::SelectManager.new(select.engine)
694
+ subselect.project Arel.sql(update.key.name)
695
+ subselect.from subsubselect.as('__active_record_temp')
696
+
697
+ update.where update.key.in(subselect)
698
+ else
699
+ update.table select.source
700
+ update.wheres = select.constraints
701
+ end
702
+ end
703
+
704
+ def show_variable(var)
705
+ res = execute("show variables like '#{var}'")
706
+ result_row = res.detect {|row| row["Variable_name"] == var }
707
+ result_row && result_row["Value"]
708
+ end
709
+
710
+ def charset
711
+ show_variable("character_set_database")
712
+ end
713
+
714
+ def collation
715
+ show_variable("collation_database")
716
+ end
717
+
718
+ # Maps logical Rails types to MySQL-specific data types.
719
+ def type_to_sql(type, limit = nil, precision = nil, scale = nil)
720
+ case type.to_s
721
+ when 'binary'
722
+ case limit
723
+ when 0..0xfff; "varbinary(#{limit})"
724
+ when nil; "blob"
725
+ when 0x1000..0xffffffff; "blob(#{limit})"
726
+ else raise(ActiveRecordError, "No binary type has character length #{limit}")
727
+ end
728
+ when 'integer'
729
+ case limit
730
+ when 1; 'tinyint'
731
+ when 2; 'smallint'
732
+ when 3; 'mediumint'
733
+ when nil, 4, 11; 'int(11)' # compatibility with MySQL default
734
+ when 5..8; 'bigint'
735
+ else raise(ActiveRecordError, "No integer type has byte size #{limit}")
736
+ end
737
+ when 'text'
738
+ case limit
739
+ when 0..0xff; 'tinytext'
740
+ when nil, 0x100..0xffff; 'text'
741
+ when 0x10000..0xffffff; 'mediumtext'
742
+ when 0x1000000..0xffffffff; 'longtext'
743
+ else raise(ActiveRecordError, "No text type has character length #{limit}")
744
+ end
745
+ when 'datetime'
746
+ return super unless precision
747
+
748
+ case precision
749
+ when 0..6; "datetime(#{precision})"
750
+ else raise(ActiveRecordError, "No datetime type has precision of #{precision}. The allowed range of precision is from 0 to 6.")
751
+ end
752
+ else
753
+ super
754
+ end
755
+ end
756
+
757
+ # @override
758
+ def empty_insert_statement_value
759
+ "VALUES ()"
760
+ end
761
+
762
+ # @note since AR 4.2
763
+ def valid_type?(type)
764
+ ! native_database_types[type].nil?
765
+ end
766
+
767
+ def clear_cache!
768
+ super
769
+ reload_type_map
770
+ end if AR42
771
+
772
+ # @private since AR 4.2
773
+ def prepare_column_options(column, types)
774
+ spec = super
775
+ spec.delete(:limit) if column.type == :boolean
776
+ spec
777
+ end if AR42
778
+
779
+ # @private
780
+ Type = ActiveRecord::Type if AR42
781
+
782
+ protected
783
+
784
+ # @private
785
+ def initialize_type_map(m)
786
+ super
787
+
788
+ register_class_with_limit m, %r(char)i, MysqlString
789
+
790
+ m.register_type %r(tinytext)i, Type::Text.new(:limit => 2**8 - 1)
791
+ m.register_type %r(tinyblob)i, Type::Binary.new(:limit => 2**8 - 1)
792
+ m.register_type %r(text)i, Type::Text.new(:limit => 2**16 - 1)
793
+ m.register_type %r(blob)i, Type::Binary.new(:limit => 2**16 - 1)
794
+ m.register_type %r(mediumtext)i, Type::Text.new(:limit => 2**24 - 1)
795
+ m.register_type %r(mediumblob)i, Type::Binary.new(:limit => 2**24 - 1)
796
+ m.register_type %r(longtext)i, Type::Text.new(:limit => 2**32 - 1)
797
+ m.register_type %r(longblob)i, Type::Binary.new(:limit => 2**32 - 1)
798
+ m.register_type %r(^float)i, Type::Float.new(:limit => 24)
799
+ m.register_type %r(^double)i, Type::Float.new(:limit => 53)
800
+
801
+ register_integer_type m, %r(^bigint)i, :limit => 8
802
+ register_integer_type m, %r(^int)i, :limit => 4
803
+ register_integer_type m, %r(^mediumint)i, :limit => 3
804
+ register_integer_type m, %r(^smallint)i, :limit => 2
805
+ register_integer_type m, %r(^tinyint)i, :limit => 1
806
+
807
+ m.alias_type %r(tinyint\(1\))i, 'boolean' if emulate_booleans
808
+ m.alias_type %r(set)i, 'varchar'
809
+ m.alias_type %r(year)i, 'integer'
810
+ m.alias_type %r(bit)i, 'binary'
811
+
812
+ m.register_type(%r(datetime)i) do |sql_type|
813
+ precision = extract_precision(sql_type)
814
+ MysqlDateTime.new(:precision => precision)
815
+ end
816
+
817
+ m.register_type(%r(enum)i) do |sql_type|
818
+ limit = sql_type[/^enum\((.+)\)/i, 1].split(',').
819
+ map{|enum| enum.strip.length - 2}.max
820
+ MysqlString.new(:limit => limit)
821
+ end
822
+ end if AR42
823
+
824
+ # @private
825
+ def register_integer_type(mapping, key, options)
826
+ mapping.register_type(key) do |sql_type|
827
+ if /unsigned/i =~ sql_type
828
+ Type::UnsignedInteger.new(options)
829
+ else
830
+ Type::Integer.new(options)
831
+ end
832
+ end
833
+ end if AR42
834
+
835
+ # MySQL is too stupid to create a temporary table for use subquery, so we have
836
+ # to give it some prompting in the form of a subsubquery. Ugh!
837
+ # @note since AR 4.2
838
+ def subquery_for(key, select)
839
+ subsubselect = select.clone
840
+ subsubselect.projections = [key]
841
+
842
+ subselect = Arel::SelectManager.new(select.engine)
843
+ subselect.project Arel.sql(key.name)
844
+ subselect.from subsubselect.as('__active_record_temp')
845
+ end if AR42
846
+
847
+ def quoted_columns_for_index(column_names, options = {})
848
+ length = options[:length] if options.is_a?(Hash)
849
+
850
+ case length
851
+ when Hash
852
+ column_names.map { |name| length[name] ? "#{quote_column_name(name)}(#{length[name]})" : quote_column_name(name) }
853
+ when Fixnum
854
+ column_names.map { |name| "#{quote_column_name(name)}(#{length})" }
855
+ else
856
+ column_names.map { |name| quote_column_name(name) }
857
+ end
858
+ end
859
+
860
+ # @override
861
+ def translate_exception(exception, message)
862
+ return super unless exception.respond_to?(:errno)
863
+
864
+ case exception.errno
865
+ when 1062
866
+ ::ActiveRecord::RecordNotUnique.new(message, exception)
867
+ when 1452
868
+ ::ActiveRecord::InvalidForeignKey.new(message, exception)
869
+ else
870
+ super
871
+ end
872
+ end
873
+
874
+ private
875
+
876
+ def column_for(table_name, column_name)
877
+ unless column = columns(table_name).find { |c| c.name == column_name.to_s }
878
+ raise "No such column: #{table_name}.#{column_name}"
879
+ end
880
+ column
881
+ end
882
+
883
+ def mariadb?; !! ( full_version =~ /mariadb/i ) end
884
+
885
+ def version
886
+ return @version ||= begin
887
+ version = []
888
+ java_connection = jdbc_connection(true)
889
+ if java_connection.java_class.name == 'com.mysql.jdbc.ConnectionImpl'
890
+ version << jdbc_connection.serverMajorVersion
891
+ version << jdbc_connection.serverMinorVersion
892
+ version << jdbc_connection.serverSubMinorVersion
893
+ else
894
+ if match = full_version.match(/^(\d+)\.(\d+)\.(\d+)/)
895
+ version << match[1].to_i
896
+ version << match[2].to_i
897
+ version << match[3].to_i
898
+ end
899
+ end
900
+ version.freeze
901
+ end
902
+ end
903
+
904
+ def full_version
905
+ @full_version ||= begin
906
+ result = execute 'SELECT VERSION()', 'SCHEMA'
907
+ result.first.values.first # [{"VERSION()"=>"5.5.37-0ubuntu..."}]
908
+ end
909
+ end
910
+
911
+ # @private
912
+ def emulate_booleans; ::ArJdbc::MySQL.emulate_booleans?; end # due AR 4.2
913
+ public :emulate_booleans
914
+
915
+ # @private
916
+ class MysqlDateTime < Type::DateTime
917
+ private
918
+
919
+ def has_precision?
920
+ precision || 0
921
+ end
922
+ end if AR42
923
+
924
+ # @private
925
+ class MysqlString < Type::String
926
+ def type_cast_for_database(value)
927
+ case value
928
+ when true then "1"
929
+ when false then "0"
930
+ else super
931
+ end
932
+ end
933
+
934
+ private
935
+
936
+ def cast_value(value)
937
+ case value
938
+ when true then "1"
939
+ when false then "0"
940
+ else super
941
+ end
942
+ end
943
+ end if AR42
944
+
945
+ end
946
+ end
947
+
948
+ module ActiveRecord
949
+ module ConnectionAdapters
950
+ # Remove any vestiges of core/Ruby MySQL adapter
951
+ remove_const(:MysqlAdapter) if const_defined?(:MysqlAdapter)
952
+
953
+ class MysqlAdapter < JdbcAdapter
954
+ include ::ArJdbc::MySQL
955
+ include ::ArJdbc::MySQL::ExplainSupport
956
+
957
+ # By default, the MysqlAdapter will consider all columns of type
958
+ # __tinyint(1)__ as boolean. If you wish to disable this :
959
+ # ```
960
+ # ActiveRecord::ConnectionAdapters::Mysql[2]Adapter.emulate_booleans = false
961
+ # ```
962
+ def self.emulate_booleans?; ::ArJdbc::MySQL.emulate_booleans?; end
963
+ def self.emulate_booleans; ::ArJdbc::MySQL.emulate_booleans?; end # native adapter
964
+ def self.emulate_booleans=(emulate); ::ArJdbc::MySQL.emulate_booleans = emulate; end
965
+
966
+ class Column < JdbcColumn
967
+ include ::ArJdbc::MySQL::ColumnMethods
968
+
969
+ # @note {#ArJdbc::MySQL::ColumnMethods} uses this to check for boolean emulation
970
+ def adapter; MysqlAdapter end
971
+
972
+ end
973
+ end
974
+
975
+ if ActiveRecord::VERSION::MAJOR < 3 ||
976
+ ( ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR <= 1 )
977
+ remove_const(:MysqlColumn) if const_defined?(:MysqlColumn)
978
+ MysqlColumn = MysqlAdapter::Column
979
+ end
980
+
981
+ if ActiveRecord::VERSION::MAJOR > 3 ||
982
+ ( ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR >= 1 )
983
+ remove_const(:Mysql2Adapter) if const_defined?(:Mysql2Adapter)
984
+ Mysql2Adapter = MysqlAdapter
985
+ if ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 1
986
+ remove_const(:Mysql2Column) if const_defined?(:Mysql2Column)
987
+ Mysql2Column = MysqlAdapter::Column
988
+ end
989
+ end
990
+
991
+ end
992
+ end
993
+
994
+ module ArJdbc
995
+ module MySQL
996
+ Column = ::ActiveRecord::ConnectionAdapters::MysqlAdapter::Column
997
+ end
998
+ end