neo-activerecord-jdbc-adapter 5.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (187) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +33 -0
  3. data/.travis.yml +438 -0
  4. data/.yardopts +4 -0
  5. data/Appraisals +41 -0
  6. data/CONTRIBUTING.md +44 -0
  7. data/Gemfile +62 -0
  8. data/History.md +1191 -0
  9. data/LICENSE.txt +25 -0
  10. data/README.md +266 -0
  11. data/RUNNING_TESTS.md +88 -0
  12. data/Rakefile +100 -0
  13. data/Rakefile.jdbc +20 -0
  14. data/activerecord-jdbc-adapter.gemspec +42 -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 +60 -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 +19 -0
  43. data/lib/arjdbc/abstract/database_statements.rb +92 -0
  44. data/lib/arjdbc/abstract/transaction_support.rb +86 -0
  45. data/lib/arjdbc/common_jdbc_methods.rb +13 -0
  46. data/lib/arjdbc/db2.rb +4 -0
  47. data/lib/arjdbc/db2/adapter.rb +789 -0
  48. data/lib/arjdbc/db2/as400.rb +130 -0
  49. data/lib/arjdbc/db2/column.rb +167 -0
  50. data/lib/arjdbc/db2/connection_methods.rb +44 -0
  51. data/lib/arjdbc/derby.rb +3 -0
  52. data/lib/arjdbc/derby/active_record_patch.rb +13 -0
  53. data/lib/arjdbc/derby/adapter.rb +556 -0
  54. data/lib/arjdbc/derby/connection_methods.rb +20 -0
  55. data/lib/arjdbc/derby/schema_creation.rb +15 -0
  56. data/lib/arjdbc/discover.rb +115 -0
  57. data/lib/arjdbc/firebird.rb +4 -0
  58. data/lib/arjdbc/firebird/adapter.rb +434 -0
  59. data/lib/arjdbc/firebird/connection_methods.rb +23 -0
  60. data/lib/arjdbc/h2.rb +3 -0
  61. data/lib/arjdbc/h2/adapter.rb +303 -0
  62. data/lib/arjdbc/h2/connection_methods.rb +27 -0
  63. data/lib/arjdbc/hsqldb.rb +3 -0
  64. data/lib/arjdbc/hsqldb/adapter.rb +297 -0
  65. data/lib/arjdbc/hsqldb/connection_methods.rb +28 -0
  66. data/lib/arjdbc/hsqldb/explain_support.rb +35 -0
  67. data/lib/arjdbc/hsqldb/schema_creation.rb +11 -0
  68. data/lib/arjdbc/informix.rb +5 -0
  69. data/lib/arjdbc/informix/adapter.rb +162 -0
  70. data/lib/arjdbc/informix/connection_methods.rb +9 -0
  71. data/lib/arjdbc/jdbc.rb +59 -0
  72. data/lib/arjdbc/jdbc/adapter.rb +899 -0
  73. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  74. data/lib/arjdbc/jdbc/adapter_require.rb +46 -0
  75. data/lib/arjdbc/jdbc/base_ext.rb +44 -0
  76. data/lib/arjdbc/jdbc/callbacks.rb +51 -0
  77. data/lib/arjdbc/jdbc/column.rb +97 -0
  78. data/lib/arjdbc/jdbc/connection.rb +133 -0
  79. data/lib/arjdbc/jdbc/connection_methods.rb +36 -0
  80. data/lib/arjdbc/jdbc/driver.rb +43 -0
  81. data/lib/arjdbc/jdbc/extension.rb +59 -0
  82. data/lib/arjdbc/jdbc/java.rb +15 -0
  83. data/lib/arjdbc/jdbc/jdbc.rake +4 -0
  84. data/lib/arjdbc/jdbc/quoted_primary_key.rb +28 -0
  85. data/lib/arjdbc/jdbc/railtie.rb +2 -0
  86. data/lib/arjdbc/jdbc/rake_tasks.rb +3 -0
  87. data/lib/arjdbc/jdbc/serialized_attributes_helper.rb +3 -0
  88. data/lib/arjdbc/jdbc/type_cast.rb +166 -0
  89. data/lib/arjdbc/jdbc/type_converter.rb +142 -0
  90. data/lib/arjdbc/mimer.rb +3 -0
  91. data/lib/arjdbc/mimer/adapter.rb +142 -0
  92. data/lib/arjdbc/mssql.rb +7 -0
  93. data/lib/arjdbc/mssql/adapter.rb +808 -0
  94. data/lib/arjdbc/mssql/column.rb +200 -0
  95. data/lib/arjdbc/mssql/connection_methods.rb +79 -0
  96. data/lib/arjdbc/mssql/explain_support.rb +99 -0
  97. data/lib/arjdbc/mssql/limit_helpers.rb +231 -0
  98. data/lib/arjdbc/mssql/lock_methods.rb +77 -0
  99. data/lib/arjdbc/mssql/types.rb +343 -0
  100. data/lib/arjdbc/mssql/utils.rb +82 -0
  101. data/lib/arjdbc/mysql.rb +3 -0
  102. data/lib/arjdbc/mysql/adapter.rb +1006 -0
  103. data/lib/arjdbc/mysql/bulk_change_table.rb +150 -0
  104. data/lib/arjdbc/mysql/column.rb +162 -0
  105. data/lib/arjdbc/mysql/connection_methods.rb +145 -0
  106. data/lib/arjdbc/mysql/explain_support.rb +82 -0
  107. data/lib/arjdbc/mysql/schema_creation.rb +58 -0
  108. data/lib/arjdbc/oracle.rb +4 -0
  109. data/lib/arjdbc/oracle/adapter.rb +952 -0
  110. data/lib/arjdbc/oracle/column.rb +126 -0
  111. data/lib/arjdbc/oracle/connection_methods.rb +21 -0
  112. data/lib/arjdbc/postgresql.rb +3 -0
  113. data/lib/arjdbc/postgresql/_bc_time_cast_patch.rb +21 -0
  114. data/lib/arjdbc/postgresql/adapter.rb +825 -0
  115. data/lib/arjdbc/postgresql/base/array_decoder.rb +26 -0
  116. data/lib/arjdbc/postgresql/base/array_encoder.rb +25 -0
  117. data/lib/arjdbc/postgresql/base/array_parser.rb +95 -0
  118. data/lib/arjdbc/postgresql/base/pgconn.rb +11 -0
  119. data/lib/arjdbc/postgresql/column.rb +51 -0
  120. data/lib/arjdbc/postgresql/connection_methods.rb +54 -0
  121. data/lib/arjdbc/postgresql/name.rb +24 -0
  122. data/lib/arjdbc/postgresql/oid_types.rb +178 -0
  123. data/lib/arjdbc/railtie.rb +11 -0
  124. data/lib/arjdbc/sqlite3.rb +3 -0
  125. data/lib/arjdbc/sqlite3/adapter.rb +703 -0
  126. data/lib/arjdbc/sqlite3/connection_methods.rb +40 -0
  127. data/lib/arjdbc/sybase.rb +2 -0
  128. data/lib/arjdbc/sybase/adapter.rb +47 -0
  129. data/lib/arjdbc/tasks.rb +13 -0
  130. data/lib/arjdbc/tasks/database_tasks.rb +54 -0
  131. data/lib/arjdbc/tasks/databases.rake +91 -0
  132. data/lib/arjdbc/tasks/databases3.rake +215 -0
  133. data/lib/arjdbc/tasks/databases4.rake +39 -0
  134. data/lib/arjdbc/tasks/db2_database_tasks.rb +104 -0
  135. data/lib/arjdbc/tasks/derby_database_tasks.rb +95 -0
  136. data/lib/arjdbc/tasks/h2_database_tasks.rb +31 -0
  137. data/lib/arjdbc/tasks/hsqldb_database_tasks.rb +70 -0
  138. data/lib/arjdbc/tasks/jdbc_database_tasks.rb +169 -0
  139. data/lib/arjdbc/tasks/mssql_database_tasks.rb +46 -0
  140. data/lib/arjdbc/tasks/oracle/enhanced_structure_dump.rb +297 -0
  141. data/lib/arjdbc/tasks/oracle_database_tasks.rb +65 -0
  142. data/lib/arjdbc/util/quoted_cache.rb +60 -0
  143. data/lib/arjdbc/util/serialized_attributes.rb +98 -0
  144. data/lib/arjdbc/util/table_copier.rb +110 -0
  145. data/lib/arjdbc/version.rb +8 -0
  146. data/lib/generators/jdbc/USAGE +9 -0
  147. data/lib/generators/jdbc/jdbc_generator.rb +17 -0
  148. data/lib/jdbc_adapter.rb +2 -0
  149. data/lib/jdbc_adapter/rake_tasks.rb +4 -0
  150. data/lib/jdbc_adapter/version.rb +4 -0
  151. data/pom.xml +114 -0
  152. data/rails_generators/jdbc_generator.rb +15 -0
  153. data/rails_generators/templates/config/initializers/jdbc.rb +10 -0
  154. data/rails_generators/templates/lib/tasks/jdbc.rake +11 -0
  155. data/rakelib/01-tomcat.rake +51 -0
  156. data/rakelib/02-test.rake +121 -0
  157. data/rakelib/bundler_ext.rb +11 -0
  158. data/rakelib/compile.rake +62 -0
  159. data/rakelib/db.rake +58 -0
  160. data/rakelib/rails.rake +75 -0
  161. data/src/java/arjdbc/ArJdbcModule.java +178 -0
  162. data/src/java/arjdbc/db2/DB2Module.java +71 -0
  163. data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +142 -0
  164. data/src/java/arjdbc/derby/DerbyModule.java +179 -0
  165. data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +164 -0
  166. data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +190 -0
  167. data/src/java/arjdbc/h2/H2Module.java +44 -0
  168. data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +67 -0
  169. data/src/java/arjdbc/hsqldb/HSQLDBModule.java +68 -0
  170. data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +75 -0
  171. data/src/java/arjdbc/jdbc/AdapterJavaService.java +45 -0
  172. data/src/java/arjdbc/jdbc/Callable.java +44 -0
  173. data/src/java/arjdbc/jdbc/JdbcConnectionFactory.java +45 -0
  174. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +3616 -0
  175. data/src/java/arjdbc/jdbc/SQLBlock.java +54 -0
  176. data/src/java/arjdbc/mssql/MSSQLModule.java +102 -0
  177. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +195 -0
  178. data/src/java/arjdbc/mysql/MySQLModule.java +147 -0
  179. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +397 -0
  180. data/src/java/arjdbc/oracle/OracleModule.java +75 -0
  181. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +465 -0
  182. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +752 -0
  183. data/src/java/arjdbc/sqlite3/SQLite3Module.java +78 -0
  184. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +351 -0
  185. data/src/java/arjdbc/util/CallResultSet.java +826 -0
  186. data/src/java/arjdbc/util/QuotingUtils.java +111 -0
  187. metadata +255 -0
