activerecord-jdbc-adapter 1.2.5 → 1.2.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (155) hide show
  1. data/.gitignore +1 -0
  2. data/.travis.yml +5 -1
  3. data/Appraisals +5 -5
  4. data/Gemfile +9 -1
  5. data/Gemfile.lock +44 -10
  6. data/History.txt +126 -2
  7. data/README.md +246 -0
  8. data/Rakefile +34 -25
  9. data/activerecord-jdbc-adapter.gemspec +1 -1
  10. data/gemfiles/rails23.gemfile +5 -3
  11. data/gemfiles/rails23.gemfile.lock +26 -18
  12. data/gemfiles/rails30.gemfile +4 -2
  13. data/gemfiles/rails30.gemfile.lock +16 -8
  14. data/gemfiles/rails31.gemfile +4 -2
  15. data/gemfiles/rails31.gemfile.lock +16 -9
  16. data/gemfiles/rails32.gemfile +4 -2
  17. data/gemfiles/rails32.gemfile.lock +15 -8
  18. data/lib/active_record/connection_adapters/db2_adapter.rb +1 -0
  19. data/lib/arel/visitors/sql_server.rb +3 -0
  20. data/lib/arjdbc.rb +3 -5
  21. data/lib/arjdbc/db2.rb +1 -0
  22. data/lib/arjdbc/db2/adapter.rb +302 -196
  23. data/lib/arjdbc/db2/connection_methods.rb +18 -0
  24. data/lib/arjdbc/derby/active_record_patch.rb +12 -0
  25. data/lib/arjdbc/derby/adapter.rb +180 -158
  26. data/lib/arjdbc/derby/connection_methods.rb +5 -1
  27. data/lib/arjdbc/firebird/adapter.rb +27 -19
  28. data/lib/arjdbc/h2/adapter.rb +162 -7
  29. data/lib/arjdbc/h2/connection_methods.rb +5 -1
  30. data/lib/arjdbc/hsqldb.rb +1 -1
  31. data/lib/arjdbc/hsqldb/adapter.rb +96 -61
  32. data/lib/arjdbc/hsqldb/connection_methods.rb +5 -1
  33. data/lib/arjdbc/hsqldb/explain_support.rb +35 -0
  34. data/lib/arjdbc/informix/adapter.rb +56 -55
  35. data/lib/arjdbc/jdbc/adapter.rb +173 -86
  36. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  37. data/lib/arjdbc/jdbc/column.rb +28 -23
  38. data/lib/arjdbc/jdbc/connection.rb +10 -6
  39. data/lib/arjdbc/jdbc/driver.rb +13 -5
  40. data/lib/arjdbc/jdbc/serialized_attributes_helper.rb +21 -0
  41. data/lib/arjdbc/mssql.rb +1 -1
  42. data/lib/arjdbc/mssql/adapter.rb +51 -53
  43. data/lib/arjdbc/mssql/connection_methods.rb +8 -1
  44. data/lib/arjdbc/mysql.rb +1 -1
  45. data/lib/arjdbc/mysql/adapter.rb +186 -150
  46. data/lib/arjdbc/mysql/connection_methods.rb +9 -9
  47. data/lib/arjdbc/mysql/explain_support.rb +85 -0
  48. data/lib/arjdbc/oracle.rb +1 -1
  49. data/lib/arjdbc/oracle/adapter.rb +232 -125
  50. data/lib/arjdbc/oracle/connection_methods.rb +2 -2
  51. data/lib/arjdbc/postgresql.rb +1 -1
  52. data/lib/arjdbc/postgresql/adapter.rb +134 -86
  53. data/lib/arjdbc/postgresql/connection_methods.rb +6 -4
  54. data/lib/arjdbc/postgresql/explain_support.rb +55 -0
  55. data/lib/arjdbc/sqlite3.rb +1 -1
  56. data/lib/arjdbc/sqlite3/adapter.rb +176 -108
  57. data/lib/arjdbc/sqlite3/connection_methods.rb +5 -5
  58. data/lib/arjdbc/sqlite3/explain_support.rb +32 -0
  59. data/lib/arjdbc/sybase/adapter.rb +7 -6
  60. data/lib/arjdbc/version.rb +1 -1
  61. data/pom.xml +1 -1
  62. data/rakelib/02-test.rake +9 -11
  63. data/rakelib/rails.rake +18 -10
  64. data/src/java/arjdbc/db2/DB2Module.java +70 -0
  65. data/src/java/arjdbc/derby/DerbyModule.java +24 -5
  66. data/src/java/arjdbc/hsqldb/HSQLDBModule.java +66 -0
  67. data/src/java/arjdbc/jdbc/AdapterJavaService.java +14 -7
  68. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +111 -89
  69. data/src/java/arjdbc/mysql/MySQLModule.java +79 -70
  70. data/src/java/arjdbc/oracle/OracleModule.java +74 -0
  71. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +5 -10
  72. data/src/java/arjdbc/sqlite3/SQLite3Module.java +77 -0
  73. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +127 -0
  74. data/src/java/arjdbc/sqlite3/Sqlite3RubyJdbcConnection.java +25 -111
  75. data/src/java/arjdbc/util/QuotingUtils.java +104 -0
  76. data/test/abstract_db_create.rb +6 -6
  77. data/test/activerecord/connection_adapters/type_conversion_test.rb +2 -2
  78. data/test/assets/flowers.jpg +0 -0
  79. data/test/binary.rb +67 -0
  80. data/test/db/db2.rb +30 -7
  81. data/test/db/jdbc.rb +4 -2
  82. data/test/db/oracle.rb +18 -27
  83. data/test/db2_binary_test.rb +6 -0
  84. data/test/db2_serialize_test.rb +6 -0
  85. data/test/db2_simple_test.rb +20 -25
  86. data/test/db2_test.rb +71 -0
  87. data/test/derby_binary_test.rb +6 -0
  88. data/test/derby_migration_test.rb +42 -35
  89. data/test/derby_reset_column_information_test.rb +1 -0
  90. data/test/derby_row_locking_test.rb +17 -0
  91. data/test/derby_schema_dump_test.rb +9 -0
  92. data/test/derby_serialize_test.rb +6 -0
  93. data/test/derby_simple_test.rb +59 -17
  94. data/test/generic_jdbc_connection_test.rb +112 -5
  95. data/test/h2_binary_test.rb +6 -0
  96. data/test/h2_change_column_test.rb +1 -1
  97. data/test/h2_schema_dump_test.rb +25 -0
  98. data/test/h2_serialize_test.rb +6 -0
  99. data/test/h2_simple_test.rb +23 -9
  100. data/test/has_many_through.rb +18 -4
  101. data/test/hsqldb_binary_test.rb +6 -0
  102. data/test/hsqldb_schema_dump_test.rb +15 -0
  103. data/test/hsqldb_serialize_test.rb +6 -0
  104. data/test/hsqldb_simple_test.rb +1 -0
  105. data/test/informix_simple_test.rb +1 -1
  106. data/test/jdbc/db2.rb +23 -0
  107. data/test/jdbc/oracle.rb +23 -0
  108. data/test/jdbc_common.rb +3 -110
  109. data/test/jndi_callbacks_test.rb +0 -2
  110. data/test/jndi_test.rb +2 -0
  111. data/test/models/binary.rb +18 -0
  112. data/test/models/custom_pk_name.rb +1 -0
  113. data/test/models/data_types.rb +11 -2
  114. data/test/models/entry.rb +1 -1
  115. data/test/models/string_id.rb +2 -2
  116. data/test/models/thing.rb +1 -1
  117. data/test/models/topic.rb +32 -0
  118. data/test/mssql_legacy_types_test.rb +1 -1
  119. data/test/mssql_limit_offset_test.rb +13 -3
  120. data/test/mssql_serialize_test.rb +6 -0
  121. data/test/mysql_binary_test.rb +6 -0
  122. data/test/mysql_schema_dump_test.rb +220 -0
  123. data/test/mysql_serialize_test.rb +6 -0
  124. data/test/mysql_simple_test.rb +22 -2
  125. data/test/mysql_test.rb +93 -0
  126. data/test/oracle_binary_test.rb +6 -0
  127. data/test/oracle_limit_test.rb +2 -1
  128. data/test/oracle_serialize_test.rb +6 -0
  129. data/test/oracle_simple_test.rb +61 -0
  130. data/test/oracle_specific_test.rb +77 -26
  131. data/test/postgres_binary_test.rb +6 -0
  132. data/test/postgres_native_type_mapping_test.rb +12 -11
  133. data/test/postgres_nonseq_pkey_test.rb +1 -0
  134. data/test/postgres_reserved_test.rb +1 -0
  135. data/test/postgres_reset_column_information_test.rb +1 -0
  136. data/test/postgres_row_locking_test.rb +21 -0
  137. data/test/postgres_schema_dump_test.rb +88 -0
  138. data/test/postgres_schema_search_path_test.rb +1 -0
  139. data/test/postgres_simple_test.rb +62 -89
  140. data/test/postgres_table_alias_length_test.rb +1 -0
  141. data/test/postgres_test.rb +31 -0
  142. data/test/postgres_type_conversion_test.rb +16 -16
  143. data/test/row_locking.rb +69 -64
  144. data/test/schema_dump.rb +168 -0
  145. data/test/serialize.rb +277 -0
  146. data/test/simple.rb +326 -122
  147. data/test/sqlite3_serialize_test.rb +6 -0
  148. data/test/sqlite3_simple_test.rb +51 -84
  149. data/test/sqlite3_type_conversion_test.rb +101 -0
  150. data/test/test_helper.rb +224 -0
  151. metadata +325 -366
  152. data/README.rdoc +0 -214
  153. data/test/db/logger.rb +0 -3
  154. data/test/derby_multibyte_test.rb +0 -11
  155. data/test/mysql_info_test.rb +0 -123
