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

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