activerecord-jdbc-adapter 1.3.0.beta1 → 1.3.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (161) hide show
  1. data/.gitignore +12 -11
  2. data/.travis.yml +36 -7
  3. data/Appraisals +3 -3
  4. data/Gemfile +1 -1
  5. data/Gemfile.lock +13 -6
  6. data/History.txt +64 -0
  7. data/README.md +8 -1
  8. data/Rakefile +3 -1
  9. data/gemfiles/rails23.gemfile +1 -1
  10. data/gemfiles/rails23.gemfile.lock +6 -5
  11. data/gemfiles/rails30.gemfile +1 -1
  12. data/gemfiles/rails30.gemfile.lock +7 -6
  13. data/gemfiles/rails31.gemfile +1 -1
  14. data/gemfiles/rails31.gemfile.lock +6 -5
  15. data/gemfiles/rails32.gemfile +1 -1
  16. data/gemfiles/rails32.gemfile.lock +6 -5
  17. data/gemfiles/rails40.gemfile +2 -4
  18. data/gemfiles/rails40.gemfile.lock +37 -51
  19. data/lib/active_record/connection_adapters/as400_adapter.rb +2 -0
  20. data/lib/active_record/connection_adapters/db2_adapter.rb +1 -1
  21. data/lib/arel/visitors/db2.rb +5 -1
  22. data/lib/arel/visitors/hsqldb.rb +1 -0
  23. data/lib/arel/visitors/sql_server.rb +55 -13
  24. data/lib/arjdbc/db2/adapter.rb +197 -227
  25. data/lib/arjdbc/db2/as400.rb +124 -0
  26. data/lib/arjdbc/db2/connection_methods.rb +20 -1
  27. data/lib/arjdbc/derby/adapter.rb +17 -85
  28. data/lib/arjdbc/derby/connection_methods.rb +2 -1
  29. data/lib/arjdbc/discover.rb +55 -47
  30. data/lib/arjdbc/h2/adapter.rb +52 -18
  31. data/lib/arjdbc/h2/connection_methods.rb +10 -2
  32. data/lib/arjdbc/hsqldb/adapter.rb +33 -9
  33. data/lib/arjdbc/hsqldb/connection_methods.rb +10 -2
  34. data/lib/arjdbc/informix.rb +2 -1
  35. data/lib/arjdbc/jdbc.rb +5 -1
  36. data/lib/arjdbc/jdbc/adapter.rb +167 -89
  37. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  38. data/lib/arjdbc/jdbc/adapter_require.rb +46 -0
  39. data/lib/arjdbc/jdbc/base_ext.rb +25 -3
  40. data/lib/arjdbc/jdbc/callbacks.rb +9 -8
  41. data/lib/arjdbc/jdbc/column.rb +8 -20
  42. data/lib/arjdbc/jdbc/connection.rb +69 -80
  43. data/lib/arjdbc/jdbc/extension.rb +6 -8
  44. data/lib/arjdbc/jdbc/jdbc.rake +3 -141
  45. data/lib/arjdbc/jdbc/rake_tasks.rb +3 -10
  46. data/lib/arjdbc/mssql/adapter.rb +108 -34
  47. data/lib/arjdbc/mssql/connection_methods.rb +3 -1
  48. data/lib/arjdbc/mssql/limit_helpers.rb +3 -2
  49. data/lib/arjdbc/mssql/lock_helpers.rb +5 -1
  50. data/lib/arjdbc/mysql/adapter.rb +127 -70
  51. data/lib/arjdbc/mysql/connection_methods.rb +5 -2
  52. data/lib/arjdbc/oracle/adapter.rb +124 -94
  53. data/lib/arjdbc/oracle/connection_methods.rb +2 -1
  54. data/lib/arjdbc/postgresql/adapter.rb +99 -67
  55. data/lib/arjdbc/postgresql/column_cast.rb +3 -5
  56. data/lib/arjdbc/postgresql/connection_methods.rb +6 -6
  57. data/lib/arjdbc/railtie.rb +3 -1
  58. data/lib/arjdbc/sqlite3/adapter.rb +60 -43
  59. data/lib/arjdbc/sqlite3/connection_methods.rb +9 -9
  60. data/lib/arjdbc/sybase.rb +1 -1
  61. data/lib/arjdbc/tasks.rb +13 -0
  62. data/lib/arjdbc/tasks/database_tasks.rb +50 -0
  63. data/lib/arjdbc/tasks/databases.rake +89 -0
  64. data/lib/arjdbc/tasks/databases3.rake +203 -0
  65. data/lib/arjdbc/tasks/databases4.rake +39 -0
  66. data/lib/arjdbc/tasks/db2_database_tasks.rb +104 -0
  67. data/lib/arjdbc/tasks/derby_database_tasks.rb +95 -0
  68. data/lib/arjdbc/tasks/h2_database_tasks.rb +29 -0
  69. data/lib/arjdbc/tasks/hsqldb_database_tasks.rb +70 -0
  70. data/lib/arjdbc/tasks/jdbc_database_tasks.rb +122 -0
  71. data/lib/arjdbc/tasks/mssql_database_tasks.rb +36 -0
  72. data/lib/arjdbc/tasks/oracle/enhanced_structure_dump.rb +297 -0
  73. data/lib/arjdbc/tasks/oracle_database_tasks.rb +62 -0
  74. data/lib/arjdbc/version.rb +1 -1
  75. data/pom.xml +11 -12
  76. data/rails_generators/jdbc_generator.rb +1 -1
  77. data/rails_generators/templates/config/initializers/jdbc.rb +8 -5
  78. data/rails_generators/templates/lib/tasks/jdbc.rake +7 -4
  79. data/rakelib/02-test.rake +42 -15
  80. data/rakelib/compile.rake +29 -2
  81. data/rakelib/db.rake +2 -1
  82. data/rakelib/rails.rake +23 -6
  83. data/src/java/arjdbc/ArJdbcModule.java +175 -0
  84. data/src/java/arjdbc/db2/DB2Module.java +2 -1
  85. data/src/java/arjdbc/derby/DerbyModule.java +5 -24
  86. data/src/java/arjdbc/hsqldb/HSQLDBModule.java +3 -2
  87. data/src/java/arjdbc/jdbc/AdapterJavaService.java +3 -46
  88. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +1001 -259
  89. data/src/java/arjdbc/mssql/MSSQLModule.java +2 -1
  90. data/src/java/arjdbc/mysql/MySQLModule.java +4 -3
  91. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +12 -7
  92. data/src/java/arjdbc/oracle/OracleModule.java +2 -1
  93. data/src/java/arjdbc/sqlite3/SQLite3Module.java +2 -1
  94. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +12 -0
  95. data/test/db/db2.rb +14 -7
  96. data/test/db/db2/rake_test.rb +82 -0
  97. data/test/db/db2/rake_test_data.sql +35 -0
  98. data/test/db/db2/simple_test.rb +20 -0
  99. data/test/db/db2/unit_test.rb +3 -1
  100. data/test/db/derby.rb +7 -5
  101. data/test/db/derby/rake_test.rb +96 -0
  102. data/test/db/derby/simple_test.rb +10 -2
  103. data/test/db/h2.rb +6 -8
  104. data/test/db/h2/identity_column_test.rb +35 -0
  105. data/test/db/h2/offset_test.rb +49 -0
  106. data/test/db/h2/rake_test.rb +98 -0
  107. data/test/db/h2/schema_dump_test.rb +5 -1
  108. data/test/db/hsqldb.rb +6 -10
  109. data/test/db/hsqldb/rake_test.rb +101 -0
  110. data/test/db/hsqldb/schema_dump_test.rb +5 -1
  111. data/test/db/hsqldb/simple_test.rb +8 -0
  112. data/test/db/jndi_config.rb +1 -3
  113. data/test/db/jndi_pooled_config.rb +1 -3
  114. data/test/db/mssql/limit_offset_test.rb +23 -14
  115. data/test/db/mssql/rake_test.rb +143 -0
  116. data/test/db/mysql/_rails_test_mysql.32.out +1069 -1252
  117. data/test/db/mysql/nonstandard_primary_key_test.rb +21 -24
  118. data/test/db/mysql/rake_test.rb +97 -0
  119. data/test/db/mysql/schema_dump_test.rb +11 -11
  120. data/test/db/mysql/simple_test.rb +52 -3
  121. data/test/db/mysql/statement_escaping_test.rb +46 -0
  122. data/test/db/oracle/rake_test.rb +100 -0
  123. data/test/db/oracle/simple_test.rb +48 -0
  124. data/test/db/postgres/_rails_test_postgres.32.out +998 -1370
  125. data/test/db/postgres/active_schema_unit_test.rb +68 -0
  126. data/test/db/postgres/connection_test.rb +10 -2
  127. data/test/db/postgres/data_types_test.rb +2 -2
  128. data/test/db/postgres/ltree_test.rb +6 -5
  129. data/test/db/postgres/native_types_test.rb +1 -5
  130. data/test/db/postgres/rake_test.rb +117 -0
  131. data/test/db/postgres/schema_dump_test.rb +9 -2
  132. data/test/db/postgres/schema_test.rb +4 -2
  133. data/test/db/postgres/simple_test.rb +57 -16
  134. data/test/db/sqlite3.rb +3 -10
  135. data/test/db/sqlite3/_rails_test_sqlite3.32.out +1070 -1298
  136. data/test/db/sqlite3/rake_test.rb +71 -0
  137. data/test/db/sqlite3/simple_test.rb +9 -9
  138. data/test/has_many_through.rb +4 -1
  139. data/test/jdbc/db2.rb +14 -1
  140. data/test/jdbc_column_test.rb +23 -0
  141. data/test/{generic_jdbc_connection_test.rb → jdbc_connection_test.rb} +22 -17
  142. data/test/jndi_callbacks_test.rb +26 -28
  143. data/test/jndi_test.rb +7 -16
  144. data/test/models/data_types.rb +2 -1
  145. data/test/models/thing.rb +1 -0
  146. data/test/rails/mysql.rb +13 -0
  147. data/test/rails/sqlite3/version.rb +6 -0
  148. data/test/rails_stub.rb +31 -0
  149. data/test/rake_test_support.rb +298 -0
  150. data/test/serialize.rb +2 -4
  151. data/test/{helper.rb → shared_helper.rb} +0 -0
  152. data/test/simple.rb +167 -93
  153. data/test/test_helper.rb +52 -16
  154. metadata +388 -354
  155. data/lib/pg.rb +0 -26
  156. data/test/abstract_db_create.rb +0 -139
  157. data/test/activerecord/connection_adapters/type_conversion_test.rb +0 -36
  158. data/test/db/mssql/db_create_test.rb +0 -29
  159. data/test/db/mysql/db_create_test.rb +0 -33
  160. data/test/db/postgres/db_create_test.rb +0 -44
  161. data/test/db/postgres/db_drop_test.rb +0 -17