@@ -2,7 +2,11 @@ module ActiveRecord
2
2
  class Base
3
3
  class << self
4
4
  def hsqldb_connection(config)
5
- require 'active_record/connection_adapters/jdbchsqldb_adapter'
5
+ begin
6
+ require 'jdbc/hsqldb'
7
+ ::Jdbc::HSQLDB.load_driver(:require) if defined?(::Jdbc::HSQLDB.load_driver)
8
+ rescue LoadError # assuming driver.jar is on the class-path
9
+ end
6
10
 
7
11
  config[:url] ||= "jdbc:hsqldb:#{config[:database]}"
8
12
  config[:driver] ||= defined?(::Jdbc::HSQLDB.driver_name) ? ::Jdbc::HSQLDB.driver_name : 'org.hsqldb.jdbcDriver'
@@ -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 = execute(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
+ rows = raw_result.map { |hash| hash.values }
31
+ rows.join("\n")
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,43 +1,35 @@
1
- module ::ActiveRecord
2
- class Base
3
- after_save :write_lobs
4
-
5
- private
6
- def write_lobs
7
- if connection.is_a?(ArJdbc::Informix)
8
- self.class.columns.each do |c|
9
- if [:text, :binary].include? c.type
10
- value = self[c.name]
11
- if respond_to?(:unserializable_attribute?)
12
- value = value.to_yaml if unserializable_attribute?(c.name, c)
13
- else
14
- value = value.to_yaml if value.is_a?(Hash)
15
- end
1
+ require 'arjdbc/jdbc/serialized_attributes_helper'
16
2
 
17
- unless value.nil? || (value == '')
18
- connection.write_large_object(c.type == :binary,
19
- c.name,
20
- self.class.table_name,
21
- self.class.primary_key,
22
- quote_value(id),
23
- value)
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
+ )
24
22
  end