@@ -0,0 +1,28 @@
1
+ ArJdbc::ConnectionMethods.module_eval do
2
+ def hsqldb_connection(config)
3
+ config[:adapter_spec] ||= ::ArJdbc::HSQLDB
4
+ config[:adapter_class] = ActiveRecord::ConnectionAdapters::HsqldbAdapter unless config.key?(:adapter_class)
5
+
6
+ return jndi_connection(config) if jndi_config?(config)
7
+
8
+ begin
9
+ require 'jdbc/hsqldb'
10
+ ::Jdbc::HSQLDB.load_driver(:require) if defined?(::Jdbc::HSQLDB.load_driver)
11
+ rescue LoadError # assuming driver.jar is on the class-path
12
+ end
13
+
14
+ config[:url] ||= begin
15
+ db = config[:database]
16
+ if db[0, 4] == 'mem:' || db[0, 5] == 'file:' || db[0, 5] == 'hsql:'
17
+ "jdbc:hsqldb:#{db}"
18
+ else
19
+ "jdbc:hsqldb:file:#{db}"
20
+ end
21
+ end
22
+ config[:driver] ||= defined?(::Jdbc::HSQLDB.driver_name) ? ::Jdbc::HSQLDB.driver_name : 'org.hsqldb.jdbcDriver'
23
+ config[:connection_alive_sql] ||= 'CALL PI()' # does not like 'SELECT 1'
24
+
25
+ embedded_driver(config)
26
+ end
27
+ alias_method :jdbchsqldb_connection, :hsqldb_connection
28
+ end
@@ -0,0 +1,35 @@
1
+ module ArJdbc
2
+ module HSQLDB
3
+ module ExplainSupport
4
+ def supports_explain?; true; end
5
+
6
+ def explain(arel, binds = [])
7
+ sql = "EXPLAIN PLAN FOR #{to_sql(arel, binds)}"
8
+ raw_result = exec_query_raw(sql, "EXPLAIN", binds)
9
+ # HSQLDB's SqlTool just prints it as it comes :
10
+ #
11
+ # sql> EXPLAIN PLAN FOR SELECT * FROM entries JOIN users on ... ;
12
+ #
13
+ # isDistinctSelect=[false]
14
+ # isGrouped=[false]
15
+ # isAggregated=[false]
16
+ # columns=[ COLUMN: PUBLIC.ENTRIES.ID
17
+ # not nullable COLUMN: PUBLIC.ENTRIES.TITLE
18
+ # nullable COLUMN: PUBLIC.ENTRIES.UPDATED_ON
19
+ # nullable COLUMN: PUBLIC.ENTRIES.CONTENT
20
+ # nullable COLUMN: PUBLIC.ENTRIES.RATING
21
+ # nullable COLUMN: PUBLIC.ENTRIES.USER_ID
22
+ # nullable COLUMN: PUBLIC.USERS.ID
23
+ # not nullable COLUMN: PUBLIC.USERS.LOGIN
24
+ # nullable
25
+ # ]
26
+ # ...
27
+ # PARAMETERS=[]
28
+ # SUBQUERIES[]
29
+ #
30
+ raw_result.map!(&:values)
31
+ raw_result.join("\n")
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,11 @@
1
+ module ArJdbc
2
+ module HSQLDB
3
+ # @private
4
+ SchemaCreation = ::ActiveRecord::ConnectionAdapters::AbstractAdapter::SchemaCreation
5
+
6
+ def schema_creation
7
+ SchemaCreation.new self
8
+ end
9
+
10
+ end
11
+ end if ::ActiveRecord::ConnectionAdapters::AbstractAdapter.const_defined? :SchemaCreation
@@ -0,0 +1,5 @@
1
+ require 'arjdbc'
2
+ ArJdbc.load_java_part :Informix
3
+ require 'arjdbc/informix/adapter'
4
+ require 'arjdbc/informix/connection_methods'
5
+ ArJdbc.warn_unsupported_adapter 'informix', [4, 2] # warns on AR >= 4.2
@@ -0,0 +1,162 @@
1
+ require 'arjdbc/util/serialized_attributes'
2
+
3
+ module ArJdbc
4
+ module Informix
5
+
6
+ @@_lob_callback_added = nil
7
+
8
+ def self.extended(base)
9
+ unless @@_lob_callback_added
10
+ ActiveRecord::Base.class_eval do
11
+ def after_save_with_informix_lob
12
+ lob_columns = self.class.columns.select { |c| [:text, :binary].include?(c.type) }
13
+ lob_columns.each do |column|
14
+ value = ::ArJdbc::SerializedAttributesHelper.dump_column_value(self, column)
15
+ next if value.nil? || (value == '')
16
+
17
+ connection.write_large_object(
18
+ column.type == :binary, column.name,
19
+ self.class.table_name, self.class.primary_key,
20
+ quote_value(id), value
21
+ )
22
+ end
23
+ end
24
+ end
25
+
26
+ ActiveRecord::Base.after_save :after_save_with_informix_lob
27
+ @@_lob_callback_added = true
28
+ end
29
+ end
30
+
31
+ # @see ActiveRecord::ConnectionAdapters::JdbcColumn#column_types
32
+ def self.column_selector
33
+ [ /informix/i, lambda { |cfg, column| column.extend(ColumnMethods) } ]
34
+ end
35
+
36
+ JdbcConnection = ::ActiveRecord::ConnectionAdapters::InformixJdbcConnection
37
+
38
+ # @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
39
+ def self.jdbc_connection_class
40
+ ::ActiveRecord::ConnectionAdapters::InformixJdbcConnection
41
+ end
42
+
43
+ # @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_column_class
44
+ def jdbc_column_class
45
+ ::ActiveRecord::ConnectionAdapters::InformixColumn
46
+ end
47
+
48
+ module ColumnMethods
49
+
50
+ private
51
+ # TODO: Test all Informix column types.
52
+ def simplified_type(field_type)
53
+ if field_type =~ /serial/i
54
+ :primary_key
55
+ else
56
+ super
57
+ end
58
+ end
59
+
60
+ end
61
+
62
+ def modify_types(types)
63
+ super(types)
64
+ types[:primary_key] = "SERIAL PRIMARY KEY"
65
+ types[:string] = { :name => "VARCHAR", :limit => 255 }
66
+ types[:integer] = { :name => "INTEGER" }
67
+ types[:float] = { :name => "FLOAT" }
68
+ types[:decimal] = { :name => "DECIMAL" }
69
+ types[:datetime] = { :name => "DATETIME YEAR TO FRACTION(5)" }
70
+ types[:timestamp] = { :name => "DATETIME YEAR TO FRACTION(5)" }
71
+ types[:time] = { :name => "DATETIME HOUR TO FRACTION(5)" }
72
+ types[:date] = { :name => "DATE" }
73
+ types[:binary] = { :name => "BYTE" }
74
+ types[:boolean] = { :name => "BOOLEAN" }
75
+ types
76
+ end
77
+
78
+ def prefetch_primary_key?(table_name = nil)
79
+ true
80
+ end
81
+
82
+ def supports_migrations?
83
+ true
84
+ end
85
+
86
+ def default_sequence_name(table, column)
87
+ "#{table}_seq"
88
+ end
89
+
90
+ def add_limit_offset!(sql, options)
91
+ if options[:limit]
92
+ limit = "FIRST #{options[:limit]}" # SKIP available only in IDS >= 10 :
93
+ offset = (db_major_version >= 10 && options[:offset] ? "SKIP #{options[:offset]}" : "")
94
+ sql.sub!(/^\s*?select /i, "SELECT #{offset} #{limit} ")
95
+ end
96
+ sql
97
+ end
98
+
99
+ def next_sequence_value(sequence_name)
100
+ select_one("SELECT #{sequence_name}.nextval id FROM systables WHERE tabid=1")['id']
101
+ end
102
+
103
+ # TODO: Add some smart quoting for newlines in string and text fields.
104
+ def quote_string(string)
105
+ string.gsub(/\'/, "''")
106
+ end
107
+
108
+ def quote(value, column = nil)
109
+ column_type = column && column.type
110
+ if column_type == :binary || column_type == :text
111
+ # LOBs are updated separately by an after_save trigger.
112
+ "NULL"
113
+ elsif column_type == :date
114
+ "'#{value.mon}/#{value.day}/#{value.year}'"
115
+ else
116
+ super
117
+ end
118
+ end
119
+
120
+ def create_table(name, options = {})
121
+ super(name, options)
122
+ execute("CREATE SEQUENCE #{name}_seq")
123
+ end
124
+
125
+ def rename_table(name, new_name)
126
+ execute("RENAME TABLE #{name} TO #{new_name}")
127
+ execute("RENAME SEQUENCE #{name}_seq TO #{new_name}_seq")
128
+ end
129
+
130
+ def drop_table(name)
131
+ super(name)
132
+ execute("DROP SEQUENCE #{name}_seq")
133
+ end
134
+
135
+ def remove_index(table_name, options = {})
136
+ @connection.execute_update("DROP INDEX #{index_name(table_name, options)}")
137
+ end
138
+
139
+ def select(sql, *rest)
140
+ # Informix does not like "= NULL", "!= NULL", or "<> NULL".
141
+ super(sql.gsub(/(!=|<>)\s*null/i, "IS NOT NULL").gsub(/=\s*null/i, "IS NULL"), *rest)
142
+ end
143
+
144
+ private
145
+
146
+ def db_major_version
147
+ @@db_major_version ||=
148
+ select_one("SELECT dbinfo('version', 'major') version FROM systables WHERE tabid = 1")['version'].to_i
149
+ end
150
+
151
+ end # module Informix
152
+ end # module ::ArJdbc
153
+
154
+ module ActiveRecord::ConnectionAdapters
155
+ class InformixColumn < JdbcColumn
156
+ include ::ArJdbc::Informix::ColumnMethods
157
+ end
158
+
159
+ class InformixAdapter < JdbcAdapter
160
+ include ::ArJdbc::Informix
161
+ end
162
+ end
@@ -0,0 +1,9 @@
1
+ ArJdbc::ConnectionMethods.module_eval do
2
+ def informix_connection(config)
3
+ config[:port] ||= 9088
4
+ config[:url] ||= "jdbc:informix-sqli://#{config[:host]}:#{config[:port]}/#{config[:database]}:INFORMIXSERVER=#{config[:servername]}"
5
+ config[:driver] = 'com.informix.jdbc.IfxDriver'
6
+ config[:adapter_spec] = ::ArJdbc::Informix
7
+ jdbc_connection(config)
8
+ end
9
+ end
@@ -0,0 +1,59 @@
1
+ require 'active_support/deprecation'
2
+
3
+ module ArJdbc
4
+
5
+ # @private
6
+ AR40 = ::ActiveRecord::VERSION::MAJOR > 3
7
+ # @private
8
+ AR42 = ::ActiveRecord::VERSION::STRING >= '4.2'
9
+ # @private
10
+ AR50 = ::ActiveRecord::VERSION::MAJOR > 4
11
+
12
+ class << self
13
+
14
+ # @private Internal API
15
+ def warn_unsupported_adapter(adapter, version = nil)
16
+ warn_prefix = 'NOTE:'
17
+ if version # e.g. [4, 2]
18
+ ar_version = [ ActiveRecord::VERSION::MAJOR, ActiveRecord::VERSION::MINOR, ActiveRecord::VERSION::TINY ]
19
+ if ( ar_version <=> version ) >= 0 # e.g. 4.2.0 > 4.2
20
+ warn_prefix = "NOTE: ActiveRecord #{version.join('.')} with"
21
+ else
22
+ warn_prefix = nil
23
+ end
24
+ end
25
+ warn "#{warn_prefix} adapter: #{adapter} is not (yet) fully supported by AR-JDBC," <<
26
+ " please consider helping us out." if warn_prefix
27
+ end
28
+
29
+ def warn(message, once = nil)
30
+ super(message) || true if warn?(message, once)
31
+ end
32
+
33
+ def deprecate(message, once = nil) # adds a "DEPRECATION WARNING: " prefix
34
+ ::ActiveSupport::Deprecation.warn(message, caller) || true if warn?(message, once)
35
+ end
36
+
37
+ private
38
+
39
+ @@warns = nil
40
+ @@warns = false if ENV_JAVA['arjdbc.warn'].eql? 'false'
41
+
42
+ def warn?(message, once)
43
+ return nil if @@warns.equal?(false) || ! message
44
+ warns = @@warns ||= ( require 'set'; Set.new )
45
+ return false if warns.include?(message)
46
+ warns << message.dup if once
47
+ true
48
+ end
49
+
50
+ end
51
+
52
+ require 'arjdbc/jdbc/adapter'
53
+
54
+ if ENV_JAVA['arjdbc.extensions.discover'].eql? 'true'
55
+ self.discover_extensions
56
+ else
57
+ require 'arjdbc/discover'
58
+ end
59
+ end
@@ -0,0 +1,899 @@
1
+ require 'active_record/version'
2
+ require 'active_record/connection_adapters/abstract_adapter'
3
+
4
+ require 'arjdbc/version'
5
+ require 'arjdbc/jdbc/java'
6
+ require 'arjdbc/jdbc/base_ext'
7
+ require 'arjdbc/jdbc/connection_methods'
8
+ require 'arjdbc/jdbc/driver'
9
+ require 'arjdbc/jdbc/column'
10
+ require 'arjdbc/jdbc/connection'
11
+ require 'arjdbc/jdbc/callbacks'
12
+ require 'arjdbc/jdbc/extension'
13
+ require 'arjdbc/jdbc/type_converter'
14
+
15
+ module ActiveRecord
16
+ module ConnectionAdapters
17
+ # Built on top of `ActiveRecord::ConnectionAdapters::AbstractAdapter` which
18
+ # provides the abstract interface for database-specific functionality, this
19
+ # class serves 2 purposes in AR-JDBC :
20
+ # - as a base class for sub-classes
21
+ # - usable standalone (or with a mixed in adapter spec module)
22
+ #
23
+ # Historically this class is mostly been used standalone and that's still a
24
+ # valid use-case esp. since (with it's `arjdbc.jdbc.RubyJdbcConnectionClass`)
25
+ # JDBC provides a unified interface for all databases in Java it tries to do
26
+ # it's best implementing all `ActiveRecord` functionality on top of that.
27
+ # This might no be perfect that's why it checks for a `config[:adapter_spec]`
28
+ # module (or tries to resolve one from the JDBC driver's meta-data) and if
29
+ # the database has "extended" AR-JDBC support mixes in the given module for
30
+ # each adapter instance.
31
+ # This is sufficient for most database specific specs we support, but for
32
+ # compatibility with native (MRI) adapters it's perfectly fine to sub-class
33
+ # the adapter and override some of its API methods.
34
+ class JdbcAdapter < AbstractAdapter
35
+ include Jdbc::ConnectionPoolCallbacks
36
+
37
+ attr_reader :config, :prepared_statements
38
+
39
+ def self.new(connection, logger = nil, pool = nil)
40
+ adapter = super
41
+ Jdbc::JndiConnectionPoolCallbacks.prepare(adapter, adapter.instance_variable_get(:@connection))
42
+ adapter
43
+ end
44
+
45
+ # Initializes the (JDBC connection) adapter instance.
46
+ # The passed configuration Hash's keys are symbolized, thus changes to
47
+ # the original `config` keys won't be reflected in the adapter.
48
+ # If the adapter's sub-class or the spec module that this instance will
49
+ # extend in responds to `configure_connection` than it will be called.
50
+ # @param connection an (optional) connection instance
51
+ # @param logger the `ActiveRecord::Base.logger` to use (or nil)
52
+ # @param config the database configuration
53
+ # @note `initialize(logger, config)` with 2 arguments is supported as well
54
+ def initialize(connection, logger = nil, config = nil)
55
+ @config = config.respond_to?(:symbolize_keys) ? config.symbolize_keys : config
56
+ # FIXME: Rails 5 defaults to prepared statements on and we do not seem
57
+ # to work yet. So default to off unless it is requested until that is
58
+ # fixed.
59
+ @config[:prepared_statements] = false if !@config[:prepared_statements]
60
+
61
+ # NOTE: JDBC 4.0 drivers support checking if connection isValid
62
+ # thus no need to @config[:connection_alive_sql] ||= 'SELECT 1'
63
+ #
64
+ # NOTE: setup to retry 5-times previously - maybe do not set at all ?
65
+ @config[:retry_count] ||= 1
66
+
67
+ @config[:adapter_spec] = adapter_spec(@config) unless @config.key?(:adapter_spec)
68
+ spec = @config[:adapter_spec]
69
+
70
+ # NOTE: adapter spec's init_connection only called if instantiated here :
71
+ connection ||= jdbc_connection_class(spec).new(@config, self)
72
+
73
+ super(connection, logger, @config)
74
+
75
+ # kind of like `extend ArJdbc::MyDB if self.class == JdbcAdapter` :
76
+ klass = @config[:adapter_class]
77
+ extend spec if spec && ( ! klass || klass == JdbcAdapter)
78
+
79
+ # NOTE: should not be necessary for JNDI due reconnect! on checkout :
80
+ configure_connection if respond_to?(:configure_connection)
81
+ end
82
+
83
+ # Returns the (JDBC) connection class to be used for this adapter.
84
+ # This is used by (database specific) spec modules to override the class
85
+ # used assuming some of the available methods have been re-defined.
86
+ # @see ActiveRecord::ConnectionAdapters::JdbcConnection
87
+ def jdbc_connection_class(spec)
88
+ connection_class = spec.jdbc_connection_class if spec && spec.respond_to?(:jdbc_connection_class)
89
+ connection_class ? connection_class : ::ActiveRecord::ConnectionAdapters::JdbcConnection
90
+ end
91
+
92
+ # Returns the (JDBC) `ActiveRecord` column class for this adapter.
93
+ # This is used by (database specific) spec modules to override the class.
94
+ # @see ActiveRecord::ConnectionAdapters::JdbcColumn
95
+ def jdbc_column_class
96
+ ::ActiveRecord::ConnectionAdapters::JdbcColumn
97
+ end
98
+
99
+ # Retrieve the raw `java.sql.Connection` object.
100
+ # The unwrap parameter is useful if an attempt to unwrap a pooled (JNDI)
101
+ # connection should be made - to really return the 'native' JDBC object.
102
+ # @param unwrap [true, false] whether to unwrap the connection object
103
+ # @return [Java::JavaSql::Connection] the JDBC connection
104
+ def jdbc_connection(unwrap = nil)
105
+ java_connection = raw_connection.connection
106
+ return java_connection unless unwrap
107
+ connection_class = java.sql.Connection.java_class
108
+ begin
109
+ if java_connection.wrapper_for?(connection_class)
110
+ return java_connection.unwrap(connection_class) # java.sql.Wrapper.unwrap
111
+ end
112
+ rescue Java::JavaLang::AbstractMethodError => e
113
+ ArJdbc.warn("driver/pool connection impl does not support unwrapping (#{e})")
114
+ end
115
+ if java_connection.respond_to?(:connection)
116
+ # e.g. org.apache.tomcat.jdbc.pool.PooledConnection
117
+ java_connection.connection # getConnection
118
+ else
119
+ java_connection
120
+ end
121
+ end
122
+
123
+ # Locate the specialized (database specific) adapter specification module
124
+ # if one exists based on provided configuration data. This module will than
125
+ # extend an instance of the adapter (unless an `:adapter_class` provided).
126
+ #
127
+ # This method is called during {#initialize} unless an explicit
128
+ # `config[:adapter_spec]` is set.
129
+ # @param config the configuration to check for `:adapter_spec`
130
+ # @return [Module] the database specific module
131
+ def adapter_spec(config)
132
+ dialect = (config[:dialect] || config[:driver]).to_s
133
+ ::ArJdbc.modules.each do |constant| # e.g. ArJdbc::MySQL
134
+ if constant.respond_to?(:adapter_matcher)
135
+ spec = constant.adapter_matcher(dialect, config)
136
+ return spec if spec
137
+ end
138
+ end
139
+
140
+ if (config[:jndi] || config[:data_source]) && ! config[:dialect]
141
+ begin
142
+ data_source = config[:data_source] ||
143
+ Java::JavaxNaming::InitialContext.new.lookup(config[:jndi])
144
+ connection = data_source.getConnection
145
+ config[:dialect] = connection.getMetaData.getDatabaseProductName
146
+ rescue Java::JavaSql::SQLException => e
147
+ warn "failed to set database :dialect from connection meda-data (#{e})"
148
+ else
149
+ return adapter_spec(config) # re-try matching a spec with set config[:dialect]
150
+ ensure
151
+ connection.close if connection # return to the pool
152
+ end
153
+ end
154
+
155
+ nil
156
+ end
157
+
158
+ ADAPTER_NAME = 'JDBC'.freeze
159
+
160
+ # @return [String] the 'JDBC' adapter name.
161
+ def adapter_name
162
+ ADAPTER_NAME
163
+ end
164
+
165
+ # @override
166
+ # Will return true even when native adapter classes passed in
167
+ # e.g. `jdbc_adapter.is_a? ConnectionAdapter::PostgresqlAdapter`
168
+ #
169
+ # This is only necessary (for built-in adapters) when
170
+ # `config[:adapter_class]` is forced to `nil` and the `:adapter_spec`
171
+ # module is used to extend the `JdbcAdapter`, otherwise we replace the
172
+ # class constants for built-in adapters (MySQL, PostgreSQL and SQLite3).
173
+ def is_a?(klass)
174
+ # This is to fake out current_adapter? conditional logic in AR tests
175
+ if klass.is_a?(Class) && klass.name =~ /#{adapter_name}Adapter$/i
176
+ true
177
+ else
178
+ super
179
+ end
180
+ end
181
+
182
+ # @deprecated re-implemented - no longer used
183
+ # @return [Hash] the AREL visitor to use
184
+ # If there's a `self.arel2_visitors(config)` method on the adapter
185
+ # spec than it is preferred and will be used instead of this one.
186
+ def self.arel2_visitors(config)
187
+ { 'jdbc' => ::Arel::Visitors::ToSql }
188
+ end
189
+
190
+ # @deprecated re-implemented - no longer used
191
+ # @see #arel2_visitors
192
+ def self.configure_arel2_visitors(config)
193
+ visitors = ::Arel::Visitors::VISITORS
194
+ klass = config[:adapter_spec]
195
+ klass = self unless klass.respond_to?(:arel2_visitors)
196
+ visitor = nil
197
+ klass.arel2_visitors(config).each do |name, arel|
198
+ visitors[name] = ( visitor = arel )
199
+ end
200
+ if visitor && config[:adapter] =~ /^(jdbc|jndi)$/
201
+ visitors[ config[:adapter] ] = visitor
202
+ end
203
+ visitor
204
+ end
205
+
206
+ # DB specific types are detected but adapter specs (or extenders) are
207
+ # expected to hand tune these types for concrete databases.
208
+ # @return [Hash] the native database types
209
+ # @override
210
+ def native_database_types
211
+ @native_database_types ||= begin
212
+ types = @connection.native_database_types
213
+ modify_types(types)
214
+ types
215
+ end
216
+ end
217
+
218
+ # @override introduced in AR 4.2
219
+ def valid_type?(type)
220
+ ! native_database_types[type].nil?
221
+ end
222
+
223
+ # Allows for modification of the detected native types.
224
+ # @param types the resolved native database types
225
+ # @see #native_database_types
226
+ def modify_types(types)
227
+ types
228
+ end
229
+
230
+ # Abstract adapter default implementation does nothing silently.
231
+ # @override
232
+ def structure_dump
233
+ raise NotImplementedError, "structure_dump not supported"
234
+ end
235
+
236
+ # JDBC adapters support migration.
237
+ # @return [true]
238
+ # @override
239
+ def supports_migrations?
240
+ true
241
+ end
242
+
243
+ # Returns the underlying database name.
244
+ # @override
245
+ def database_name
246
+ @connection.database_name
247
+ end
248
+
249
+ # @private
250
+ def native_sql_to_type(type)
251
+ if /^(.*?)\(([0-9]+)\)/ =~ type
252
+ tname, limit = $1, $2.to_i
253
+ ntypes = native_database_types
254
+ if ntypes[:primary_key] == type
255
+ return :primary_key, nil
256
+ else
257
+ ntypes.each do |name, val|
258
+ if name == :primary_key
259
+ next
260
+ end
261
+ if val[:name].downcase == tname.downcase &&
262
+ ( val[:limit].nil? || val[:limit].to_i == limit )
263
+ return name, limit
264
+ end
265
+ end
266
+ end
267
+ elsif /^(.*?)/ =~ type
268
+ tname = $1
269
+ ntypes = native_database_types
270
+ if ntypes[:primary_key] == type
271
+ return :primary_key, nil
272
+ else
273
+ ntypes.each do |name, val|
274
+ if val[:name].downcase == tname.downcase && val[:limit].nil?
275
+ return name, nil
276
+ end
277
+ end
278
+ end
279
+ else
280
+ return :string, 255
281
+ end
282
+ return nil, nil
283
+ end
284
+
285
+ # @override
286
+ def active?
287
+ @connection.active?
288
+ end
289
+
290
+ # @override
291
+ def reconnect!
292
+ super
293
+ @connection.reconnect! # handles adapter.configure_connection
294
+ @connection
295
+ end
296
+
297
+ # @override
298
+ def disconnect!
299
+ super
300
+ @connection.disconnect!
301
+ end
302
+
303
+ def columns(table_name, name = nil)
304
+ @connection.columns(table_name.to_s)
305
+ end
306
+
307
+ # Starts a database transaction.
308
+ # @override
309
+ def begin_db_transaction
310
+ @connection.begin
311
+ end
312
+
313
+ # Commits the current database transaction.
314
+ # @override
315
+ def commit_db_transaction
316
+ @connection.commit
317
+ end
318
+
319
+ # Rolls back the current database transaction.
320
+ # @override
321
+ def rollback_db_transaction
322
+ @connection.rollback
323
+ end
324
+
325
+ # Starts a database transaction.
326
+ # @param isolation the transaction isolation to use
327
+ # @since 1.3.0
328
+ # @override on **AR-4.0**
329
+ def begin_isolated_db_transaction(isolation)
330
+ @connection.begin(isolation)
331
+ end
332
+
333
+ # Does this adapter support setting the isolation level for a transaction?
334
+ # Unlike 'plain' `ActiveRecord` we allow checking for concrete transaction
335
+ # isolation level support by the database.
336
+ # @param level optional to check if we support a specific isolation level
337
+ # @since 1.3.0
338
+ # @extension added optional level parameter
339
+ def supports_transaction_isolation?(level = nil)
340
+ @connection.supports_transaction_isolation?(level)
341
+ end
342
+
343
+ # Does our database (+ its JDBC driver) support save-points?
344
+ # @since 1.3.0
345
+ # @override
346
+ def supports_savepoints?
347
+ @connection.supports_savepoints?
348
+ end
349
+
350
+ # Creates a (transactional) save-point one can rollback to.
351
+ # Unlike 'plain' `ActiveRecord` it is allowed to pass a save-point name.
352
+ # @param name the save-point name
353
+ # @return save-point name (even if nil passed will be generated)
354
+ # @since 1.3.0
355
+ # @extension added optional name parameter
356
+ def create_savepoint(name = current_savepoint_name(true))
357
+ @connection.create_savepoint(name)
358
+ end
359
+
360
+ # Transaction rollback to a given (previously created) save-point.
361
+ # If no save-point name given rollback to the last created one.
362
+ # @param name the save-point name
363
+ # @since 1.3.0
364
+ # @extension added optional name parameter
365
+ def rollback_to_savepoint(name = current_savepoint_name(true))
366
+ @connection.rollback_savepoint(name)
367
+ end
368
+
369
+ # Release a previously created save-point.
370
+ # @note Save-points are auto-released with the transaction they're created
371
+ # in (on transaction commit or roll-back).
372
+ # @param name the save-point name
373
+ # @since 1.3.0
374
+ # @extension added optional name parameter
375
+ def release_savepoint(name = current_savepoint_name(false))
376
+ @connection.release_savepoint(name)
377
+ end
378
+
379
+ # @note Same as AR 4.2 but we're allowing an unused parameter.
380
+ # @private
381
+ def current_savepoint_name(compat = nil)
382
+ current_transaction.savepoint_name
383
+ end
384
+
385
+ # @override
386
+ def supports_views?
387
+ @connection.supports_views?
388
+ end
389
+
390
+ # Executes a SQL query in the context of this connection using the bind
391
+ # substitutes.
392
+ # @param sql the query string (or AREL object)
393
+ # @param name logging marker for the executed SQL statement log entry
394
+ # @param binds the bind parameters
395
+ # @return [ActiveRecord::Result] or [Array] on **AR-2.3**
396
+ # @override available since **AR-3.1**
397
+ def exec_query(sql, name = 'SQL', binds = [])
398
+ if sql.respond_to?(:to_sql)
399
+ sql = to_sql(sql, binds); to_sql = true
400
+ end
401
+ if prepared_statements?
402
+ log(sql, name, binds) { @connection.execute_query(sql, binds) }
403
+ else
404
+ sql = suble_binds(sql, binds) unless to_sql # deprecated behavior
405
+ log(sql, name) { @connection.execute_query(sql) }
406
+ end
407
+ end
408
+
409
+ # Executes an insert statement in the context of this connection.
410
+ # @param sql the query string (or AREL object)
411
+ # @param name logging marker for the executed SQL statement log entry
412
+ # @param binds the bind parameters
413
+ # @override available since **AR-3.1**
414
+ def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
415
+ if sql.respond_to?(:to_sql)
416
+ sql = to_sql(sql, binds); to_sql = true
417
+ end
418
+ if prepared_statements?
419
+ log(sql, name || 'SQL', binds) { @connection.execute_insert(sql, binds) }
420
+ else
421
+ sql = suble_binds(sql, binds) unless to_sql # deprecated behavior
422
+ log(sql, name || 'SQL') { @connection.execute_insert(sql) }
423
+ end
424
+ end
425
+
426
+ # Executes a delete statement in the context of this connection.
427
+ # @param sql the query string (or AREL object)
428
+ # @param name logging marker for the executed SQL statement log entry
429
+ # @param binds the bind parameters
430
+ # @override available since **AR-3.1**
431
+ def exec_delete(sql, name, binds)
432
+ if sql.respond_to?(:to_sql)
433
+ sql = to_sql(sql, binds); to_sql = true
434
+ end
435
+ if prepared_statements?
436
+ log(sql, name || 'SQL', binds) { @connection.execute_delete(sql, binds) }
437
+ else
438
+ sql = suble_binds(sql, binds) unless to_sql # deprecated behavior
439
+ log(sql, name || 'SQL') { @connection.execute_delete(sql) }
440
+ end
441
+ end
442
+
443
+ # # Executes an update statement in the context of this connection.
444
+ # @param sql the query string (or AREL object)
445
+ # @param name logging marker for the executed SQL statement log entry
446
+ # @param binds the bind parameters
447
+ # @override available since **AR-3.1**
448
+ def exec_update(sql, name, binds)
449
+ if sql.respond_to?(:to_sql)
450
+ sql = to_sql(sql, binds); to_sql = true
451
+ end
452
+ if prepared_statements?
453
+ log(sql, name || 'SQL', binds) { @connection.execute_update(sql, binds) }
454
+ else
455
+ sql = suble_binds(sql, binds) unless to_sql # deprecated behavior
456
+ log(sql, name || 'SQL') { @connection.execute_update(sql) }
457
+ end
458
+ end
459
+
460
+ # Similar to {#exec_query} except it returns "raw" results in an array
461
+ # where each rows is a hash with keys as columns (just like Rails used to
462
+ # do up until 3.0) instead of wrapping them in a {#ActiveRecord::Result}.
463
+ # @param sql the query string (or AREL object)
464
+ # @param name logging marker for the executed SQL statement log entry
465
+ # @param binds the bind parameters
466
+ # @yield [v1, v2] depending on the row values returned from the query
467
+ # In case a block is given it will yield each row from the result set
468
+ # instead of returning mapped query results in an array.
469
+ # @return [Array] unless a block is given
470
+ def exec_query_raw(sql, name = 'SQL', binds = [], &block)
471
+ if sql.respond_to?(:to_sql)
472
+ sql = to_sql(sql, binds); to_sql = true
473
+ end
474
+ if prepared_statements?
475
+ log(sql, name, binds) { @connection.execute_query_raw(sql, binds, &block) }
476
+ else
477
+ sql = suble_binds(sql, binds) unless to_sql # deprecated behavior
478
+ log(sql, name) { @connection.execute_query_raw(sql, &block) }
479
+ end
480
+ end
481
+
482
+ # @private
483
+ # @override
484
+ def select_rows(sql, name = nil, binds = [])
485
+ exec_query_raw(sql, name, binds).map!(&:values)
486
+ end
487
+
488
+ if ActiveRecord::VERSION::MAJOR > 3 # expects AR::Result e.g. from select_all
489
+
490
+ # @private
491
+ def select(sql, name = nil, binds = [])
492
+ exec_query(to_sql(sql, binds), name, binds)
493
+ end
494
+
495
+ else
496
+
497
+ # @private
498
+ def select(sql, name = nil, binds = []) # NOTE: only (sql, name) on AR < 3.1
499
+ exec_query_raw(to_sql(sql, binds), name, binds)
500
+ end
501
+
502
+ end
503
+
504
+ # Executes the SQL statement in the context of this connection.
505
+ # The return value from this method depends on the SQL type (whether
506
+ # it's a SELECT, INSERT etc.). For INSERTs a generated id might get
507
+ # returned while for UPDATE statements the affected row count.
508
+ # Please note that this method returns "raw" results (in an array) for
509
+ # statements that return a result set, while {#exec_query} is expected to
510
+ # return a `ActiveRecord::Result` (since AR 3.1).
511
+ # @note This method does not use prepared statements.
512
+ # @note The method does not emulate various "native" `execute` results on MRI.
513
+ # @see #exec_query
514
+ # @see #exec_insert
515
+ # @see #exec_update
516
+ def execute(sql, name = nil, binds = nil)
517
+ sql = suble_binds to_sql(sql, binds), binds if binds
518
+ if name == :skip_logging
519
+ _execute(sql, name)
520
+ else
521
+ log(sql, name) { _execute(sql, name) }
522
+ end
523
+ end
524
+
525
+ # We need to do it this way, to allow Rails stupid tests to always work
526
+ # even if we define a new `execute` method. Instead of mixing in a new
527
+ # `execute`, an `_execute` should be mixed in.
528
+ # @deprecated it was only introduced due tests
529
+ # @private
530
+ def _execute(sql, name = nil)
531
+ @connection.execute(sql)
532
+ end
533
+ private :_execute
534
+
535
+ # Kind of `execute(sql) rescue nil` but logging failures at debug level only.
536
+ def execute_quietly(sql, name = 'SQL')
537
+ log(sql, name) do
538
+ begin
539
+ _execute(sql)
540
+ rescue => e
541
+ logger.debug("#{e.class}: #{e.message}: #{sql}")
542
+ end
543
+ end
544
+ end
545
+
546
+ # @override
547
+ def tables(name = nil)
548
+ @connection.tables
549
+ end
550
+
551
+ # @override
552
+ def table_exists?(name)
553
+ return false unless name
554
+ @connection.table_exists?(name) # schema_name = nil
555
+ end
556
+
557
+ # @override
558
+ def data_sources
559
+ tables
560
+ end if ArJdbc::AR42
561
+
562
+ # @override
563
+ def data_source_exists?(name)
564
+ table_exists?(name)
565
+ end if ArJdbc::AR42
566
+
567
+ # @override
568
+ def indexes(table_name, name = nil, schema_name = nil)
569
+ @connection.indexes(table_name, name, schema_name)
570
+ end
571
+
572
+ # @override
573
+ def pk_and_sequence_for(table)
574
+ ( key = primary_key(table) ) ? [ key, nil ] : nil
575
+ end
576
+
577
+ # @override
578
+ def primary_keys(table)
579
+ @connection.primary_keys(table)
580
+ end
581
+
582
+ # @override
583
+ def foreign_keys(table_name)
584
+ @connection.foreign_keys(table_name)
585
+ end if ArJdbc::AR42
586
+
587
+ # Does our database (+ its JDBC driver) support foreign-keys?
588
+ # @since 1.3.18
589
+ # @override
590
+ def supports_foreign_keys?
591
+ @connection.supports_foreign_keys?
592
+ end if ArJdbc::AR42
593
+
594
+ # @deprecated Rather use {#update_lob_value} instead.
595
+ def write_large_object(*args)
596
+ @connection.write_large_object(*args)
597
+ end
598
+
599
+ # @param record the record e.g. `User.find(1)`
600
+ # @param column the model's column e.g. `User.columns_hash['photo']`
601
+ # @param value the lob value - string or (IO or Java) stream
602
+ def update_lob_value(record, column, value)
603
+ @connection.update_lob_value(record, column, value)
604
+ end
605
+
606
+ if ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 0
607
+
608
+ #attr_reader :visitor unless method_defined?(:visitor) # not in 3.0
609
+
610
+ # @private
611
+ def to_sql(arel, binds = nil)
612
+ # NOTE: can not handle `visitor.accept(arel.ast)` right
613
+ arel.respond_to?(:to_sql) ? arel.send(:to_sql) : arel
614
+ end
615
+
616
+ elsif ActiveRecord::VERSION::MAJOR < 3 # AR-2.3 'fake' #to_sql method
617
+
618
+ # @private
619
+ def to_sql(sql, binds = nil)
620
+ sql
621
+ end
622
+
623
+ end
624
+
625
+ protected
626
+
627
+ # @override so that we do not have to care having 2 arguments on 3.0
628
+ def log(sql, name = nil, binds = [])
629
+ unless binds.blank?
630
+ binds = binds.map do |column, value|
631
+ column ? [column.name, value] : [nil, value]
632
+ end
633
+ sql = "#{sql} #{binds.inspect}"
634
+ end
635
+ super(sql, name || 'SQL') # `log(sql, name)` on AR <= 3.0
636
+ end if ActiveRecord::VERSION::MAJOR < 3 ||
637
+ ( ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR < 1 )
638
+
639
+ def translate_exception(e, message)
640
+ # we shall not translate native "Java" exceptions as they might
641
+ # swallow an ArJdbc / driver bug into a AR::StatementInvalid ...
642
+ return e if e.is_a?(NativeException) # JRuby 1.6
643
+ return e if e.is_a?(Java::JavaLang::Throwable)
644
+
645
+ case e
646
+ when SystemExit, SignalException, NoMemoryError then e
647
+ # NOTE: wraps AR::JDBCError into AR::StatementInvalid, desired ?!
648
+ else super
649
+ end
650
+ end
651
+
652
+ # Take an id from the result of an INSERT query.
653
+ # @return [Integer, NilClass]
654
+ def last_inserted_id(result)
655
+ if result.is_a?(Hash) || result.is_a?(ActiveRecord::Result)
656
+ result.first.first[1] # .first = { "id"=>1 } .first = [ "id", 1 ]
657
+ else
658
+ result
659
+ end
660
+ end
661
+
662
+ # @private
663
+ def last_inserted_id(result)
664
+ if result.is_a?(Hash)
665
+ result.first.first[1] # .first = { "id"=>1 } .first = [ "id", 1 ]
666
+ else
667
+ result
668
+ end
669
+ end unless defined? ActiveRecord::Result
670
+
671
+ # NOTE: make sure if adapter overrides #table_definition that it will
672
+ # work on AR 3.x as well as 4.0
673
+ if ActiveRecord::VERSION::MAJOR > 3
674
+
675
+ # aliasing #create_table_definition as #table_definition :
676
+ alias table_definition create_table_definition
677
+
678
+ # `TableDefinition.new native_database_types, name, temporary, options`
679
+ # and ActiveRecord 4.1 supports optional `as` argument (which defaults
680
+ # to nil) to provide the SQL to use to generate the table:
681
+ # `TableDefinition.new native_database_types, name, temporary, options, as`
682
+ # @private
683
+ def create_table_definition(*args)
684
+ table_definition(*args)
685
+ end
686
+
687
+ # @note AR-4x arguments expected: `(name, temporary, options)`
688
+ # @private documented bellow
689
+ def new_table_definition(table_definition, *args)
690
+ if ActiveRecord::VERSION::MAJOR > 4
691
+ table_definition.new(*args)
692
+ else
693
+ table_definition.new native_database_types, *args
694
+ end
695
+ end
696
+ private :new_table_definition
697
+
698
+ # @private
699
+ def new_index_definition(table, name, unique, columns, lengths,
700
+ orders = nil, where = nil, type = nil, using = nil)
701
+ IndexDefinition.new(table, name, unique, columns, lengths, orders, where, type, using)
702
+ end
703
+ private :new_index_definition
704
+
705
+ #
706
+
707
+ # Provides backwards-compatibility on ActiveRecord 4.1 for DB adapters
708
+ # that override this and than call super expecting to work.
709
+ # @note This method is available in 4.0 but won't be in 4.1
710
+ # @private
711
+ def add_column_options!(sql, options)
712
+ sql << " DEFAULT #{quote(options[:default], options[:column])}" if options_include_default?(options)
713
+ # must explicitly check for :null to allow change_column to work on migrations
714
+ sql << " NOT NULL" if options[:null] == false
715
+ sql << " AUTO_INCREMENT" if options[:auto_increment] == true
716
+ end
717
+ public :add_column_options!
718
+
719
+ else # AR < 4.0
720
+
721
+ # Helper to easily override #table_definition (on AR 3.x/4.0) as :
722
+ # ```
723
+ # def table_definition(*args)
724
+ # new_table_definition(TableDefinition, *args)
725
+ # end
726
+ # ```
727
+ def new_table_definition(table_definition, *args)
728
+ table_definition.new(self) # args ignored only used for 4.0
729
+ end
730
+ private :new_table_definition
731
+
732
+ # @private (:table, :name, :unique, :columns, :lengths, :orders)
733
+ def new_index_definition(table, name, unique, columns, lengths,
734
+ orders = nil, where = nil, type = nil, using = nil)
735
+ IndexDefinition.new(table, name, unique, columns, lengths, orders)
736
+ end
737
+ # @private (:table, :name, :unique, :columns, :lengths)
738
+ def new_index_definition(table, name, unique, columns, lengths,
739
+ orders = nil, where = nil, type = nil, using = nil)
740
+ IndexDefinition.new(table, name, unique, columns, lengths)
741
+ end if ActiveRecord::VERSION::STRING < '3.2'
742
+ private :new_index_definition
743
+
744
+ end
745
+
746
+ # @return whether `:prepared_statements` are to be used
747
+ def prepared_statements?
748
+ return @prepared_statements unless (@prepared_statements ||= nil).nil?
749
+ @prepared_statements = self.class.prepared_statements?(config)
750
+ end
751
+
752
+ # Allows changing the prepared statements setting for this connection.
753
+ # @see #prepared_statements?
754
+ #def prepared_statements=(statements)
755
+ # @prepared_statements = statements
756
+ #end
757
+
758
+ def self.prepared_statements?(config)
759
+ config.key?(:prepared_statements) ?
760
+ type_cast_config_to_boolean(config.fetch(:prepared_statements)) :
761
+ false # off by default - NOTE: on AR 4.x it's on by default !?
762
+ end
763
+
764
+ if @@suble_binds = Java::JavaLang::System.getProperty('arjdbc.adapter.suble_binds')
765
+ @@suble_binds = Java::JavaLang::Boolean.parseBoolean(@@suble_binds)
766
+ else
767
+ @@suble_binds = ActiveRecord::VERSION::MAJOR < 4 # due compatibility
768
+ end
769
+ def self.suble_binds?; @@suble_binds; end
770
+ def self.suble_binds=(flag); @@suble_binds = flag; end
771
+
772
+ private
773
+
774
+ # @private Supporting "string-subling" on AR 4.0 would require {#to_sql}
775
+ # to consume binds parameters otherwise it happens twice e.g. for a record
776
+ # insert it is called during {#insert} as well as on {#exec_insert} ...
777
+ # but that than leads to other issues with libraries that save the binds
778
+ # array and run a query again since it's the very same instance on 4.0 !
779
+ def suble_binds(sql, binds)
780
+ sql
781
+ end
782
+
783
+ # @deprecated No longer used, kept for 1.2 API compatibility.
784
+ def extract_sql(arel)
785
+ arel.respond_to?(:to_sql) ? arel.send(:to_sql) : arel
786
+ end
787
+
788
+ if ActiveRecord::VERSION::MAJOR > 2
789
+ # Helper useful during {#quote} since AREL might pass in it's literals
790
+ # to be quoted, fixed since AREL 4.0.0.beta1 : http://git.io/7gyTig
791
+ def sql_literal?(value); ::Arel::Nodes::SqlLiteral === value; end
792
+ else
793
+ # @private
794
+ def sql_literal?(value); false; end
795
+ end
796
+
797
+ # Helper to get local/UTC time (based on `ActiveRecord::Base.default_timezone`).
798
+ def get_time(value)
799
+ get = ::ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
800
+ value.respond_to?(get) ? value.send(get) : value
801
+ end
802
+
803
+ protected
804
+
805
+ # @return whether the given SQL string is a 'SELECT' like
806
+ # query (returning a result set)
807
+ def self.select?(sql)
808
+ JdbcConnection::select?(sql)
809
+ end
810
+
811
+ # @return whether the given SQL string is an 'INSERT' query
812
+ def self.insert?(sql)
813
+ JdbcConnection::insert?(sql)
814
+ end
815
+
816
+ # @return whether the given SQL string is an 'UPDATE' (or 'DELETE') query
817
+ def self.update?(sql)
818
+ ! select?(sql) && ! insert?(sql)
819
+ end
820
+
821
+ unless defined? AbstractAdapter.type_cast_config_to_integer
822
+
823
+ # @private
824
+ def self.type_cast_config_to_integer(config)
825
+ config =~ /\A\d+\z/ ? config.to_i : config
826
+ end
827
+
828
+ end
829
+
830
+ # @private
831
+ def self.type_cast_config_to_boolean(config)
832
+ config == 'false' ? false : (config == 'true' ? true : config)
833
+ end
834
+
835
+ public
836
+
837
+ # @note Used by Java API to convert dates from (custom) SELECTs (might get refactored).
838
+ # @private
839
+ def _string_to_date(value); jdbc_column_class.string_to_date(value) end
840
+
841
+ # @note Used by Java API to convert times from (custom) SELECTs (might get refactored).
842
+ # @private
843
+ def _string_to_time(value); jdbc_column_class.string_to_dummy_time(value) end
844
+
845
+ # @note Used by Java API to convert times from (custom) SELECTs (might get refactored).
846
+ # @private
847
+ def _string_to_timestamp(value); jdbc_column_class.string_to_time(value) end
848
+
849
+ if ActiveRecord::VERSION::STRING > '4.2'
850
+
851
+ # @private
852
+ @@_date = nil
853
+
854
+ # @private
855
+ def _string_to_date(value)
856
+ if jdbc_column_class.respond_to?(:string_to_date)
857
+ jdbc_column_class.string_to_date(value)
858
+ else
859
+ (@@_date ||= ActiveRecord::Type::Date.new).send(:cast_value, value)
860
+ end
861
+ end
862
+
863
+ # @private
864
+ @@_time = nil
865
+
866
+ # @private
867
+ def _string_to_time(value)
868
+ if jdbc_column_class.respond_to?(:string_to_dummy_time)
869
+ jdbc_column_class.string_to_dummy_time(value)
870
+ else
871
+ (@@_time ||= ActiveRecord::Type::Time.new).send(:cast_value, value)
872
+ end
873
+ end
874
+
875
+ # @private
876
+ @@_date_time = nil
877
+
878
+ # @private
879
+ def _string_to_timestamp(value)
880
+ if jdbc_column_class.respond_to?(:string_to_time)
881
+ jdbc_column_class.string_to_time(value)
882
+ else
883
+ (@@_date_time ||= ActiveRecord::Type::DateTime.new).send(:cast_value, value)
884
+ end
885
+ end
886
+
887
+ end
888
+
889
+ if ActiveRecord::VERSION::MAJOR < 4 # emulating Rails 3.x compatibility
890
+ JdbcConnection.raw_date_time = true if JdbcConnection.raw_date_time?.nil?
891
+ JdbcConnection.raw_boolean = true if JdbcConnection.raw_boolean?.nil?
892
+ elsif ArJdbc::AR42 # AR::Type should do the conversion - for better accuracy
893
+ JdbcConnection.raw_date_time = true if JdbcConnection.raw_date_time?.nil?
894
+ JdbcConnection.raw_boolean = true if JdbcConnection.raw_boolean?.nil?
895
+ end
896
+
897
+ end
898
+ end
899
+ end