c3-activerecord-jdbc-adapter 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (188) hide show
  1. data/History.txt +452 -0
  2. data/LICENSE.txt +21 -0
  3. data/Manifest.txt +194 -0
  4. data/README.txt +181 -0
  5. data/Rakefile +10 -0
  6. data/lib/active_record/connection_adapters/derby_adapter.rb +1 -0
  7. data/lib/active_record/connection_adapters/h2_adapter.rb +1 -0
  8. data/lib/active_record/connection_adapters/hsqldb_adapter.rb +1 -0
  9. data/lib/active_record/connection_adapters/informix_adapter.rb +1 -0
  10. data/lib/active_record/connection_adapters/jdbc_adapter.rb +1 -0
  11. data/lib/active_record/connection_adapters/jndi_adapter.rb +1 -0
  12. data/lib/active_record/connection_adapters/mssql_adapter.rb +1 -0
  13. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -0
  14. data/lib/active_record/connection_adapters/mysql_adapter.rb +1 -0
  15. data/lib/active_record/connection_adapters/oracle_adapter.rb +1 -0
  16. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -0
  17. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -0
  18. data/lib/active_record/connection_adapters/teradata_adapter.rb +1 -0
  19. data/lib/activerecord-jdbc-adapter.rb +8 -0
  20. data/lib/arel/engines/sql/compilers/db2_compiler.rb +9 -0
  21. data/lib/arel/engines/sql/compilers/derby_compiler.rb +6 -0
  22. data/lib/arel/engines/sql/compilers/h2_compiler.rb +6 -0
  23. data/lib/arel/engines/sql/compilers/hsqldb_compiler.rb +15 -0
  24. data/lib/arel/engines/sql/compilers/jdbc_compiler.rb +6 -0
  25. data/lib/arel/engines/sql/compilers/mssql_compiler.rb +46 -0
  26. data/lib/arel/visitors/compat.rb +13 -0
  27. data/lib/arel/visitors/db2.rb +17 -0
  28. data/lib/arel/visitors/derby.rb +21 -0
  29. data/lib/arel/visitors/firebird.rb +17 -0
  30. data/lib/arel/visitors/hsqldb.rb +26 -0
  31. data/lib/arel/visitors/sql_server.rb +44 -0
  32. data/lib/arjdbc.rb +29 -0
  33. data/lib/arjdbc/db2.rb +2 -0
  34. data/lib/arjdbc/db2/adapter.rb +421 -0
  35. data/lib/arjdbc/derby.rb +7 -0
  36. data/lib/arjdbc/derby/adapter.rb +352 -0
  37. data/lib/arjdbc/derby/connection_methods.rb +18 -0
  38. data/lib/arjdbc/discover.rb +99 -0
  39. data/lib/arjdbc/firebird.rb +2 -0
  40. data/lib/arjdbc/firebird/adapter.rb +136 -0
  41. data/lib/arjdbc/h2.rb +4 -0
  42. data/lib/arjdbc/h2/adapter.rb +36 -0
  43. data/lib/arjdbc/h2/connection_methods.rb +12 -0
  44. data/lib/arjdbc/hsqldb.rb +4 -0
  45. data/lib/arjdbc/hsqldb/adapter.rb +182 -0
  46. data/lib/arjdbc/hsqldb/connection_methods.rb +14 -0
  47. data/lib/arjdbc/informix.rb +3 -0
  48. data/lib/arjdbc/informix/adapter.rb +138 -0
  49. data/lib/arjdbc/informix/connection_methods.rb +10 -0
  50. data/lib/arjdbc/jdbc.rb +2 -0
  51. data/lib/arjdbc/jdbc/adapter.rb +283 -0
  52. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  53. data/lib/arjdbc/jdbc/callbacks.rb +44 -0
  54. data/lib/arjdbc/jdbc/column.rb +47 -0
  55. data/lib/arjdbc/jdbc/compatibility.rb +51 -0
  56. data/lib/arjdbc/jdbc/connection.rb +130 -0
  57. data/lib/arjdbc/jdbc/connection_methods.rb +16 -0
  58. data/lib/arjdbc/jdbc/core_ext.rb +24 -0
  59. data/lib/arjdbc/jdbc/discover.rb +18 -0
  60. data/lib/arjdbc/jdbc/driver.rb +35 -0
  61. data/lib/arjdbc/jdbc/extension.rb +47 -0
  62. data/lib/arjdbc/jdbc/java.rb +14 -0
  63. data/lib/arjdbc/jdbc/jdbc.rake +131 -0
  64. data/lib/arjdbc/jdbc/missing_functionality_helper.rb +87 -0
  65. data/lib/arjdbc/jdbc/quoted_primary_key.rb +28 -0
  66. data/lib/arjdbc/jdbc/railtie.rb +9 -0
  67. data/lib/arjdbc/jdbc/rake_tasks.rb +10 -0
  68. data/lib/arjdbc/jdbc/require_driver.rb +16 -0
  69. data/lib/arjdbc/jdbc/type_converter.rb +126 -0
  70. data/lib/arjdbc/mimer.rb +2 -0
  71. data/lib/arjdbc/mimer/adapter.rb +142 -0
  72. data/lib/arjdbc/mssql.rb +4 -0
  73. data/lib/arjdbc/mssql/adapter.rb +472 -0
  74. data/lib/arjdbc/mssql/connection_methods.rb +30 -0
  75. data/lib/arjdbc/mssql/limit_helpers.rb +98 -0
  76. data/lib/arjdbc/mssql/tsql_helper.rb +61 -0
  77. data/lib/arjdbc/mysql.rb +4 -0
  78. data/lib/arjdbc/mysql/adapter.rb +425 -0
  79. data/lib/arjdbc/mysql/connection_methods.rb +27 -0
  80. data/lib/arjdbc/oracle.rb +3 -0
  81. data/lib/arjdbc/oracle/adapter.rb +418 -0
  82. data/lib/arjdbc/oracle/connection_methods.rb +11 -0
  83. data/lib/arjdbc/postgresql.rb +4 -0
  84. data/lib/arjdbc/postgresql/adapter.rb +598 -0
  85. data/lib/arjdbc/postgresql/connection_methods.rb +21 -0
  86. data/lib/arjdbc/sqlite3.rb +4 -0
  87. data/lib/arjdbc/sqlite3/adapter.rb +381 -0
  88. data/lib/arjdbc/sqlite3/connection_methods.rb +34 -0
  89. data/lib/arjdbc/sybase.rb +2 -0
  90. data/lib/arjdbc/sybase/adapter.rb +46 -0
  91. data/lib/arjdbc/teradata.rb +3 -0
  92. data/lib/arjdbc/teradata/adapter.rb +81 -0
  93. data/lib/arjdbc/teradata/connection_methods.rb +11 -0
  94. data/lib/arjdbc/version.rb +8 -0
  95. data/lib/generators/jdbc/jdbc_generator.rb +9 -0
  96. data/lib/jdbc_adapter.rb +2 -0
  97. data/lib/jdbc_adapter/rake_tasks.rb +3 -0
  98. data/lib/jdbc_adapter/version.rb +3 -0
  99. data/lib/pg.rb +26 -0
  100. data/rails_generators/jdbc_generator.rb +15 -0
  101. data/rails_generators/templates/config/initializers/jdbc.rb +7 -0
  102. data/rails_generators/templates/lib/tasks/jdbc.rake +8 -0
  103. data/rakelib/compile.rake +25 -0
  104. data/rakelib/db.rake +19 -0
  105. data/rakelib/package.rake +92 -0
  106. data/rakelib/rails.rake +41 -0
  107. data/rakelib/test.rake +81 -0
  108. data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +62 -0
  109. data/src/java/arjdbc/derby/DerbyModule.java +322 -0
  110. data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +70 -0
  111. data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +74 -0
  112. data/src/java/arjdbc/jdbc/AdapterJavaService.java +70 -0
  113. data/src/java/arjdbc/jdbc/JdbcConnectionFactory.java +36 -0
  114. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +1328 -0
  115. data/src/java/arjdbc/jdbc/SQLBlock.java +48 -0
  116. data/src/java/arjdbc/mssql/MssqlRubyJdbcConnection.java +127 -0
  117. data/src/java/arjdbc/mysql/MySQLModule.java +134 -0
  118. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +87 -0
  119. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +85 -0
  120. data/src/java/arjdbc/postgresql/PostgresqlRubyJdbcConnection.java +57 -0
  121. data/src/java/arjdbc/sqlite3/Sqlite3RubyJdbcConnection.java +64 -0
  122. data/src/java/arjdbc/teradata/TeradataRubyJdbcConnection.java +62 -0
  123. data/test/abstract_db_create.rb +128 -0
  124. data/test/activerecord/connection_adapters/type_conversion_test.rb +31 -0
  125. data/test/activerecord/connections/native_jdbc_mysql/connection.rb +25 -0
  126. data/test/db/db2.rb +11 -0
  127. data/test/db/derby.rb +12 -0
  128. data/test/db/h2.rb +11 -0
  129. data/test/db/hsqldb.rb +13 -0
  130. data/test/db/informix.rb +11 -0
  131. data/test/db/jdbc.rb +11 -0
  132. data/test/db/jndi_config.rb +40 -0
  133. data/test/db/logger.rb +3 -0
  134. data/test/db/mssql.rb +9 -0
  135. data/test/db/mysql.rb +10 -0
  136. data/test/db/oracle.rb +34 -0
  137. data/test/db/postgres.rb +9 -0
  138. data/test/db/sqlite3.rb +11 -0
  139. data/test/db2_simple_test.rb +66 -0
  140. data/test/derby_migration_test.rb +68 -0
  141. data/test/derby_multibyte_test.rb +12 -0
  142. data/test/derby_simple_test.rb +99 -0
  143. data/test/generic_jdbc_connection_test.rb +29 -0
  144. data/test/h2_simple_test.rb +41 -0
  145. data/test/has_many_through.rb +79 -0
  146. data/test/helper.rb +5 -0
  147. data/test/hsqldb_simple_test.rb +6 -0
  148. data/test/informix_simple_test.rb +48 -0
  149. data/test/jdbc_common.rb +25 -0
  150. data/test/jndi_callbacks_test.rb +40 -0
  151. data/test/jndi_test.rb +25 -0
  152. data/test/manualTestDatabase.rb +191 -0
  153. data/test/models/add_not_null_column_to_table.rb +9 -0
  154. data/test/models/auto_id.rb +15 -0
  155. data/test/models/data_types.rb +30 -0
  156. data/test/models/entry.rb +40 -0
  157. data/test/models/mixed_case.rb +22 -0
  158. data/test/models/reserved_word.rb +15 -0
  159. data/test/models/string_id.rb +15 -0
  160. data/test/models/validates_uniqueness_of_string.rb +19 -0
  161. data/test/mssql_db_create_test.rb +26 -0
  162. data/test/mssql_identity_insert_test.rb +19 -0
  163. data/test/mssql_legacy_types_test.rb +58 -0
  164. data/test/mssql_limit_offset_test.rb +136 -0
  165. data/test/mssql_multibyte_test.rb +18 -0
  166. data/test/mssql_simple_test.rb +55 -0
  167. data/test/mysql_db_create_test.rb +27 -0
  168. data/test/mysql_info_test.rb +123 -0
  169. data/test/mysql_multibyte_test.rb +10 -0
  170. data/test/mysql_nonstandard_primary_key_test.rb +42 -0
  171. data/test/mysql_simple_test.rb +49 -0
  172. data/test/oracle_simple_test.rb +18 -0
  173. data/test/oracle_specific_test.rb +83 -0
  174. data/test/pick_rails_version.rb +3 -0
  175. data/test/postgres_db_create_test.rb +32 -0
  176. data/test/postgres_drop_db_test.rb +16 -0
  177. data/test/postgres_information_schema_leak_test.rb +29 -0
  178. data/test/postgres_mixed_case_test.rb +29 -0
  179. data/test/postgres_native_type_mapping_test.rb +84 -0
  180. data/test/postgres_nonseq_pkey_test.rb +38 -0
  181. data/test/postgres_reserved_test.rb +22 -0
  182. data/test/postgres_schema_search_path_test.rb +48 -0
  183. data/test/postgres_simple_test.rb +90 -0
  184. data/test/postgres_table_alias_length_test.rb +15 -0
  185. data/test/simple.rb +557 -0
  186. data/test/sqlite3_simple_test.rb +233 -0
  187. data/test/sybase_jtds_simple_test.rb +28 -0
  188. metadata +273 -0