25
23
  end
26
24
  end
27
- end
28
- end
29
- end
30
- end
31
25
 
32
- module ::ArJdbc
33
- module Informix
34
- def self.extended(base)
35
- @@db_major_version = base.select_one("SELECT dbinfo('version', 'major') version FROM systables WHERE tabid = 1")['version'].to_i
26
+ ActiveRecord::Base.after_save :after_save_with_informix_lob
27
+ @@_lob_callback_added = true
28
+ end
36
29
  end
37
30
 
38
31
  def self.column_selector
39
- [ /informix/i,
40
- lambda { |cfg, column| column.extend(::ArJdbc::Informix::Column) } ]
32
+ [ /informix/i, lambda { |cfg, column| column.extend(::ArJdbc::Informix::Column) } ]
41
33
  end
42
34
 
43
35
  def self.jdbc_connection_class
@@ -45,7 +37,8 @@ module ::ArJdbc
45
37
  end
46
38
 
47
39
  module Column
48
- private
40
+
41
+ private
49
42
  # TODO: Test all Informix column types.
50
43
  def simplified_type(field_type)
51
44
  if field_type =~ /serial/i
@@ -54,21 +47,23 @@ module ::ArJdbc
54
47
  super
55
48
  end
56
49
  end
50
+
57
51
  end