@@ -1,10 +1,3 @@
1
- if defined?(Rake.application) && Rake.application && ENV["SKIP_AR_JDBC_RAKE_REDEFINES"].nil?
2
- jdbc_rakefile = File.dirname(__FILE__) + "/jdbc.rake"
3
- if Rake.application.lookup("db:create")
4
- # rails tasks already defined; load the override tasks now
5
- load jdbc_rakefile
6
- else
7
- # rails tasks not loaded yet; load as an import
8
- Rake.application.add_import(jdbc_rakefile)
9
- end
10
- end
1
+ # @deprecated
2
+ warn "[DEPRECATED] load 'arjdbc/tasks.rb' instead of 'arjdbc/jdbc/rake_tasks.rb'"
3
+ load 'arjdbc/tasks.rb'
@@ -1,10 +1,11 @@
1
+ ArJdbc.load_java_part :MSSQL
2
+
1
3
  require 'strscan'
2
4
  require 'arjdbc/mssql/utils'
3
5
  require 'arjdbc/mssql/tsql_methods'
4
6
  require 'arjdbc/mssql/limit_helpers'
5
7
  require 'arjdbc/mssql/lock_helpers'
6
8
  require 'arjdbc/mssql/explain_support'
7
- require 'arjdbc/jdbc/serialized_attributes_helper'
8
9
 