@@ -0,0 +1,30 @@
1
+ class ActiveRecord::Base
2
+ class << self
3
+ def mssql_connection(config)
4
+ require "arjdbc/mssql"
5
+ config[:host] ||= "localhost"
6
+ config[:port] ||= 1433
7
+ config[:driver] ||= "net.sourceforge.jtds.jdbc.Driver"
8
+
9
+ url = "jdbc:jtds:sqlserver://#{config[:host]}:#{config[:port]}/#{config[:database]}"
10
+
11
+ # Instance is often a preferrable alternative to port when dynamic ports are used.
12
+ # If instance is specified then port is essentially ignored.
13
+ url << ";instance=#{config[:instance]}" if config[:instance]
14
+
15
+ # This will enable windows domain-based authentication and will require the JTDS native libraries be available.
16
+ url << ";domain=#{config[:domain]}" if config[:domain]
17
+
18
+ # AppName is shown in sql server as additional information against the connection.
19
+ url << ";appname=#{config[:appname]}" if config[:appname]
20
+ config[:url] ||= url
21
+
22
+ if !config[:domain]
23
+ config[:username] ||= "sa"
24
+ config[:password] ||= ""
25
+ end
26
+ jdbc_connection(config)
27
+ end
28
+ alias_method :jdbcmssql_connection, :mssql_connection
29
+ end
30
+ end
@@ -0,0 +1,98 @@
1
+ module ::ArJdbc
2
+ module MsSQL
3
+ module LimitHelpers
4
+ module_function
5
+ def get_table_name(sql)
6
+ if sql =~ /^\s*insert\s+into\s+([^\(\s,]+)\s*|^\s*update\s+([^\(\s,]+)\s*/i
7
+ $1
8
+ elsif sql =~ /\bfrom\s+([^\(\s,]+)\s*/i
9
+ $1
10
+ else
11
+ nil
12
+ end
13
+ end
14
+
15
+ module SqlServer2000ReplaceLimitOffset
16
+ module_function
17
+ def replace_limit_offset!(sql, limit, offset, order)
18
+ if limit
19
+ offset ||= 0
20
+ start_row = offset + 1
21
+ end_row = offset + limit.to_i
22
+ find_select = /\b(SELECT(?:\s+DISTINCT)?)\b(.*)/im
23
+ whole, select, rest_of_query = find_select.match(sql).to_a
24
+ if (start_row == 1) && (end_row ==1)
25
+ new_sql = "#{select} TOP 1 #{rest_of_query}"
26
+ sql.replace(new_sql)
27
+ else
28
+ #UGLY
29
+ #KLUDGY?
30
+ #removing out stuff before the FROM...
31
+ rest = rest_of_query[/FROM/i=~ rest_of_query.. -1]
32
+ #need the table name for avoiding amiguity
33
+ table_name = LimitHelpers.get_table_name(sql)
34
+ primary_key = order[/(\w*id\w*)/i]
35
+ #I am not sure this will cover all bases. but all the tests pass
36
+ new_order = "ORDER BY #{order}, #{table_name}.#{primary_key}" if order.index("#{table_name}.#{primary_key}").nil?
37
+ new_order ||= order
38
+
39
+ if (rest_of_query.match(/WHERE/).nil?)
40
+ new_sql = "#{select} TOP #{limit} #{rest_of_query} WHERE #{table_name}.#{primary_key} NOT IN (#{select} TOP #{offset} #{table_name}.#{primary_key} #{rest} #{new_order}) #{order} "
41
+ else
42
+ new_sql = "#{select} TOP #{limit} #{rest_of_query} AND #{table_name}.#{primary_key} NOT IN (#{select} TOP #{offset} #{table_name}.#{primary_key} #{rest} #{new_order}) #{order} "
43
+ end
44
+
45
+ sql.replace(new_sql)
46
+ end
47
+ end
48
+ sql
49
+ end
50
+ end
51
+
52
+ module SqlServer2000AddLimitOffset
53
+ def add_limit_offset!(sql, options)
54
+ if options[:limit]
55
+ order = "ORDER BY #{options[:order] || determine_order_clause(sql)}"
56
+ sql.sub!(/ ORDER BY.*$/i, '')
57
+ SqlServerReplaceLimitOffset.replace_limit_offset!(sql, options[:limit], options[:offset], order)
58
+ end
59
+ end
60
+ end
61
+
62
+ module SqlServerReplaceLimitOffset
63
+ module_function
64
+ def replace_limit_offset!(sql, limit, offset, order)
65
+ if limit
66
+ offset ||= 0
67
+ start_row = offset + 1
68
+ end_row = offset + limit.to_i
69
+ find_select = /\b(SELECT(?:\s+DISTINCT)?)\b(.*)/im
70
+ whole, select, rest_of_query = find_select.match(sql).to_a
71
+ rest_of_query.strip!
72
+ if rest_of_query[0] == "1"
73
+ rest_of_query[0] = "*"
74
+ end
75
+ if rest_of_query[0] == "*"
76
+ from_table = LimitHelpers.get_table_name(rest_of_query)
77
+ rest_of_query = from_table + '.' + rest_of_query
78
+ end
79
+ new_sql = "#{select} t.* FROM (SELECT ROW_NUMBER() OVER(#{order}) AS _row_num, #{rest_of_query}"
80
+ new_sql << ") AS t WHERE t._row_num BETWEEN #{start_row.to_s} AND #{end_row.to_s}"
81
+ sql.replace(new_sql)
82
+ end
83
+ sql
84
+ end
85
+ end
86
+
87
+ module SqlServerAddLimitOffset
88
+ def add_limit_offset!(sql, options)
89
+ if options[:limit]
90
+ order = "ORDER BY #{options[:order] || determine_order_clause(sql)}"
91
+ sql.sub!(/ ORDER BY.*$/i, '')
92
+ SqlServerReplaceLimitOffset.replace_limit_offset!(sql, options[:limit], options[:offset], order)
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,61 @@
1
+ # Common methods for handling TSQL databases.
2
+ module TSqlMethods
3
+
4
+ def modify_types(tp) #:nodoc:
5
+ tp[:primary_key] = "int NOT NULL IDENTITY(1, 1) PRIMARY KEY"
6
+ tp[:integer][:limit] = nil
7
+ tp[:boolean] = {:name => "bit"}
8
+ tp[:binary] = { :name => "image"}
9
+ tp
10
+ end
11
+
12
+ def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
13
+ limit = nil if %w(text binary).include? type.to_s
14
+ return 'uniqueidentifier' if (type.to_s == 'uniqueidentifier')
15
+ return super unless type.to_s == 'integer'
16
+
17
+ if limit.nil? || limit == 4
18
+ 'int'
19
+ elsif limit == 2
20
+ 'smallint'
21
+ elsif limit == 1
22
+ 'tinyint'
23
+ else
24
+ 'bigint'
25
+ end
26
+ end
27
+
28
+ def add_limit_offset!(sql, options)
29
+ if options[:limit] and options[:offset]
30
+ total_rows = select_all("SELECT count(*) as TotalRows from (#{sql.gsub(/\bSELECT(\s+DISTINCT)?\b/i, "SELECT\\1 TOP 1000000000")}) tally")[0]["TotalRows"].to_i
31
+ if (options[:limit] + options[:offset]) >= total_rows
32
+ options[:limit] = (total_rows - options[:offset] >= 0) ? (total_rows - options[:offset]) : 0
33
+ end
34
+ sql.sub!(/^\s*SELECT(\s+DISTINCT)?/i, "SELECT * FROM (SELECT TOP #{options[:limit]} * FROM (SELECT\\1 TOP #{options[:limit] + options[:offset]} ")
35
+ sql << ") AS tmp1"
36
+ if options[:order]
37
+ options[:order] = options[:order].split(',').map do |field|
38
+ parts = field.split(" ")
39
+ tc = parts[0]
40
+ if sql =~ /\.\[/ and tc =~ /\./ # if column quoting used in query
41
+ tc.gsub!(/\./, '\\.\\[')
42
+ tc << '\\]'
43
+ end
44
+ if sql =~ /#{tc} AS (t\d_r\d\d?)/
45
+ parts[0] = $1
46
+ elsif parts[0] =~ /\w+\.(\w+)/
47
+ parts[0] = $1
48
+ end
49
+ parts.join(' ')
50
+ end.join(', ')
51
+ sql << " ORDER BY #{change_order_direction(options[:order])}) AS tmp2 ORDER BY #{options[:order]}"
52
+ else
53
+ sql << " ) AS tmp2"
54
+ end
55
+ elsif sql !~ /^\s*SELECT (@@|COUNT\()/i
56
+ sql.sub!(/^\s*SELECT(\s+DISTINCT)?/i) do
57
+ "SELECT#{$1} TOP #{options[:limit]}"
58
+ end unless options[:limit].nil?
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,4 @@
1
+ require 'arjdbc/jdbc'
2
+ jdbc_require_driver 'jdbc/mysql'
3
+ require 'arjdbc/mysql/connection_methods'
4
+ require 'arjdbc/mysql/adapter'
@@ -0,0 +1,425 @@
1
+ require 'active_record/connection_adapters/abstract/schema_definitions'
2
+
3
+ module ::ArJdbc
4
+ module MySQL
5
+ def self.column_selector
6
+ [/mysql/i, lambda {|cfg,col| col.extend(::ArJdbc::MySQL::Column)}]
7
+ end
8
+
9
+ def self.extended(adapter)
10
+ adapter.configure_connection
11
+ end
12
+
13
+ def configure_connection
14
+ execute("SET SQL_AUTO_IS_NULL=0")
15
+ end
16
+
17
+ def self.jdbc_connection_class
18
+ ::ActiveRecord::ConnectionAdapters::MySQLJdbcConnection
19
+ end
20
+
21
+ module Column
22
+ def extract_default(default)
23
+ if sql_type =~ /blob/i || type == :text
24
+ if default.blank?
25
+ return null ? nil : ''
26
+ else
27
+ raise ArgumentError, "#{type} columns cannot have a default value: #{default.inspect}"
28
+ end
29
+ elsif missing_default_forged_as_empty_string?(default)
30
+ nil
31
+ else
32
+ super
33
+ end
34
+ end
35
+
36
+ def has_default?
37
+ return false if sql_type =~ /blob/i || type == :text #mysql forbids defaults on blob and text columns
38
+ super
39
+ end
40
+
41
+ def simplified_type(field_type)
42
+ case field_type
43
+ when /tinyint\(1\)|bit/i then :boolean
44
+ when /enum/i then :string
45
+ when /decimal/i then :decimal
46
+ else
47
+ super
48
+ end
49
+ end
50
+
51
+ def extract_limit(sql_type)
52
+ case sql_type
53
+ when /blob|text/i
54
+ case sql_type
55
+ when /tiny/i
56
+ 255
57
+ when /medium/i
58
+ 16777215
59
+ when /long/i
60
+ 2147483647 # mysql only allows 2^31-1, not 2^32-1, somewhat inconsistently with the tiny/medium/normal cases
61
+ else
62
+ nil # we could return 65535 here, but we leave it undecorated by default
63
+ end
64
+ when /^bigint/i; 8
65
+ when /^int/i; 4
66
+ when /^mediumint/i; 3
67
+ when /^smallint/i; 2
68
+ when /^tinyint/i; 1
69
+ when /^(bool|date|float|int|time)/i
70
+ nil
71
+ else
72
+ super
73
+ end
74
+ end
75
+
76
+ # MySQL misreports NOT NULL column default when none is given.
77
+ # We can't detect this for columns which may have a legitimate ''
78
+ # default (string) but we can for others (integer, datetime, boolean,
79
+ # and the rest).
80
+ #
81
+ # Test whether the column has default '', is not null, and is not
82
+ # a type allowing default ''.
83
+ def missing_default_forged_as_empty_string?(default)
84
+ type != :string && !null && default == ''
85
+ end
86
+ end
87
+
88
+ def modify_types(tp)
89
+ tp[:primary_key] = "int(11) DEFAULT NULL auto_increment PRIMARY KEY"
90
+ tp[:integer] = { :name => 'int', :limit => 4 }
91
+ tp[:decimal] = { :name => "decimal" }
92
+ tp[:timestamp] = { :name => "datetime" }
93
+ tp[:datetime][:limit] = nil
94
+ tp
95
+ end
96
+
97
+ def adapter_name #:nodoc:
98
+ 'MySQL'
99
+ end
100
+
101
+ def arel2_visitors
102
+ {'jdbcmysql' => ::Arel::Visitors::MySQL}
103
+ end
104
+
105
+ def case_sensitive_equality_operator
106
+ "= BINARY"
107
+ end
108
+
109
+ def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key)
110
+ where_sql
111
+ end
112
+
113
+ # QUOTING ==================================================
114
+
115
+ def quote(value, column = nil)
116
+ return value.quoted_id if value.respond_to?(:quoted_id)
117
+
118
+ if column && column.type == :primary_key
119
+ value.to_s
120
+ elsif column && String === value && column.type == :binary && column.class.respond_to?(:string_to_binary)
121
+ s = column.class.string_to_binary(value).unpack("H*")[0]
122
+ "x'#{s}'"
123
+ elsif BigDecimal === value
124
+ "'#{value.to_s("F")}'"
125
+ else
126
+ super
127
+ end
128
+ end
129
+
130
+ def quoted_true
131
+ "1"
132
+ end
133
+
134
+ def quoted_false
135
+ "0"
136
+ end
137
+
138
+ def begin_db_transaction #:nodoc:
139
+ @connection.begin
140
+ rescue Exception
141
+ # Transactions aren't supported
142
+ end
143
+
144
+ def commit_db_transaction #:nodoc:
145
+ @connection.commit
146
+ rescue Exception
147
+ # Transactions aren't supported
148
+ end
149
+
150
+ def rollback_db_transaction #:nodoc:
151
+ @connection.rollback
152
+ rescue Exception
153
+ # Transactions aren't supported
154
+ end
155
+
156
+ def supports_savepoints? #:nodoc:
157
+ true
158
+ end
159
+
160
+ def create_savepoint
161
+ execute("SAVEPOINT #{current_savepoint_name}")
162
+ end
163
+
164
+ def rollback_to_savepoint
165
+ execute("ROLLBACK TO SAVEPOINT #{current_savepoint_name}")
166
+ end
167
+
168
+ def release_savepoint
169
+ execute("RELEASE SAVEPOINT #{current_savepoint_name}")
170
+ end
171
+
172
+ def disable_referential_integrity(&block) #:nodoc:
173
+ old = select_value("SELECT @@FOREIGN_KEY_CHECKS")
174
+ begin
175
+ update("SET FOREIGN_KEY_CHECKS = 0")
176
+ yield
177
+ ensure
178
+ update("SET FOREIGN_KEY_CHECKS = #{old}")
179
+ end
180
+ end
181
+
182
+ # SCHEMA STATEMENTS ========================================
183
+
184
+ def structure_dump #:nodoc:
185
+ if supports_views?
186
+ sql = "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'"
187
+ else
188
+ sql = "SHOW TABLES"
189
+ end
190
+
191
+ select_all(sql).inject("") do |structure, table|
192
+ table.delete('Table_type')
193
+
194
+ hash = show_create_table(table.to_a.first.last)
195
+
196
+ if(table = hash["Create Table"])
197
+ structure += table + ";\n\n"
198
+ elsif(view = hash["Create View"])
199
+ structure += view + ";\n\n"
200
+ end
201
+ end
202
+ end
203
+
204
+ def jdbc_columns(table_name, name = nil)#:nodoc:
205
+ sql = "SHOW FIELDS FROM #{quote_table_name(table_name)}"
206
+ execute(sql, :skip_logging).map do |field|
207
+ ::ActiveRecord::ConnectionAdapters::MysqlColumn.new(field["Field"], field["Default"], field["Type"], field["Null"] == "YES")
208
+ end
209
+ end
210
+
211
+ def recreate_database(name, options = {}) #:nodoc:
212
+ drop_database(name)
213
+ create_database(name, options)
214
+ end
215
+
216
+ def create_database(name, options = {}) #:nodoc:
217
+ if options[:collation]
218
+ execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}` COLLATE `#{options[:collation]}`"
219
+ else
220
+ execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}`"
221
+ end
222
+ end
223
+
224
+ def drop_database(name) #:nodoc:
225
+ execute "DROP DATABASE IF EXISTS `#{name}`"
226
+ end
227
+
228
+ def current_database
229
+ select_one("SELECT DATABASE() as db")["db"]
230
+ end
231
+
232
+ def create_table(name, options = {}) #:nodoc:
233
+ super(name, {:options => "ENGINE=InnoDB"}.merge(options))
234
+ end
235
+
236
+ def rename_table(name, new_name)
237
+ execute "RENAME TABLE #{quote_table_name(name)} TO #{quote_table_name(new_name)}"
238
+ end
239
+
240
+ def add_column(table_name, column_name, type, options = {})
241
+ 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])}"
242
+ add_column_options!(add_column_sql, options)
243
+ add_column_position!(add_column_sql, options)
244
+ execute(add_column_sql)
245
+ end
246
+
247
+ def change_column_default(table_name, column_name, default) #:nodoc:
248
+ column = column_for(table_name, column_name)
249
+ change_column table_name, column_name, column.sql_type, :default => default
250
+ end
251
+
252
+ def change_column_null(table_name, column_name, null, default = nil)
253
+ column = column_for(table_name, column_name)
254
+
255
+ unless null || default.nil?
256
+ execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
257
+ end
258
+
259
+ change_column table_name, column_name, column.sql_type, :null => null
260
+ end
261
+
262
+ def change_column(table_name, column_name, type, options = {}) #:nodoc:
263
+ column = column_for(table_name, column_name)
264
+
265
+ unless options_include_default?(options)
266
+ options[:default] = column.default
267
+ end
268
+
269
+ unless options.has_key?(:null)
270
+ options[:null] = column.null
271
+ end
272
+
273
+ 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])}"
274
+ add_column_options!(change_column_sql, options)
275
+ add_column_position!(change_column_sql, options)
276
+ execute(change_column_sql)
277
+ end
278
+
279
+ def rename_column(table_name, column_name, new_column_name) #:nodoc:
280
+ options = {}
281
+ if column = columns(table_name).find { |c| c.name == column_name.to_s }
282
+ options[:default] = column.default
283
+ options[:null] = column.null
284
+ else
285
+ raise ActiveRecord::ActiveRecordError, "No such column: #{table_name}.#{column_name}"
286
+ end
287
+ current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"]
288
+ rename_column_sql = "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}"
289
+ add_column_options!(rename_column_sql, options)
290
+ execute(rename_column_sql)
291
+ end
292
+
293
+ def add_limit_offset!(sql, options) #:nodoc:
294
+ limit, offset = options[:limit], options[:offset]
295
+ if limit && offset
296
+ sql << " LIMIT #{offset.to_i}, #{sanitize_limit(limit)}"
297
+ elsif limit
298
+ sql << " LIMIT #{sanitize_limit(limit)}"
299
+ elsif offset
300
+ sql << " OFFSET #{offset.to_i}"
301
+ end
302
+ sql
303
+ end
304
+
305
+ def show_variable(var)
306
+ res = execute("show variables like '#{var}'")
307
+ row = res.detect {|row| row["Variable_name"] == var }
308
+ row && row["Value"]
309
+ end
310
+
311
+ def charset
312
+ show_variable("character_set_database")
313
+ end
314
+
315
+ def collation
316
+ show_variable("collation_database")
317
+ end
318
+
319
+ def type_to_sql(type, limit = nil, precision = nil, scale = nil)
320
+ return super unless type.to_s == 'integer'
321
+
322
+ case limit
323
+ when 1; 'tinyint'
324
+ when 2; 'smallint'
325
+ when 3; 'mediumint'
326
+ when nil, 4, 11; 'int(11)' # compatibility with MySQL default
327
+ when 5..8; 'bigint'
328
+ else raise(ActiveRecordError, "No integer type has byte size #{limit}")
329
+ end
330
+ end
331
+
332
+ def add_column_position!(sql, options)
333
+ if options[:first]
334
+ sql << " FIRST"
335
+ elsif options[:after]
336
+ sql << " AFTER #{quote_column_name(options[:after])}"
337
+ end
338
+ end
339
+
340
+ protected
341
+ def translate_exception(exception, message)
342
+ return super unless exception.respond_to?(:errno)
343
+
344
+ case exception.errno
345
+ when 1062
346
+ ::ActiveRecord::RecordNotUnique.new(message, exception)
347
+ when 1452
348
+ ::ActiveRecord::InvalidForeignKey.new(message, exception)
349
+ else
350
+ super
351
+ end
352
+ end
353
+
354
+ private
355
+ def column_for(table_name, column_name)
356
+ unless column = columns(table_name).find { |c| c.name == column_name.to_s }
357
+ raise "No such column: #{table_name}.#{column_name}"
358
+ end
359
+ column
360
+ end
361
+
362
+ def show_create_table(table)
363
+ select_one("SHOW CREATE TABLE #{quote_table_name(table)}")
364
+ end
365
+
366
+ def supports_views?
367
+ false
368
+ end
369
+ end
370
+ end
371
+
372
+ module ActiveRecord::ConnectionAdapters
373
+ # Remove any vestiges of core/Ruby MySQL adapter
374
+ remove_const(:MysqlColumn) if const_defined?(:MysqlColumn)
375
+ remove_const(:MysqlAdapter) if const_defined?(:MysqlAdapter)
376
+
377
+ class MysqlColumn < JdbcColumn
378
+ include ArJdbc::MySQL::Column
379
+
380
+ def initialize(name, *args)
381
+ if Hash === name
382
+ super
383
+ else
384
+ super(nil, name, *args)
385
+ end
386
+ end
387
+
388
+ def call_discovered_column_callbacks(*)
389
+ end
390
+ end
391
+
392
+ class MysqlAdapter < JdbcAdapter
393
+ include ArJdbc::MySQL
394
+
395
+ def initialize(*args)
396
+ super
397
+ configure_connection
398
+ end
399
+
400
+ def adapter_spec(config)
401
+ # return nil to avoid extending ArJdbc::MySQL, which we've already done
402
+ end
403
+
404
+ def jdbc_connection_class(spec)
405
+ ::ArJdbc::MySQL.jdbc_connection_class
406
+ end
407
+
408
+ def jdbc_column_class
409
+ ActiveRecord::ConnectionAdapters::MysqlColumn
410
+ end
411
+
412
+ alias_chained_method :columns, :query_cache, :jdbc_columns
413
+ end
414
+ end
415
+
416
+ module Mysql # :nodoc:
417
+ remove_const(:Error) if const_defined?(:Error)
418
+
419
+ class Error < ::ActiveRecord::JDBCError
420
+ end
421
+
422
+ def self.client_version
423
+ 50400 # faked out for AR tests
424
+ end
425
+ end