58
52
 
59
- def modify_types(tp)
60
- tp[:primary_key] = "SERIAL PRIMARY KEY"
61
- tp[:string] = { :name => "VARCHAR", :limit => 255 }
62
- tp[:integer] = { :name => "INTEGER" }
63
- tp[:float] = { :name => "FLOAT" }
64
- tp[:decimal] = { :name => "DECIMAL" }
65
- tp[:datetime] = { :name => "DATETIME YEAR TO FRACTION(5)" }
66
- tp[:timestamp] = { :name => "DATETIME YEAR TO FRACTION(5)" }
67
- tp[:time] = { :name => "DATETIME HOUR TO FRACTION(5)" }
68
- tp[:date] = { :name => "DATE" }
69
- tp[:binary] = { :name => "BYTE" }
70
- tp[:boolean] = { :name => "BOOLEAN" }
71
- tp
53
+ def modify_types(types)
54
+ super(types)
55
+ types[:primary_key] = "SERIAL PRIMARY KEY"
56
+ types[:string] = { :name => "VARCHAR", :limit => 255 }
57
+ types[:integer] = { :name => "INTEGER" }
58
+ types[:float] = { :name => "FLOAT" }
59
+ types[:decimal] = { :name => "DECIMAL" }
60
+ types[:datetime] = { :name => "DATETIME YEAR TO FRACTION(5)" }
61
+ types[:timestamp] = { :name => "DATETIME YEAR TO FRACTION(5)" }
62
+ types[:time] = { :name => "DATETIME HOUR TO FRACTION(5)" }
63
+ types[:date] = { :name => "DATE" }
64
+ types[:binary] = { :name => "BYTE" }
65
+ types[:boolean] = { :name => "BOOLEAN" }
66
+ types
72
67
  end
73
68
 
74
69
  def prefetch_primary_key?(table_name = nil)
@@ -85,11 +80,9 @@ module ::ArJdbc
85
80
 
86
81
  def add_limit_offset!(sql, options)
87
82
  if options[:limit]
88
- limit = "FIRST #{options[:limit]}"
89
- # SKIP available only in IDS >= 10
90
- offset = (@@db_major_version >= 10 && options[:offset]?
91
- "SKIP #{options[:offset]}" : "")
92
- sql.sub!(/^select /i, "SELECT #{offset} #{limit} ")
83
+ limit = "FIRST #{options[:limit]}" # SKIP available only in IDS >= 10 :
84
+ offset = (db_major_version >= 10 && options[:offset] ? "SKIP #{options[:offset]}" : "")
85
+ sql.sub!(/^\s*?select /i, "SELECT #{offset} #{limit} ")
93
86
  end
94
87
  sql
95
88
  end
@@ -104,10 +97,11 @@ module ::ArJdbc
104
97
  end
105
98
 
106
99
  def quote(value, column = nil)
107
- if column && [:binary, :text].include?(column.type)
100
+ column_type = column && column.type
101
+ if column_type == :binary || column_type == :text
108
102
  # LOBs are updated separately by an after_save trigger.
109
103
  "NULL"
110
- elsif column && column.type == :date
104
+ elsif column_type == :date
111
105
  "'#{value.mon}/#{value.day}/#{value.year}'"
112
106
  else
113
107
  super
@@ -132,11 +126,18 @@ module ::ArJdbc
132
126
  def remove_index(table_name, options = {})
133
127
  @connection.execute_update("DROP INDEX #{index_name(table_name, options)}")
134
128
  end
135
-
136
- private
129
+
137
130
  def select(sql, *rest)
138
131
  # Informix does not like "= NULL", "!= NULL", or "<> NULL".
139
132
  execute(sql.gsub(/(!=|<>)\s*null/i, "IS NOT NULL").gsub(/=\s*null/i, "IS NULL"), *rest)
140
133
  end