9
10
  module ArJdbc
10
11
  module MSSQL
@@ -12,39 +13,41 @@ module ArJdbc
12
13
  include TSqlMethods
13
14
 
14
15
  include ExplainSupport
15
-
16
- @@_lob_callback_added = nil
17
-
18
- def self.extended(base)
19
- unless @@_lob_callback_added
20
- ActiveRecord::Base.class_eval do
21
- def after_save_with_mssql_lob
22
- self.class.columns.select { |c| c.sql_type =~ /image/i }.each do |column|
23
- value = ::ArJdbc::SerializedAttributesHelper.dump_column_value(self, column)
24
- next if value.nil? || (value == '')
25
-
26
- connection.write_large_object(
27
- column.type == :binary, column.name,
28
- self.class.table_name, self.class.primary_key,
29
- quote_value(id), value
30
- )
31
- end
32
- end
33
- end
34
-
35
- ActiveRecord::Base.after_save :after_save_with_mssql_lob
36
- @@_lob_callback_added = true
37
- end
16
+
17
+ def self.extended(adapter) # :nodoc:
18
+ initialize!
38
19
 
39
- if ( version = base.sqlserver_version ) == '2000'
20
+ if ( version = adapter.sqlserver_version ) == '2000'
40
21
  extend LimitHelpers::SqlServer2000AddLimitOffset
41
22
  else
42
23
  extend LimitHelpers::SqlServerAddLimitOffset
43
24
  end
44
- base.config[:sqlserver_version] ||= version
45
- base.configure_connection
25
+ adapter.config[:sqlserver_version] ||= version
46
26
  end
47
27
 