134
+
135
+ private
136
+
137
+ def db_major_version
138
+ @@db_major_version ||=
139
+ select_one("SELECT dbinfo('version', 'major') version FROM systables WHERE tabid = 1")['version'].to_i
140
+ end
141
+
141
142
  end # module Informix
142
143
  end # module ::ArJdbc
@@ -50,8 +50,20 @@ module ActiveRecord
50
50
  end
51
51
 
52
52
  # Retrieve the raw java.sql.Connection object.
53
- def jdbc_connection
54
- raw_connection.connection
53
+ # The unwrap parameter is useful if an attempt to unwrap a pooled (JNDI)
54
+ # connection should be made - to really return the native (SQL) object.
55
+ def jdbc_connection(unwrap = nil)
56
+ java_connection = raw_connection.connection
57
+ return java_connection unless unwrap
58
+ connection_class = java.sql.Connection.java_class
59
+ if java_connection.wrapper_for?(connection_class)
60
+ java_connection.unwrap(connection_class) # java.sql.Wrapper.unwrap
61
+ elsif java_connection.respond_to?(:connection)
62
+ # e.g. org.apache.tomcat.jdbc.pool.PooledConnection
63
+ java_connection.connection # getConnection
64
+ else
65
+ java_connection
66
+ end
55
67
  end
56
68
 
57
69
  # Locate specialized adapter specification if one exists based on config data
@@ -83,8 +95,8 @@ module ActiveRecord
83
95
  nil
84
96
  end
85
97
 
86
- def modify_types(tp)
87
- tp
98
+ def modify_types(types)
99
+ types
88
100
  end
89
101
 
90
102
  def adapter_name #:nodoc:
@@ -122,7 +134,7 @@ module ActiveRecord
122
134
  end
123
135
  end
124
136
 
125
- def is_a?(klass) # :nodoc:
137
+ def is_a?(klass) # :nodoc:
126
138
  # This is to fake out current_adapter? conditional logic in AR tests
127
139
  if Class === klass && klass.name =~ /#{adapter_name}Adapter$/i
128
140
  true
@@ -143,39 +155,39 @@ module ActiveRecord
143
155
  @connection.database_name
144
156
  end
145
157
 
146
- def native_sql_to_type(tp)
147
- if /^(.*?)\(([0-9]+)\)/ =~ tp
148
- tname = $1
149
- limit = $2.to_i
150
- ntype = native_database_types
151
- if ntype[:primary_key] == tp
152
- return :primary_key,nil
158
+ def native_sql_to_type(type)
159
+ if /^(.*?)\(([0-9]+)\)/ =~ type
160
+ tname, limit = $1, $2.to_i
161
+ ntypes = native_database_types
162
+ if ntypes[:primary_key] == type
163
+ return :primary_key, nil
153
164
  else
154
- ntype.each do |name,val|
165
+ ntypes.each do |name, val|
155
166
  if name == :primary_key
156
167
  next
157
168
  end
158
- if val[:name].downcase == tname.downcase && (val[:limit].nil? || val[:limit].to_i == limit)
159
- return name,limit
169
+ if val[:name].downcase == tname.downcase &&
170
+ ( val[:limit].nil? || val[:limit].to_i == limit )
171
+ return name, limit
160
172
  end
161
173
  end
162
174
  end
163
- elsif /^(.*?)/ =~ tp
175
+ elsif /^(.*?)/ =~ type
164
176
  tname = $1
165
- ntype = native_database_types
166
- if ntype[:primary_key] == tp
167
- return :primary_key,nil
177
+ ntypes = native_database_types
178
+ if ntypes[:primary_key] == type
179
+ return :primary_key, nil
168
180
  else
169
- ntype.each do |name,val|
181
+ ntypes.each do |name, val|
170
182
  if val[:name].downcase == tname.downcase && val[:limit].nil?
171
- return name,nil
183
+ return name, nil
172
184
  end
173
185
  end
174
186
  end
175
187
  else
176
- return :string,255
188
+ return :string, 255
177
189
  end
178
- return nil,nil
190
+ return nil, nil
179
191
  end
180
192
 
181
193
  def active?
@@ -191,44 +203,20 @@ module ActiveRecord
191
203
  @connection.disconnect!
192
204
  end
193
205
 
194
- def substitute_binds(manager, binds = [])
195
- sql = extract_sql(manager)
196
- if binds.empty?
197
- sql
198
- else
199
- copy = binds.dup
200
- sql.gsub('?') { quote(*copy.shift.reverse) }
206
+ if ActiveRecord::VERSION::MAJOR < 3
207
+
208
+ def jdbc_insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = []) # :nodoc:
209
+ insert_sql(sql, name, pk, id_value, sequence_name, binds)
201
210
  end
202
- end
203
-
204
- def execute(sql, name = nil, binds = [])
205
- sql = substitute_binds(sql, binds)
206
- if name == :skip_logging
207
- _execute(sql)
208
- else
209
- log(sql, name) { _execute(sql) }
211
+
212
+ def jdbc_update(sql, name = nil, binds = []) # :nodoc:
213
+ execute(sql, name, binds)
210
214
  end
211
- end
212
-
213
- # we need to do it this way, to allow Rails stupid tests to always work
214
- # even if we define a new execute method. Instead of mixing in a new
215
- # execute, an _execute should be mixed in.
216
- def _execute(sql, name = nil)
217
- @connection.execute(sql)
218
- end
219
-
220
- def jdbc_insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
221
- insert_sql(sql, name, pk, id_value, sequence_name, binds)
222
- end
223
-
224
- def jdbc_update(sql, name = nil, binds = []) #:nodoc:
225
- execute(sql, name, binds)
226
- end
227
- def jdbc_select_all(sql, name = nil, binds = [])
228
- select(sql, name, binds)
229
- end
230
-
231
- if ActiveRecord::VERSION::MAJOR < 3
215
+
216
+ def jdbc_select_all(sql, name = nil, binds = []) # :nodoc:
217
+ select(sql, name, binds)
218
+ end
219
+
232
220
  # Allow query caching to work even when we override alias_method_chain'd methods
233
221
  alias_chained_method :select_all, :query_cache, :jdbc_select_all
234
222
  alias_chained_method :update, :query_dirty, :jdbc_update
@@ -238,25 +226,14 @@ module ActiveRecord
238
226
  def select_one(sql, name = nil)
239
227
  select(sql, name).first
240
228
  end
229
+
241
230
  end
242
231
 
243
- def last_inserted_id(result)
244
- result
245
- end
246
-
247
- def select_rows(sql, name = nil)
248
- rows = []
249
- select(sql, name).each {|row| rows << row.values }
250
- rows
251
- end
252
-
253
- def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
254
- id = execute(sql, name = nil, binds)
255
- id_value || id
232
+ def jdbc_columns(table_name, name = nil)
233
+ @connection.columns(table_name.to_s)
256
234
  end
257
-
258
- ### Rails 3.1 prepared statement support
259
-
235
+ alias_chained_method :columns, :query_cache, :jdbc_columns
236
+
260
237
  # Executes +sql+ statement in the context of this connection using
261
238
  # +binds+ as the bind substitutes. +name+ is logged along with
262
239
  # the executed +sql+ statement.
@@ -284,11 +261,69 @@ module ActiveRecord
284
261
  def exec_update(sql, name, binds)
285
262
  exec_query(sql, name, binds)
286
263
  end
264
+
265
+ if ActiveRecord::VERSION::MAJOR < 3 # 2.3.x
266
+
267
+ # NOTE: 2.3 log(sql, name) while does not like `name == nil`
268
+
269
+ # Executes the SQL statement in the context of this connection.
270
+ def execute(sql, name = nil, binds = [])
271
+ sql = to_sql(sql, binds)
272
+ if name == :skip_logging
273
+ _execute(sql, name)
274
+ else
275
+ log(sql, name) { _execute(sql, name ||= "SQL") }
276
+ end
277
+ end
287
278
 