28
+ @@_initialized = nil
29
+
30
+ def self.initialize!
31
+ return if @@_initialized; @@_initialized = true
32
+
33
+ require 'arjdbc/jdbc/serialized_attributes_helper'
34
+ ActiveRecord::Base.class_eval do
35
+ def after_save_with_mssql_lob
36
+ self.class.columns.select { |c| c.sql_type =~ /image/i }.each do |column|
37
+ value = ::ArJdbc::SerializedAttributesHelper.dump_column_value(self, column)
38
+ next if value.nil? || (value == '')
39
+
40
+ self.class.connection.write_large_object(
41
+ column.type == :binary, column.name,
42
+ self.class.table_name, self.class.primary_key,
43
+ self.class.connection.quote(id), value
44
+ )
45
+ end
46
+ end
47
+ end
48
+ ActiveRecord::Base.after_save :after_save_with_mssql_lob
49
+ end
50
+
48
51
  def configure_connection
49
52
  use_database # config[:database]
50
53
  end
@@ -72,7 +75,7 @@ module ArJdbc
72
75
  @sqlserver_version ||= begin
73
76
  config_version = config[:sqlserver_version]
74
77
  config_version ? config_version.to_s :
75
- select_value("SELECT @@version")[/Microsoft SQL Server\s+(\d{4})/, 1]
78
+ select_value("SELECT @@version")[/(Microsoft SQL Server\s+|Microsoft SQL Azure.+\n.+)(\d{4})/, 2]
76
79
  end
77
80
  end
78
81
 
@@ -310,13 +313,17 @@ module ArJdbc
310
313
  quote_column_name(name)
311
314
  end
312
315
 
316
+ # def quote_table_name_for_assignment(table, attr)
317
+ # quote_column_name(attr)
318
+ # end if ::ActiveRecord::VERSION::MAJOR > 3
319
+
313
320
  def quote_column_name(name)
314
321
  name.to_s.split('.').map do |n| # "[#{name}]"
315
322
  n =~ /^\[.*\]$/ ? n : "[#{n.gsub(']', ']]')}]"
316
323
  end.join('.')
317
324
  end
318
325
 
319
- ADAPTER_NAME = 'MSSQL'
326
+ ADAPTER_NAME = 'MSSQL'.freeze
320
327
 
321
328
  def adapter_name # :nodoc:
322
329
  ADAPTER_NAME
@@ -351,12 +358,13 @@ module ArJdbc
351
358
  #
352
359
  # http://blogs.msdn.com/b/mssqlisv/archive/2007/03/23/upgrading-to-sql-server-2005-and-default-schema-setting.aspx
353
360
 
354
- # Returns the default schema (to be used for table resolution) used for
355
- # the {#current_user}.
361
+ # Returns the default schema (to be used for table resolution) used for the {#current_user}.
356
362
  def default_schema
357
363
  return current_user if sqlserver_2000?
358
364
  @default_schema ||=
359
- select_value("SELECT default_schema_name FROM sys.database_principals WHERE name = CURRENT_USER")
365
+ @connection.execute_query_raw(
366
+ "SELECT default_schema_name FROM sys.database_principals WHERE name = CURRENT_USER"
367
+ ).first['default_schema_name']
360
368
  end
361
369
  alias_method :current_schema, :default_schema
362
370
 
@@ -372,12 +380,16 @@ module ArJdbc
372
380
 
373
381
  # `SELECT CURRENT_USER`
374
382
  def current_user
375
- @current_user ||= select_value("SELECT CURRENT_USER")
383
+ @current_user ||= @connection.execute_query_raw("SELECT CURRENT_USER").first['']
376
384
  end
377
385
 
378
386
  def charset
379
387
  select_value "SELECT SERVERPROPERTY('SqlCharSetName')"
380
388
  end
389
+
390
+ def collation
391
+ select_value "SELECT SERVERPROPERTY('Collation')"
392
+ end
381
393
 
382
394
  def current_database
383
395
  select_value 'SELECT DB_NAME()'
@@ -410,6 +422,10 @@ module ArJdbc
410
422
  def create_database(name, options = {})
411
423
  execute "CREATE DATABASE #{quote_table_name(name)}"
412
424
  end
425
+
426
+ def database_exists?(name)
427
+ select_value "SELECT name FROM sys.databases WHERE name = '#{name}'"
428
+ end
413
429
 
414
430
  def rename_table(table_name, new_table_name)
415
431
  clear_cached_table(table_name)
@@ -601,7 +617,23 @@ module ArJdbc
601
617
  # NOTE: we allow to execute SQL as requested returning a results.
602
618
  # e.g. this allows to use SQLServer's EXEC with a result set ...
603
619
  sql = repair_special_columns to_sql(sql, binds)