288
- def jdbc_columns(table_name, name = nil)
289
- @connection.columns(table_name.to_s)
279
+ else
280
+ #elsif ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 0
281
+
282
+ # NOTE: 3.0 log(sql, name) allow `name == nil` (handles `name ||= "SQL"`)
283
+
284
+ # Executes the SQL statement in the context of this connection.
285
+ def execute(sql, name = nil, binds = [])
286
+ sql = to_sql(sql, binds)
287
+ if name == :skip_logging
288
+ _execute(sql, name)
289
+ else
290
+ log(sql, name) { _execute(sql, name) }
291
+ end
292
+ end
293
+
294
+ # NOTE: 3.1 log(sql, name = "SQL", binds = []) `name == nil` is fine
295
+ # TODO skip logging the binds (twice) until prepared-statement support
296
+
297
+ #else
298
+ end
299
+
300
+ # we need to do it this way, to allow Rails stupid tests to always work
301
+ # even if we define a new execute method. Instead of mixing in a new
302
+ # execute, an _execute should be mixed in.
303
+ def _execute(sql, name = nil)
304
+ @connection.execute(sql)
305
+ end
306
+ private :_execute
307
+
308
+ # Returns an array of record hashes with the column names as keys and
309
+ # column values as values.
310
+ # @note on AR-3.2 expects "only" 2 arguments `select(sql, name = nil)`
311
+ # we accept 3 arguments as well `select(sql, name = nil, binds = [])`
312
+ def select(*args)
313
+ execute(*args)
314
+ end
315
+
316
+ def select_rows(sql, name = nil)
317
+ rows = []
318
+ select(sql, name).each {|row| rows << row.values }
319
+ rows
320
+ end
321
+
322
+ # NOTE: we have an extra binds argument at the end due 2.3 support (due {#jdbc_insert}).
323
+ def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = []) # :nodoc:
324
+ id = execute(sql, name = nil, binds)
325
+ id_value || id
290
326
  end
291
- alias_chained_method :columns, :query_cache, :jdbc_columns
292
327
 
293
328
  def tables(name = nil)
294
329
  @connection.tables
@@ -331,24 +366,76 @@ module ActiveRecord
331
366
  @connection.primary_keys(table)
332
367
  end
333
368
 
334
- def select(*args)
335
- execute(*args)
369
+ if ActiveRecord::VERSION::MAJOR >= 3
370
+
371
+ # Converts an arel AST to SQL
372
+ def to_sql(arel, binds = [])
373
+ if arel.respond_to?(:ast)
374
+ visitor.accept(arel.ast) do
375
+ quote(*binds.shift.reverse)
376
+ end
377
+ else # for backwards compatibility :
378
+ sql = arel.respond_to?(:to_sql) ? arel.send(:to_sql) : arel
379
+ return sql if binds.blank?
380
+ sql.gsub('?') { quote(*binds.shift.reverse) }
381
+ end
336
382
  end
337
-
383
+
384
+ else # AR-2.3 no #to_sql method
385
+
386
+ # Substitutes SQL bind (?) parameters
387
+ def to_sql(sql, binds = [])
388
+ sql = sql.send(:to_sql) if sql.respond_to?(:to_sql)
389
+ return sql if binds.blank?
390
+ copy = binds.dup
391
+ sql.gsub('?') { quote(*copy.shift.reverse) }
392
+ end
393
+
394
+ end
395
+
396
+ protected
397
+
338
398
  def translate_exception(e, message)
339
399
  puts e.backtrace if $DEBUG || ENV['DEBUG']
340
400
  super
341
401
  end
342
402
 
343
- def extract_sql(obj)
344
- if obj.respond_to? :to_sql
345
- obj.send :to_sql
403
+ def last_inserted_id(result)
404
+ result
405
+ end
406
+
407
+ private
408
+
409
+ # #deprecated no longer used
410
+ def substitute_binds(sql, binds = [])
411
+ sql = extract_sql(sql)
412
+ if binds.empty?
413
+ sql
346
414
  else
347
- obj
415
+ copy = binds.dup
416
+ sql.gsub('?') { quote(*copy.shift.reverse) }
348
417
  end
349
418
  end
350
419
 
351
- protected :translate_exception, :extract_sql
420
+ # #deprecated no longer used
421
+ def extract_sql(obj)
422
+ obj.respond_to?(:to_sql) ? obj.send(:to_sql) : obj
423
+ end
424
+
425
+ protected
426
+
427
+ def self.select?(sql)
428
+ JdbcConnection::select?(sql)
429
+ end
430
+
431
+ def self.insert?(sql)
432
+ JdbcConnection::insert?(sql)
433
+ end
434
+
435
+ def self.update?(sql)
436
+ ! select?(sql) && ! insert?(sql)
437
+ end
438
+
352
439
  end
353
440
  end
354
441
  end