604
- log(sql, name || 'SQL') { @connection.execute_query(sql) }
620
+ if prepared_statements?
621
+ log(sql, name, binds) { @connection.execute_query(sql, binds) }
622
+ else
623
+ sql = suble_binds(sql, binds)
624
+ log(sql, name) { @connection.execute_query(sql) }
625
+ end
626
+ end
627
+
628
+ # @override
629
+ def exec_query_raw(sql, name = 'SQL', binds = [], &block) # :nodoc:
630
+ sql = repair_special_columns to_sql(sql, binds)
631
+ if prepared_statements?
632
+ log(sql, name, binds) { @connection.execute_query_raw(sql, binds, &block) }
633
+ else
634
+ sql = suble_binds(sql, binds)
635
+ log(sql, name) { @connection.execute_query_raw(sql, &block) }
636
+ end
605
637
  end
606
638
 
607
639
  private
@@ -671,7 +703,49 @@ module ArJdbc
671
703
  end
672
704
 
673
705
  module ActiveRecord::ConnectionAdapters
706
+
707
+ class MSSQLAdapter < JdbcAdapter
708
+ include ::ArJdbc::MSSQL
709
+
710
+ def initialize(*args)
711
+ ::ArJdbc::MSSQL.initialize!
712
+
713
+ super # configure_connection happens in super
714
+
715
+ if ( version = self.sqlserver_version ) == '2000'
716
+ extend LimitHelpers::SqlServer2000AddLimitOffset
717
+ else
718
+ extend LimitHelpers::SqlServerAddLimitOffset
719
+ end
720
+ config[:sqlserver_version] ||= version
721
+ end
722
+
723
+ # some QUOTING caching :
724
+
725
+ @@quoted_table_names = {}
726
+
727
+ def quote_table_name(name)
728
+ unless quoted = @@quoted_table_names[name]
729
+ quoted = super
730
+ @@quoted_table_names[name] = quoted.freeze
731
+ end
732
+ quoted
733
+ end
734
+
735
+ @@quoted_column_names = {}
736
+
737
+ def quote_column_name(name)
738
+ unless quoted = @@quoted_column_names[name]
739
+ quoted = super
740
+ @@quoted_column_names[name] = quoted.freeze
741
+ end
742
+ quoted
743
+ end
744
+
745
+ end
746
+
674
747
  class MSSQLColumn < JdbcColumn
675
748
  include ArJdbc::MSSQL::Column
676
749
  end
750
+
677
751
  end
@@ -12,7 +12,9 @@ ArJdbc::ConnectionMethods.module_eval do
12
12
  config[:host] ||= "localhost"
13
13
  config[:port] ||= 1433
14
14
  config[:driver] ||= defined?(::Jdbc::JTDS.driver_name) ? ::Jdbc::JTDS.driver_name : 'net.sourceforge.jtds.jdbc.Driver'
15
- config[:adapter_spec] = ::ArJdbc::MSSQL
15
+ config[:adapter_spec] ||= ::ArJdbc::MSSQL
16
+ config[:adapter_class] = ActiveRecord::ConnectionAdapters::MSSQLAdapter unless config.key?(:adapter_class)
17
+ config[:connection_alive_sql] ||= 'SELECT 1'
16
18
 
17
19
  config[:url] ||= begin
18
20
  url = "jdbc:jtds:sqlserver://#{config[:host]}:#{config[:port]}/#{config[:database]}"
@@ -23,11 +23,12 @@ module ArJdbc
23
23
  rest_of_query = from_table + '.' + rest_of_query
24
24
  end
25
25
  new_sql = "#{select} t.* FROM (SELECT ROW_NUMBER() OVER(#{order}) AS _row_num, #{rest_of_query}"
26
- new_sql << ") AS t WHERE t._row_num BETWEEN #{start_row.to_s} AND #{end_row.to_s}"
26
+ new_sql << ") AS t WHERE t._row_num BETWEEN #{start_row} AND #{end_row}"
27
27
  sql.replace(new_sql)
28
28
  end
29
29
  sql
30
30
  end
31
+
31
32
  end
32
33
 
33
34
  module SqlServerAddLimitOffset
@@ -116,7 +117,7 @@ module ArJdbc
116
117
  if order =~ /(\w*id\w*)/i
117
118
  $1
118
119
  else
119
- unquoted_name = unquote_table_name(table_name)
120
+ unquoted_name = Utils.unquote_table_name(table_name)
120
121
  model = descendants.find { |m| m.table_name == table_name || m.table_name == unquoted_name }
121
122
  model ? model.primary_key : 'id'
122
123
  end
@@ -2,6 +2,9 @@ module ArJdbc
2
2
  module MSSQL
3
3
  module LockHelpers
4
4
  module SqlServerAddLock
5
+
6
+ SELECT_FROM_WHERE_RE = /\A(\s*SELECT\s.*?)(\sFROM\s)(.*?)(\sWHERE\s.*|)\Z/mi # :nodoc:
7
+
5
8
  # Microsoft SQL Server uses its own syntax for SELECT .. FOR UPDATE:
6
9
  # SELECT .. FROM table1 WITH(ROWLOCK,UPDLOCK), table2 WITH(ROWLOCK,UPDLOCK) WHERE ..
7
10
  #
@@ -14,7 +17,7 @@ module ArJdbc
14
17
  add_lock!(subselect, options)
15
18
  return sql.replace(prefix + subselect + suffix)
16
19
  end
17
- unless sql =~ /\A(\s*SELECT\s.*?)(\sFROM\s)(.*?)(\sWHERE\s.*|)\Z/mi
20
+ unless sql =~ SELECT_FROM_WHERE_RE
18
21
  # If you get this error, this driver probably needs to be fixed.
19
22
  raise NotImplementedError, "Don't know how to add_lock! to SQL statement: #{sql.inspect}"
20
23
  end
@@ -66,6 +69,7 @@ module ArJdbc
66
69
  end
67
70
  sql
68
71
  end
72
+
69
73
  end
70
74
  end
71
75
  end
@@ -1,14 +1,12 @@
1
+ ArJdbc.load_java_part :MySQL
2
+
1
3
  require 'bigdecimal'
2
4
  require 'active_record/connection_adapters/abstract/schema_definitions'
3
5
  require 'arjdbc/mysql/explain_support'
4
6
 
5
7
  module ArJdbc
6
8
  module MySQL
7
-
8
- def self.extended(adapter)
9
- adapter.configure_connection
10
- end
11
-
9
+
12
10
  def configure_connection
13
11
  variables = config[:variables] || {}
14
12
  # By default, MySQL 'where id is null' selects the last inserted id. Turn this off.
@@ -57,6 +55,16 @@ module ArJdbc
57
55
  config.key?(:strict) ? config[:strict] : ::ActiveRecord::VERSION::MAJOR > 3
58
56
  end
59
57
 
58
+ @@emulate_booleans = true
59
+
60
+ # Boolean emulation can be disabled using (or using the adapter method) :
61
+ #
62
+ # ArJdbc::MySQL.emulate_booleans = false
63
+ #
64
+ # @see ActiveRecord::ConnectionAdapters::MysqlAdapter#emulate_booleans
65
+ def self.emulate_booleans; @@emulate_booleans; end
66
+ def self.emulate_booleans=(emulate); @@emulate_booleans = emulate; end
67
+
60
68
  module Column
61
69
 
62
70
  def extract_default(default)
@@ -79,15 +87,19 @@ module ArJdbc
79
87
  end
80
88
 
81
89
  def simplified_type(field_type)
90
+ if adapter.respond_to?(:emulate_booleans) && adapter.emulate_booleans
91
+ return :boolean if field_type.downcase.index('tinyint(1)')
92
+ end
93
+
82
94
  case field_type
83
- when /tinyint\(1\)|bit/i then :boolean
84
- when /enum/i then :string
85
- when /year/i then :integer
95
+ when /enum/i, /set/i then :string
96
+ when /year/i then :integer
97
+ when /bit/i then :binary
86
98
  else
87
99
  super
88
100
  end
89
101
  end
90
-
102
+
91
103
  def extract_limit(sql_type)
92
104
  case sql_type
93
105
  when /blob|text/i
@@ -126,6 +138,9 @@ module ArJdbc
126
138
  type != :string && !null && default == ''
127
139
  end
128
140
 
141
+ def adapter; end
142
+ private :adapter
143
+
129
144
  end
130
145
 
131
146
  ColumnExtensions = Column # :nodoc: backwards-compatibility
@@ -172,6 +187,16 @@ module ArJdbc
172
187
  }
173
188
  end
174
189
 
190
+ def new_visitor(config = nil)
191
+ visitor = ::Arel::Visitors::MySQL
192
+ ( prepared_statements? ? visitor : bind_substitution(visitor) ).new(self)
193
+ end if defined? ::Arel::Visitors::MySQL
194
+
195
+ # @see #bind_substitution
196
+ class BindSubstitution < Arel::Visitors::MySQL # :nodoc:
197
+ include Arel::Visitors::BindVisitor
198
+ end if defined? Arel::Visitors::BindVisitor
199
+
175
200
  def case_sensitive_equality_operator
176
201
  "= BINARY"
177
202
  end
@@ -289,7 +314,7 @@ module ArJdbc
289
314
 
290
315
  # SCHEMA STATEMENTS ========================================
291
316
 
292
- def structure_dump #:nodoc:
317
+ def structure_dump # :nodoc:
293
318
  if supports_views?
294
319
  sql = "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'"
295
320
  else
@@ -309,33 +334,53 @@ module ArJdbc
309
334
  end
310
335
  end
311
336
 
312
- # based on:
313
- # https://github.com/rails/rails/blob/3-1-stable/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb#L756
314
- # Required for passing rails column caching tests
337
+ # Returns just a table's primary key
338
+ def primary_key(table)
339
+ #pk_and_sequence = pk_and_sequence_for(table)
340
+ #pk_and_sequence && pk_and_sequence.first
341
+ @connection.primary_keys(table).first
342
+ end
343
+
315
344
  # Returns a table's primary key and belonging sequence.
316
- def pk_and_sequence_for(table) #:nodoc:
317
- keys = []
318
- result = execute("SHOW INDEX FROM #{quote_table_name(table)} WHERE Key_name = 'PRIMARY'", 'SCHEMA')
319
- result.each do |h|
320
- keys << h["Column_name"]
345
+ # @note not used only here for potential compatibility with AR's adapter.
346
+ def pk_and_sequence_for(table)
347
+ result = execute("SHOW CREATE TABLE #{quote_table_name(table)}", 'SCHEMA').first
348
+ if result['Create Table'].to_s =~ /PRIMARY KEY\s+(?:USING\s+\w+\s+)?\((.+)\)/
349
+ keys = $1.split(","); keys.map! { |key| key.gsub(/[`"]/, "") }
350
+ return keys.length == 1 ? [ keys.first, nil ] : nil
351
+ else
352
+ return nil
321
353
  end
322
- keys.length == 1 ? [keys.first, nil] : nil
323
354
  end
324
-
325
- # based on:
326
- # https://github.com/rails/rails/blob/3-1-stable/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb#L647
355
+
356
+ IndexDefinition = ::ActiveRecord::ConnectionAdapters::IndexDefinition
357
+
358
+ if ::ActiveRecord::VERSION::MAJOR > 3
359
+
360
+ INDEX_TYPES = [ :fulltext, :spatial ]
361
+ INDEX_USINGS = [ :btree, :hash ]
362
+
363
+ end
364
+
327
365
  # Returns an array of indexes for the given table.
328
- def indexes(table_name, name = nil)#:nodoc:
366
+ def indexes(table_name, name = nil) # :nodoc:
329
367
  indexes = []
330
368
  current_index = nil
331
- result = execute("SHOW KEYS FROM #{quote_table_name(table_name)}", name)
369
+ result = execute("SHOW KEYS FROM #{quote_table_name(table_name)}", name || 'SCHEMA')
332
370
  result.each do |row|
333
- key_name = row["Key_name"]
371
+ key_name = row['Key_name']
334
372
  if current_index != key_name
335
- next if key_name == "PRIMARY" # skip the primary key
373
+ next if key_name == 'PRIMARY' # skip the primary key
336
374
  current_index = key_name
337
- indexes << ::ActiveRecord::ConnectionAdapters::IndexDefinition.new(
338
- row["Table"], key_name, row["Non_unique"] == 0, [], [])
375
+ indexes <<
376
+ if self.class.const_defined?(:INDEX_TYPES) # AR 4.0
377
+ mysql_index_type = row['Index_type'].downcase.to_sym
378
+ index_type = INDEX_TYPES.include?(mysql_index_type) ? mysql_index_type : nil
379
+ index_using = INDEX_USINGS.include?(mysql_index_type) ? mysql_index_type : nil
380
+ IndexDefinition.new(row['Table'], key_name, row['Non_unique'].to_i == 0, [], [], nil, nil, index_type, index_using)
381
+ else
382
+ IndexDefinition.new(row['Table'], key_name, row['Non_unique'].to_i == 0, [], [])
383
+ end
339
384
  end
340
385
 
341
386
  indexes.last.columns << row["Column_name"]
@@ -343,26 +388,23 @@ module ArJdbc
343
388
  end
344
389
  indexes
345
390
  end
346
-
347
- def jdbc_columns(table_name, name = nil)#:nodoc:
391
+
392
+ def columns(table_name, name = nil) # :nodoc:
348
393
  sql = "SHOW FIELDS FROM #{quote_table_name(table_name)}"
349
- execute(sql, 'SCHEMA').map do |field|
350
- ::ActiveRecord::ConnectionAdapters::MysqlColumn.new(field["Field"], field["Default"], field["Type"], field["Null"] == "YES")
394
+ column = ::ActiveRecord::ConnectionAdapters::MysqlAdapter::Column
395
+ result = execute(sql, name || 'SCHEMA')
396
+ result.map! do |field|
397
+ column.new(field["Field"], field["Default"], field["Type"], field["Null"] == "YES")
351
398
  end
399
+ result
352
400
  end
353
401
 
354
- # Returns just a table's primary key
355
- def primary_key(table)
356
- pk_and_sequence = pk_and_sequence_for(table)
357
- pk_and_sequence && pk_and_sequence.first
358
- end
359
-
360
- def recreate_database(name, options = {}) #:nodoc:
402
+ def recreate_database(name, options = {}) # :nodoc:
361
403
  drop_database(name)
362
404
  create_database(name, options)
363
405
  end
364
406
 
365
- def create_database(name, options = {}) #:nodoc:
407
+ def create_database(name, options = {}) # :nodoc:
366
408
  if options[:collation]
367
409
  execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}` COLLATE `#{options[:collation]}`"
368
410
  else
@@ -572,7 +614,7 @@ module ArJdbc
572
614
  end
573
615
  column
574
616
  end
575
-
617
+
576
618
  def show_create_table(table)
577
619
  select_one("SHOW CREATE TABLE #{quote_table_name(table)}")
578
620
  end
@@ -598,29 +640,41 @@ end
598
640
  module ActiveRecord
599
641
  module ConnectionAdapters
600
642
  # Remove any vestiges of core/Ruby MySQL adapter
601
- remove_const(:MysqlColumn) if const_defined?(:MysqlColumn)
602
643
  remove_const(:MysqlAdapter) if const_defined?(:MysqlAdapter)
644
+
645
+ class MysqlAdapter < JdbcAdapter
646
+ include ::ArJdbc::MySQL
647
+ include ::ArJdbc::MySQL::ExplainSupport
648
+
649
+ # By default, the MysqlAdapter will consider all columns of type
650
+ # <tt>tinyint(1)</tt> as boolean. If you wish to disable this :
651
+ #
652
+ # ActiveRecord::ConnectionAdapters::Mysql[2]Adapter.emulate_booleans = false
653
+ #
654
+ def self.emulate_booleans; ::ArJdbc::MySQL.emulate_booleans; end
655
+ def self.emulate_booleans=(emulate); ::ArJdbc::MySQL.emulate_booleans = emulate; end
656
+
657
+ class Column < JdbcColumn
658
+ include ::ArJdbc::MySQL::Column
603
659
 
604
- class MysqlColumn < JdbcColumn
605
- include ::ArJdbc::MySQL::Column
660
+ def initialize(name, *args)
661
+ if Hash === name
662
+ super
663
+ else
664
+ super(nil, name, *args)
665
+ end
666
+ end
606
667
 
607
- def initialize(name, *args)
608
- if Hash === name
609
- super
610
- else
611
- super(nil, name, *args)
668
+ # @note {#ArJdbc::MySQL::Column} uses this to check for boolean emulation
669
+ def adapter
670
+ MysqlAdapter
612
671
  end
672
+
613
673
  end
614
674
 
615
- end
616
-
617
- class MysqlAdapter < JdbcAdapter
618
- include ::ArJdbc::MySQL
619
- include ::ArJdbc::MySQL::ExplainSupport
620
-
621
675
  def initialize(*args)
622
676
  super
623
- configure_connection
677
+ # configure_connection happens in super
624
678
  end
625
679
 
626
680
  def jdbc_connection_class(spec)
@@ -628,9 +682,8 @@ module ActiveRecord
628
682
  end
629
683
 
630
684
  def jdbc_column_class
631
- MysqlColumn
685
+ Column
632
686
  end
633
- alias_chained_method :columns, :query_cache, :jdbc_columns
634
687
 
635
688
  # some QUOTING caching :
636
689
 
@@ -655,18 +708,22 @@ module ActiveRecord
655
708
  end
656
709
 
657
710
  end
658
- end
659
- end
660
-
661
- # Don't need to load native mysql adapter
662
- $LOADED_FEATURES << 'active_record/connection_adapters/mysql_adapter.rb'
663
- $LOADED_FEATURES << 'active_record/connection_adapters/mysql2_adapter.rb'
664
-
665
- module Mysql # :nodoc:
666
- remove_const(:Error) if const_defined?(:Error)
667
- class Error < ::ActiveRecord::JDBCError; end
711
+
712
+ if ActiveRecord::VERSION::MAJOR < 3 ||
713
+ ( ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR <= 1 )
714
+ remove_const(:MysqlColumn) if const_defined?(:MysqlColumn)
715
+ MysqlColumn = MysqlAdapter::Column
716
+ end
668
717
 
669
- def self.client_version
670
- 50400 # faked out for AR tests
718
+ if ActiveRecord::VERSION::MAJOR > 3 ||
719
+ ( ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR >= 1 )
720
+ remove_const(:Mysql2Adapter) if const_defined?(:Mysql2Adapter)
721
+ Mysql2Adapter = MysqlAdapter
722
+ if ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 1
723
+ remove_const(:Mysql2Column) if const_defined?(:Mysql2Column)
724
+ Mysql2Column = MysqlAdapter::Column
725
+ end
726
+ end
727
+
671
728
  end
672
729
  end