activerecord-jdbc-adapter 5.0.pre1 → 50.0

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.

Potentially problematic release.


This version of activerecord-jdbc-adapter might be problematic. Click here for more details.

Files changed (66) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -2
  3. data/.travis.yml +15 -416
  4. data/Gemfile +35 -37
  5. data/README.md +23 -118
  6. data/RUNNING_TESTS.md +31 -26
  7. data/Rakefile +2 -3
  8. data/lib/arjdbc/abstract/connection_management.rb +21 -0
  9. data/lib/arjdbc/abstract/core.rb +62 -0
  10. data/lib/arjdbc/abstract/database_statements.rb +46 -0
  11. data/lib/arjdbc/abstract/statement_cache.rb +58 -0
  12. data/lib/arjdbc/abstract/transaction_support.rb +86 -0
  13. data/lib/arjdbc/derby/adapter.rb +6 -1
  14. data/lib/arjdbc/discover.rb +0 -7
  15. data/lib/arjdbc/firebird/adapter.rb +2 -2
  16. data/lib/arjdbc/jdbc.rb +2 -2
  17. data/lib/arjdbc/jdbc/adapter.rb +10 -252
  18. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  19. data/lib/arjdbc/jdbc/connection.rb +6 -0
  20. data/lib/arjdbc/mysql/adapter.rb +82 -946
  21. data/lib/arjdbc/mysql/connection_methods.rb +4 -2
  22. data/lib/arjdbc/postgresql/adapter.rb +270 -970
  23. data/lib/arjdbc/postgresql/base/array_decoder.rb +26 -0
  24. data/lib/arjdbc/postgresql/base/array_encoder.rb +25 -0
  25. data/lib/arjdbc/postgresql/base/pgconn.rb +8 -5
  26. data/lib/arjdbc/postgresql/column.rb +10 -599
  27. data/lib/arjdbc/postgresql/connection_methods.rb +9 -0
  28. data/lib/arjdbc/postgresql/name.rb +24 -0
  29. data/lib/arjdbc/postgresql/oid_types.rb +28 -109
  30. data/lib/arjdbc/sqlite3/adapter.rb +18 -42
  31. data/lib/arjdbc/tasks/database_tasks.rb +1 -3
  32. data/lib/arjdbc/tasks/db2_database_tasks.rb +2 -2
  33. data/lib/arjdbc/version.rb +1 -1
  34. data/pom.xml +3 -3
  35. data/rakelib/02-test.rake +0 -12
  36. data/rakelib/compile.rake +1 -1
  37. data/rakelib/db.rake +7 -5
  38. data/rakelib/rails.rake +67 -64
  39. data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +1 -17
  40. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +518 -1260
  41. data/src/java/arjdbc/mysql/MySQLModule.java +3 -3
  42. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +53 -134
  43. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +214 -240
  44. data/src/java/arjdbc/sqlite3/SQLite3Module.java +0 -20
  45. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +85 -10
  46. metadata +16 -29
  47. data/Appraisals +0 -41
  48. data/lib/active_record/connection_adapters/oracle_adapter.rb +0 -1
  49. data/lib/arjdbc/common_jdbc_methods.rb +0 -89
  50. data/lib/arjdbc/mysql/bulk_change_table.rb +0 -150
  51. data/lib/arjdbc/mysql/column.rb +0 -162
  52. data/lib/arjdbc/mysql/explain_support.rb +0 -82
  53. data/lib/arjdbc/mysql/schema_creation.rb +0 -58
  54. data/lib/arjdbc/oracle.rb +0 -4
  55. data/lib/arjdbc/oracle/adapter.rb +0 -952
  56. data/lib/arjdbc/oracle/column.rb +0 -126
  57. data/lib/arjdbc/oracle/connection_methods.rb +0 -21
  58. data/lib/arjdbc/postgresql/base/oid.rb +0 -412
  59. data/lib/arjdbc/postgresql/base/schema_definitions.rb +0 -131
  60. data/lib/arjdbc/postgresql/explain_support.rb +0 -53
  61. data/lib/arjdbc/postgresql/oid/bytea.rb +0 -2
  62. data/lib/arjdbc/postgresql/schema_creation.rb +0 -60
  63. data/lib/arjdbc/tasks/oracle/enhanced_structure_dump.rb +0 -297
  64. data/lib/arjdbc/tasks/oracle_database_tasks.rb +0 -65
  65. data/src/java/arjdbc/oracle/OracleModule.java +0 -75
  66. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +0 -465
@@ -1,7 +1,7 @@
1
1
  ArJdbc::ConnectionMethods.module_eval do
2
2
  def mysql_connection(config)
3
3
  config[:adapter_spec] ||= ::ArJdbc::MySQL
4
- config[:adapter_class] = ActiveRecord::ConnectionAdapters::MysqlAdapter unless config.key?(:adapter_class)
4
+ config[:adapter_class] = ActiveRecord::ConnectionAdapters::Mysql2Adapter unless config.key?(:adapter_class)
5
5
 
6
6
  return jndi_connection(config) if jndi_config?(config)
7
7
 
@@ -29,6 +29,8 @@ ArJdbc::ConnectionMethods.module_eval do
29
29
 
30
30
  mariadb_driver = ! mysql_driver && driver[0, 12] == 'org.mariadb.' # org.mariadb.jdbc.Driver
31
31
 
32
+ config[:prepared_statements] ||= true if ENV['PREPARED_STATEMENTS'] == 'true'
33
+
32
34
  properties = ( config[:properties] ||= {} )
33
35
  if mysql_driver
34
36
  properties['zeroDateTimeBehavior'] ||= 'convertToNull'
@@ -78,7 +80,7 @@ ArJdbc::ConnectionMethods.module_eval do
78
80
 
79
81
  def mariadb_connection(config)
80
82
  config[:adapter_spec] ||= ::ArJdbc::MySQL
81
- config[:adapter_class] = ActiveRecord::ConnectionAdapters::MysqlAdapter unless config.key?(:adapter_class)
83
+ config[:adapter_class] = ActiveRecord::ConnectionAdapters::Mysql2Adapter unless config.key?(:adapter_class)
82
84
 
83
85
  return jndi_connection(config) if jndi_config?(config)
84
86
 
@@ -2,30 +2,38 @@
2
2
  ArJdbc.load_java_part :PostgreSQL
3
3
 
4
4
  require 'ipaddr'
5
+ require 'active_record/connection_adapters/abstract_adapter'
6
+ require 'active_record/connection_adapters/postgresql/column'
7
+ require 'active_record/connection_adapters/postgresql/explain_pretty_printer'
8
+ require 'active_record/connection_adapters/postgresql/quoting'
9
+ require 'active_record/connection_adapters/postgresql/referential_integrity'
10
+ require 'active_record/connection_adapters/postgresql/schema_dumper'
11
+ require 'active_record/connection_adapters/postgresql/schema_statements'
12
+ require 'active_record/connection_adapters/postgresql/type_metadata'
13
+ require 'active_record/connection_adapters/postgresql/utils'
14
+ require 'arjdbc/abstract/core'
15
+ require 'arjdbc/abstract/connection_management'
16
+ require 'arjdbc/abstract/database_statements'
17
+ require 'arjdbc/abstract/statement_cache'
18
+ require 'arjdbc/abstract/transaction_support'
19
+ require 'arjdbc/postgresql/base/array_decoder'
20
+ require 'arjdbc/postgresql/base/array_encoder'
21
+ require 'arjdbc/postgresql/name'
5
22
 
6
23
  module ArJdbc
7
24
  # Strives to provide Rails built-in PostgreSQL adapter (API) compatibility.
8
25
  module PostgreSQL
9
26
 
10
- # @deprecated no longer used
11
- # @private
12
- AR4_COMPAT = AR40
13
- # @deprecated no longer used
14
- # @private
15
- AR42_COMPAT = AR42
16
-
17
27
  require 'arjdbc/postgresql/column'
18
- require 'arjdbc/postgresql/explain_support'
19
- require 'arjdbc/postgresql/schema_creation' # AR 4.x
20
28
  require 'arel/visitors/postgresql_jdbc'
21
29
  # @private
22
30
  IndexDefinition = ::ActiveRecord::ConnectionAdapters::IndexDefinition
23
31
 
24
32
  # @private
25
- ForeignKeyDefinition = ::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition if ::ActiveRecord::ConnectionAdapters.const_defined? :ForeignKeyDefinition
33
+ ForeignKeyDefinition = ::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition
26
34
 
27
35
  # @private
28
- Type = ::ActiveRecord::Type if AR42
36
+ Type = ::ActiveRecord::Type
29
37
 
30
38
  # @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
31
39
  def self.jdbc_connection_class
@@ -130,172 +138,61 @@ module ArJdbc
130
138
  # @private
131
139
  ActiveRecordError = ::ActiveRecord::ActiveRecordError
132
140
 
133
- # Maps logical Rails types to PostgreSQL-specific data types.
134
- def type_to_sql(type, limit = nil, precision = nil, scale = nil)
135
- case type.to_s
136
- when 'binary'
137
- # PostgreSQL doesn't support limits on binary (bytea) columns.
138
- # The hard limit is 1Gb, because of a 32-bit size field, and TOAST.
139
- case limit
140
- when nil, 0..0x3fffffff; super(type)
141
- else raise(ActiveRecordError, "No binary type has byte size #{limit}.")
142
- end
143
- when 'text'
144
- # PostgreSQL doesn't support limits on text columns.
145
- # The hard limit is 1Gb, according to section 8.3 in the manual.
146
- case limit
147
- when nil, 0..0x3fffffff; super(type)
148
- else raise(ActiveRecordError, "The limit on text can be at most 1GB - 1byte.")
149
- end
150
- when 'integer'
151
- return 'integer' unless limit
152
-
153
- case limit
154
- when 1, 2; 'smallint'
155
- when 3, 4; 'integer'
156
- when 5..8; 'bigint'
157
- else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
158
- end
159
- when 'datetime'
160
- return super unless precision
161
-
162
- case precision
163
- when 0..6; "timestamp(#{precision})"
164
- else raise(ActiveRecordError, "No timestamp type has precision of #{precision}. The allowed range of precision is from 0 to 6")
165
- end
166
- else
167
- super
168
- end
169
- end
170
-
171
- def type_cast(value, column, array_member = false)
172
- return super(value, nil) unless column
173
-
174
- case value
175
- when String
176
- return super(value, column) unless 'bytea' == column.sql_type
177
- value # { :value => value, :format => 1 }
178
- when Array
179
- case column.sql_type
180
- when 'point'
181
- jdbc_column_class.point_to_string(value)
182
- when 'json', 'jsonb'
183
- jdbc_column_class.json_to_string(value)
184
- else
185
- return super(value, column) unless column.array?
186
- jdbc_column_class.array_to_string(value, column, self)
187
- end
188
- when NilClass
189
- if column.array? && array_member
190
- 'NULL'
191
- elsif column.array?
192
- value
193
- else
194
- super(value, column)
195
- end
196
- when Hash
197
- case column.sql_type
198
- when 'hstore'
199
- jdbc_column_class.hstore_to_string(value, array_member)
200
- when 'json', 'jsonb'
201
- jdbc_column_class.json_to_string(value)
202
- else super(value, column)
203
- end
204
- when IPAddr
205
- return super unless column.sql_type == 'inet' || column.sql_type == 'cidr'
206
- jdbc_column_class.cidr_to_string(value)
207
- when Range
208
- return super(value, column) unless /range$/ =~ column.sql_type
209
- jdbc_column_class.range_to_string(value)
210
- else
211
- super(value, column)
212
- end
213
- end if AR40 && ! AR42
214
-
215
- # @private
216
- def _type_cast(value)
217
- case value
218
- when Type::Binary::Data
219
- # Return a bind param hash with format as binary.
220
- # See http://deveiate.org/code/pg/PGconn.html#method-i-exec_prepared-doc
221
- # for more information
222
- { :value => value.to_s, :format => 1 }
223
- when OID::Xml::Data, OID::Bit::Data
224
- value.to_s
225
- else
226
- super
227
- end
228
- end if AR42
229
- private :_type_cast if AR42
230
-
231
141
  NATIVE_DATABASE_TYPES = {
232
- :primary_key => "serial primary key",
233
- :string => { :name => "character varying", :limit => 255 },
234
- :text => { :name => "text" },
235
- :integer => { :name => "integer" },
236
- :float => { :name => "float" },
237
- :numeric => { :name => "numeric" },
238
- :decimal => { :name => "decimal" }, # :limit => 1000
239
- :datetime => { :name => "timestamp" },
240
- :timestamp => { :name => "timestamp" },
241
- :time => { :name => "time" },
242
- :date => { :name => "date" },
243
- :binary => { :name => "bytea" },
244
- :boolean => { :name => "boolean" },
245
- :xml => { :name => "xml" },
246
- # AR-JDBC added :
247
- #:timestamptz => { :name => "timestamptz" },
248
- #:timetz => { :name => "timetz" },
249
- :money => { :name=>"money" },
250
- :char => { :name => "char" },
251
- :serial => { :name => "serial" }, # auto-inc integer, bigserial, smallserial
142
+ bigserial: 'bigserial',
143
+ primary_key: 'serial primary key',
144
+ bigint: { name: 'bigint' },
145
+ binary: { name: 'bytea' },
146
+ bit: { name: 'bit' },
147
+ bit_varying: { name: 'bit varying' },
148
+ boolean: { name: 'boolean' },
149
+ box: { name: 'box' },
150
+ char: { name: 'char' },
151
+ cidr: { name: 'cidr' },
152
+ circle: { name: 'circle' },
153
+ citext: { name: 'citext' },
154
+ date: { name: 'date' },
155
+ daterange: { name: 'daterange' },
156
+ datetime: { name: 'timestamp' },
157
+ decimal: { name: 'decimal' }, # :limit => 1000
158
+ float: { name: 'float' },
159
+ hstore: { name: 'hstore' },
160
+ inet: { name: 'inet' },
161
+ int4range: { name: 'int4range' },
162
+ int8range: { name: 'int8range' },
163
+ integer: { name: 'integer' },
164
+ interval: { name: 'interval' }, # This doesn't get added to AR's postgres adapter until 5.1 but it fixes broken tests in 5.0 ...
165
+ json: { name: 'json' },
166
+ jsonb: { name: 'jsonb' },
167
+ line: { name: 'line' },
168
+ lseg: { name: 'lseg' },
169
+ ltree: { name: 'ltree' },
170
+ macaddr: { name: 'macaddr' },
171
+ money: { name: 'money' },
172
+ numeric: { name: 'numeric' },
173
+ numrange: { name: 'numrange' },
174
+ path: { name: 'path' },
175
+ point: { name: 'point' },
176
+ polygon: { name: 'polygon' },
177
+ serial: { name: 'serial' }, # auto-inc integer, bigserial, smallserial
178
+ string: { name: 'character varying' },
179
+ text: { name: 'text' },
180
+ time: { name: 'time' },
181
+ timestamp: { name: 'timestamp' },
182
+ tsrange: { name: 'tsrange' },
183
+ tstzrange: { name: 'tstzrange' },
184
+ tsvector: { name: 'tsvector' },
185
+ uuid: { name: 'uuid' },
186
+ xml: { name: 'xml' }
252
187
  }
253
188
 
254
- NATIVE_DATABASE_TYPES.update({
255
- :tsvector => { :name => "tsvector" },
256
- :hstore => { :name => "hstore" },
257
- :inet => { :name => "inet" },
258
- :cidr => { :name => "cidr" },
259
- :macaddr => { :name => "macaddr" },
260
- :uuid => { :name => "uuid" },
261
- :json => { :name => "json" },
262
- :jsonb => { :name => "jsonb" },
263
- :ltree => { :name => "ltree" },
264
- # ranges :
265
- :daterange => { :name => "daterange" },
266
- :numrange => { :name => "numrange" },
267
- :tsrange => { :name => "tsrange" },
268
- :tstzrange => { :name => "tstzrange" },
269
- :int4range => { :name => "int4range" },
270
- :int8range => { :name => "int8range" },
271
- }) if AR40
272
-
273
- NATIVE_DATABASE_TYPES.update(
274
- :string => { :name => "character varying" },
275
- :bigserial => "bigserial",
276
- :bigint => { :name => "bigint" },
277
- :bit => { :name => "bit" },
278
- :bit_varying => { :name => "bit varying" }
279
- ) if AR42
280
-
281
189
  def native_database_types
282
190
  NATIVE_DATABASE_TYPES
283
191
  end
284
192
 
285
- # Adds `:array` option to the default set provided by the `AbstractAdapter`.
286
- # @override
287
- def prepare_column_options(column, types)
288
- spec = super
289
- spec[:array] = 'true' if column.respond_to?(:array) && column.array
290
- spec[:default] = "\"#{column.default_function}\"" if column.default_function
291
- spec
292
- end if AR40
293
-
294
- # Adds `:array` as a valid migration key.
295
- # @override
296
- def migration_keys
297
- super + [:array]
298
- end if AR40
193
+ def valid_type?(type)
194
+ !native_database_types[type].nil?
195
+ end
299
196
 
300
197
  # Enable standard-conforming strings if available.
301
198
  def set_standard_conforming_strings
@@ -333,15 +230,25 @@ module ArJdbc
333
230
  @standard_conforming_strings == true # return false if :unsupported
334
231
  end
335
232
 
336
- # Does PostgreSQL support migrations?
337
- def supports_migrations?
338
- true
339
- end
233
+ def supports_ddl_transactions?; true end
340
234
 
341
- # Does PostgreSQL support finding primary key on non-Active Record tables?
342
- def supports_primary_key?
343
- true
344
- end
235
+ def supports_explain?; true end
236
+
237
+ def supports_expression_index?; true end
238
+
239
+ def supports_index_sort_order?; true end
240
+
241
+ def supports_migrations?; true end
242
+
243
+ def supports_partial_index?; true end
244
+
245
+ def supports_primary_key?; true end # Supports finding primary key on non-Active Record tables
246
+
247
+ def supports_savepoints?; true end
248
+
249
+ def supports_transaction_isolation?(level = nil); true end
250
+
251
+ def supports_views?; true end
345
252
 
346
253
  # Does PostgreSQL support standard conforming strings?
347
254
  def supports_standard_conforming_strings?
@@ -357,50 +264,9 @@ module ArJdbc
357
264
  postgresql_version >= 80200
358
265
  end
359
266
 
360
- def supports_ddl_transactions?; true end
361
-
362
- def supports_transaction_isolation?; true end
363
-
364
- def supports_index_sort_order?; true end
365
-
366
- def supports_partial_index?; true end if AR40
367
-
368
267
  # Range data-types weren't introduced until PostgreSQL 9.2.
369
268
  def supports_ranges?
370
269
  postgresql_version >= 90200
371
- end if AR40
372
-
373
- def supports_transaction_isolation?(level = nil)
374
- true
375
- end
376
-
377
- # @override
378
- def supports_views?; true end
379
-
380
- if ArJdbc::AR50
381
- def views
382
- select_values("SELECT table_name FROM INFORMATION_SCHEMA.views WHERE table_schema = ANY (current_schemas(false))")
383
- end
384
- end
385
-
386
- # NOTE: handled by JdbcAdapter we override only to have save-point in logs :
387
-
388
- # @override
389
- def supports_savepoints?; true end
390
-
391
- # @override
392
- def create_savepoint(name = current_savepoint_name(true))
393
- log("SAVEPOINT #{name}", 'Savepoint') { super }
394
- end
395
-
396
- # @override
397
- def rollback_to_savepoint(name = current_savepoint_name(true))
398
- log("ROLLBACK TO SAVEPOINT #{name}", 'Savepoint') { super }
399
- end
400
-
401
- # @override
402
- def release_savepoint(name = current_savepoint_name(false))
403
- log("RELEASE SAVEPOINT #{name}", 'Savepoint') { super }
404
270
  end
405
271
 
406
272
  def supports_extensions?
@@ -441,159 +307,75 @@ module ArJdbc
441
307
  execute "SET SESSION AUTHORIZATION #{user}"
442
308
  end
443
309
 
310
+ # Came from postgres_adapter
311
+ def get_advisory_lock(lock_id) # :nodoc:
312
+ unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63
313
+ raise(ArgumentError, "Postgres requires advisory lock ids to be a signed 64 bit integer")
314
+ end
315
+ select_value("SELECT pg_try_advisory_lock(#{lock_id});")
316
+ end
317
+
318
+ # Came from postgres_adapter
319
+ def release_advisory_lock(lock_id) # :nodoc:
320
+ unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63
321
+ raise(ArgumentError, "Postgres requires advisory lock ids to be a signed 64 bit integer")
322
+ end
323
+ select_value("SELECT pg_advisory_unlock(#{lock_id})") == 't'.freeze
324
+ end
325
+
444
326
  # Returns the configured supported identifier length supported by PostgreSQL,
445
327
  # or report the default of 63 on PostgreSQL 7.x.
446
328
  def table_alias_length
447
329
  @table_alias_length ||= (
448
330
  postgresql_version >= 80000 ?
449
- select_one('SHOW max_identifier_length')['max_identifier_length'].to_i :
331
+ select_one('SHOW max_identifier_length', 'SCHEMA'.freeze)['max_identifier_length'].to_i :
450
332
  63
451
333
  )
452
334
  end
453
335
 
454
- def default_sequence_name(table_name, pk = nil)
455
- default_pk, default_seq = pk_and_sequence_for(table_name)
456
- default_seq || "#{table_name}_#{pk || default_pk || 'id'}_seq"
457
- end
458
-
459
- # Resets sequence to the max value of the table's primary key if present.
460
- def reset_pk_sequence!(table, pk = nil, sequence = nil)
461
- if ! pk || ! sequence
462
- default_pk, default_sequence = pk_and_sequence_for(table)
463
- pk ||= default_pk; sequence ||= default_sequence
464
- end
465
- if pk && sequence
466
- quoted_sequence = quote_column_name(sequence)
467
-
468
- select_value <<-end_sql, 'Reset Sequence'
469
- SELECT setval('#{quoted_sequence}', (SELECT COALESCE(MAX(#{quote_column_name pk})+(SELECT increment_by FROM #{quoted_sequence}), (SELECT min_value FROM #{quoted_sequence})) FROM #{quote_table_name(table)}), false)
470
- end_sql
471
- end
472
- end
473
-
474
- # Find a table's primary key and sequence.
475
- def pk_and_sequence_for(table)
476
- # try looking for a seq with a dependency on the table's primary key :
477
- result = select(<<-end_sql, 'PK and Serial Sequence')[0]
478
- SELECT attr.attname, seq.relname
479
- FROM pg_class seq,
480
- pg_attribute attr,
481
- pg_depend dep,
482
- pg_constraint cons
483
- WHERE seq.oid = dep.objid
484
- AND seq.relkind = 'S'
485
- AND attr.attrelid = dep.refobjid
486
- AND attr.attnum = dep.refobjsubid
487
- AND attr.attrelid = cons.conrelid
488
- AND attr.attnum = cons.conkey[1]
489
- AND cons.contype = 'p'
490
- AND dep.refobjid = '#{quote_table_name(table)}'::regclass
491
- end_sql
492
-
493
- if result.nil? || result.empty?
494
- # if that fails, try parsing the primary key's default value :
495
- result = select(<<-end_sql, 'PK and Custom Sequence')[0]
496
- SELECT attr.attname,
497
- CASE
498
- WHEN pg_get_expr(def.adbin, def.adrelid) !~* 'nextval' THEN NULL
499
- WHEN split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2) ~ '.' THEN
500
- substr(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2),
501
- strpos(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2), '.')+1)
502
- ELSE split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2)
503
- END as relname
504
- FROM pg_class t
505
- JOIN pg_attribute attr ON (t.oid = attrelid)
506
- JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum)
507
- JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
508
- WHERE t.oid = '#{quote_table_name(table)}'::regclass
509
- AND cons.contype = 'p'
510
- AND pg_get_expr(def.adbin, def.adrelid) ~* 'nextval|uuid_generate'
511
- end_sql
336
+ def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
337
+ val = super
338
+ if !use_insert_returning? && pk
339
+ unless sequence_name
340
+ table_ref = extract_table_ref_from_insert_sql(sql)
341
+ sequence_name = default_sequence_name(table_ref, pk)
342
+ return val unless sequence_name
343
+ end
344
+ last_insert_id_result(sequence_name)
345
+ else
346
+ val
512
347
  end
513
-
514
- [ result['attname'], result['relname'] ]
515
- rescue
516
- nil
517
348
  end
518
349
 
519
- def primary_key(table)
520
- result = select(<<-end_sql, 'SCHEMA').first
521
- SELECT attr.attname
522
- FROM pg_attribute attr
523
- INNER JOIN pg_constraint cons ON attr.attrelid = cons.conrelid AND attr.attnum = any(cons.conkey)
524
- WHERE cons.contype = 'p' AND cons.conrelid = '#{quote_table_name(table)}'::regclass
525
- end_sql
526
-
527
- result && result['attname']
528
- # pk_and_sequence = pk_and_sequence_for(table)
529
- # pk_and_sequence && pk_and_sequence.first
350
+ def explain(arel, binds = [])
351
+ sql = "EXPLAIN #{to_sql(arel, binds)}"
352
+ ActiveRecord::ConnectionAdapters::PostgreSQL::ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', binds))
530
353
  end
531
354
 
532
- def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
533
- unless pk
534
- # Extract the table from the insert sql. Yuck.
535
- table_ref = extract_table_ref_from_insert_sql(sql)
536
- pk = primary_key(table_ref) if table_ref
537
- end
538
-
539
- if pk && use_insert_returning? # && id_value.nil?
540
- select_value("#{to_sql(sql, binds)} RETURNING #{quote_column_name(pk)}")
355
+ # Take an id from the result of an INSERT query.
356
+ # @return [Integer, NilClass]
357
+ def last_inserted_id(result)
358
+ if result.is_a?(Hash) || result.is_a?(ActiveRecord::Result)
359
+ result.first.first[1] # .first = { "id"=>1 } .first = [ "id", 1 ]
541
360
  else
542
- execute(sql, name, binds) # super
543
- unless id_value
544
- table_ref ||= extract_table_ref_from_insert_sql(sql)
545
- # If neither PK nor sequence name is given, look them up.
546
- if table_ref && ! ( pk ||= primary_key(table_ref) ) && ! sequence_name
547
- pk, sequence_name = pk_and_sequence_for(table_ref)
548
- end
549
- # If a PK is given, fallback to default sequence name.
550
- # Don't fetch last insert id for a table without a PK.
551
- if pk && sequence_name ||= default_sequence_name(table_ref, pk)
552
- id_value = last_insert_id(table_ref, sequence_name)
553
- end
554
- end
555
- id_value
361
+ result
556
362
  end
557
363
  end
558
364
 
559
- # @override
560
- def sql_for_insert(sql, pk, id_value, sequence_name, binds)
561
- unless pk
365
+ def sql_for_insert(sql, pk, id_value, sequence_name, binds) # :nodoc:
366
+ if pk.nil?
562
367
  # Extract the table from the insert sql. Yuck.
563
368
  table_ref = extract_table_ref_from_insert_sql(sql)
564
369
  pk = primary_key(table_ref) if table_ref
565
370
  end
566
371
 
372
+ pk = nil if pk.is_a?(Array)
373
+
567
374
  if pk && use_insert_returning?
568
375
  sql = "#{sql} RETURNING #{quote_column_name(pk)}"
569
376
  end
570
377
 
571
- [ sql, binds ]
572
- end
573
-
574
- # @override due RETURNING clause
575
- def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
576
- # NOTE: 3.2 does not pass the PK on #insert (passed only into #sql_for_insert) :
577
- # sql, binds = sql_for_insert(to_sql(arel, binds), pk, id_value, sequence_name, binds)
578
- # 3.2 :
579
- # value = exec_insert(sql, name, binds)
580
- # 4.x :
581
- # value = exec_insert(sql, name, binds, pk, sequence_name)
582
- if use_insert_returning? && ( pk || (sql.is_a?(String) && sql =~ /RETURNING "?\S+"?$/) )
583
- exec_query(sql, name, binds) # due RETURNING clause returns a result set
584
- else
585
- result = super
586
- if pk
587
- unless sequence_name
588
- table_ref = extract_table_ref_from_insert_sql(sql)
589
- sequence_name = default_sequence_name(table_ref, pk)
590
- return result unless sequence_name
591
- end
592
- last_insert_id_result(sequence_name)
593
- else
594
- result
595
- end
596
- end
378
+ super
597
379
  end
598
380
 
599
381
  # @note Only for "better" AR 4.0 compatibility.
@@ -601,103 +383,29 @@ module ArJdbc
601
383
  def query(sql, name = nil)
602
384
  log(sql, name) do
603
385
  result = []
604
- @connection.execute_query_raw(sql, nil) do |*values|
605
- result << values
386
+ @connection.execute_query_raw(sql, []) do |*values|
387
+ # We need to use #deep_dup here because it appears that
388
+ # the java method is reusing an object in some cases
389
+ # which makes all of the entries in the "result"
390
+ # array end up with the same values as the last row
391
+ result << values.deep_dup
606
392
  end
607
393
  result
608
394
  end
609
395
  end
610
396
 
611
- # Returns an array of schema names.
612
- def schema_names
613
- select_values(
614
- "SELECT nspname FROM pg_namespace" <<
615
- " WHERE nspname !~ '^pg_.*' AND nspname NOT IN ('information_schema')" <<
616
- " ORDER by nspname;",
617
- 'SCHEMA')
618
- end
619
-
620
- # Returns true if schema exists.
621
- def schema_exists?(name)
622
- select_value("SELECT COUNT(*) FROM pg_namespace WHERE nspname = '#{name}'", 'SCHEMA').to_i > 0
623
- end
624
-
625
- # Returns the current schema name.
626
- def current_schema
627
- select_value('SELECT current_schema', 'SCHEMA')
628
- end
629
-
630
- # current database name
631
- def current_database
632
- select_value('SELECT current_database()', 'SCHEMA')
633
- end
634
-
635
- # Returns the current database encoding format.
636
- def encoding
637
- select_value(
638
- "SELECT pg_encoding_to_char(pg_database.encoding)" <<
639
- " FROM pg_database" <<
640
- " WHERE pg_database.datname LIKE '#{current_database}'",
641
- 'SCHEMA')
642
- end
643
-
644
- # Returns the current database collation.
645
- def collation
646
- select_value(
647
- "SELECT pg_database.datcollate" <<
648
- " FROM pg_database" <<
649
- " WHERE pg_database.datname LIKE '#{current_database}'",
650
- 'SCHEMA')
651
- end
652
-
653
- # Returns the current database ctype.
654
- def ctype
655
- select_value(
656
- "SELECT pg_database.datctype FROM pg_database WHERE pg_database.datname LIKE '#{current_database}'",
657
- 'SCHEMA')
658
- end
659
-
660
- # Returns the active schema search path.
661
- def schema_search_path
662
- @schema_search_path ||= select_value('SHOW search_path', 'SCHEMA')
663
- end
664
-
665
- # Sets the schema search path to a string of comma-separated schema names.
666
- # Names beginning with $ have to be quoted (e.g. $user => '$user').
667
- # See: http://www.postgresql.org/docs/current/static/ddl-schemas.html
668
- #
669
- # This should be not be called manually but set in database.yml.
670
- def schema_search_path=(schema_csv)
671
- if schema_csv
672
- execute "SET search_path TO #{schema_csv}"
673
- @schema_search_path = schema_csv
674
- end
675
- end
676
-
677
- # Take an id from the result of an INSERT query.
678
- # @return [Integer, NilClass]
679
- def last_inserted_id(result)
680
- return nil if result.nil?
681
- return result if result.is_a? Integer
682
- # <ActiveRecord::Result @hash_rows=nil, @columns=["id"], @rows=[[3]]>
683
- # but it will work with [{ 'id' => 1 }] Hash wrapped results as well
684
- result.first.first[1] # .first = { "id"=>1 } .first = [ "id", 1 ]
685
- end
686
-
687
- def last_insert_id(table, sequence_name = nil)
688
- sequence_name = table if sequence_name.nil? # AR-4.0 1 argument
689
- last_insert_id_result(sequence_name)
397
+ def reset!
398
+ clear_cache!
399
+ reset_transaction
400
+ @connection.rollback # Have to deal with rollbacks differently than the AR adapter
401
+ @connection.execute 'DISCARD ALL'
402
+ configure_connection
690
403
  end
691
404
 
692
405
  def last_insert_id_result(sequence_name)
693
406
  select_value("SELECT currval('#{sequence_name}')", 'SQL')
694
407
  end
695
408
 
696
- def recreate_database(name, options = {})
697
- drop_database(name)
698
- create_database(name, options)
699
- end
700
-
701
409
  # Create a new PostgreSQL database. Options include <tt>:owner</tt>, <tt>:template</tt>,
702
410
  # <tt>:encoding</tt>, <tt>:collation</tt>, <tt>:ctype</tt>,
703
411
  # <tt>:tablespace</tt>, and <tt>:connection_limit</tt> (note that MySQL uses
@@ -733,56 +441,10 @@ module ArJdbc
733
441
  execute "CREATE DATABASE #{quote_table_name(name)}#{option_string}"
734
442
  end
735
443
 
736
- def drop_database(name)
737
- execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
738
- end
739
-
740
- # Creates a schema for the given schema name.
741
- def create_schema(schema_name, pg_username = nil)
742
- if pg_username.nil? # AR 4.0 compatibility - accepts only single argument
743
- execute "CREATE SCHEMA #{schema_name}"
744
- else
745
- execute("CREATE SCHEMA \"#{schema_name}\" AUTHORIZATION \"#{pg_username}\"")
746
- end
747
- end
748
-
749
- # Drops the schema for the given schema name.
750
- def drop_schema schema_name
751
- execute "DROP SCHEMA #{schema_name} CASCADE"
752
- end
753
-
754
444
  def all_schemas
755
445
  select('SELECT nspname FROM pg_namespace').map { |row| row["nspname"] }
756
446
  end
757
447
 
758
- # @deprecated no longer used - handled with (AR built-in) Rake tasks
759
- def structure_dump
760
- database = @config[:database]
761
- if database.nil?
762
- if @config[:url] =~ /\/([^\/]*)$/
763
- database = $1
764
- else
765
- raise "Could not figure out what database this url is for #{@config["url"]}"
766
- end
767
- end
768
-
769
- ENV['PGHOST'] = @config[:host] if @config[:host]
770
- ENV['PGPORT'] = @config[:port].to_s if @config[:port]
771
- ENV['PGPASSWORD'] = @config[:password].to_s if @config[:password]
772
- search_path = "--schema=#{@config[:schema_search_path]}" if @config[:schema_search_path]
773
-
774
- @connection.connection.close
775
- begin
776
- definition = `pg_dump -i -U "#{@config[:username]}" -s -x -O #{search_path} #{database}`
777
- raise "Error dumping database" if $?.exitstatus == 1
778
-
779
- # need to patch away any references to SQL_ASCII as it breaks the JDBC driver
780
- definition.gsub(/SQL_ASCII/, 'UNICODE')
781
- ensure
782
- reconnect!
783
- end
784
- end
785
-
786
448
  # Returns the current client message level.
787
449
  def client_min_messages
788
450
  return nil if redshift? # not supported on Redshift
@@ -797,42 +459,6 @@ module ArJdbc
797
459
  execute("SET client_min_messages TO '#{level}'", 'SCHEMA')
798
460
  end
799
461
 
800
- # Gets the maximum number columns postgres has, default 32
801
- def multi_column_index_limit
802
- defined?(@multi_column_index_limit) && @multi_column_index_limit || 32
803
- end
804
-
805
- # Sets the maximum number columns postgres has, default 32
806
- def multi_column_index_limit=(limit)
807
- @multi_column_index_limit = limit
808
- end
809
-
810
- # @override
811
- def distinct(columns, orders)
812
- "DISTINCT #{columns_for_distinct(columns, orders)}"
813
- end
814
-
815
- # PostgreSQL requires the ORDER BY columns in the select list for distinct
816
- # queries, and requires that the ORDER BY include the distinct column.
817
- # @override Since AR 4.0 (on 4.1 {#distinct} is gone and won't be called).
818
- def columns_for_distinct(columns, orders)
819
- if orders.is_a?(String)
820
- orders = orders.split(','); orders.each(&:strip!)
821
- end
822
-
823
- order_columns = orders.reject(&:blank?).map! do |column|
824
- column = column.is_a?(String) ? column.dup : column.to_sql # AREL node
825
- column.gsub!(/\s+(?:ASC|DESC)\s*/i, '') # remove any ASC/DESC modifiers
826
- column.gsub!(/\s*NULLS\s+(?:FIRST|LAST)?\s*/i, '')
827
- column
828
- end
829
- order_columns.reject!(&:empty?)
830
- i = -1; order_columns.map! { |column| "#{column} AS alias_#{i += 1}" }
831
-
832
- columns = [ columns ]; columns.flatten!
833
- columns.push( *order_columns ).join(', ')
834
- end
835
-
836
462
  # ORDER BY clause for the passed order option.
837
463
  #
838
464
  # PostgreSQL does not allow arbitrary ordering when using DISTINCT ON,
@@ -848,94 +474,6 @@ module ArJdbc
848
474
  sql.replace "SELECT * FROM (#{sql}) AS id_list ORDER BY #{order}"
849
475
  end
850
476
 
851
- # @return [String]
852
- # @override
853
- def quote(value, column = nil)
854
- return super unless column && column.type
855
- return value if sql_literal?(value)
856
-
857
- case value
858
- when Float
859
- if value.infinite? && ( column.type == :datetime || column.type == :timestamp )
860
- "'#{value.to_s.downcase}'"
861
- elsif value.infinite? || value.nan?
862
- "'#{value.to_s}'"
863
- else super
864
- end
865
- when Numeric
866
- if column.respond_to?(:sql_type) && column.sql_type == 'money'
867
- "'#{value}'"
868
- elsif column.type == :string || column.type == :text
869
- "'#{value}'"
870
- else super
871
- end
872
- when String
873
- return "E'#{escape_bytea(value)}'::bytea" if column.type == :binary
874
- return "xml '#{quote_string(value)}'" if column.type == :xml
875
- sql_type = column.respond_to?(:sql_type) && column.sql_type
876
- sql_type && sql_type[0, 3] == 'bit' ? quote_bit(value) : super
877
- when Array
878
- if AR40 && column.array? # will be always falsy in AR < 4.0
879
- "'#{jdbc_column_class.array_to_string(value, column, self).gsub(/'/, "''")}'"
880
- elsif column.type == :json # only in AR-4.0
881
- super(jdbc_column_class.json_to_string(value), column)
882
- elsif column.type == :jsonb # only in AR-4.0
883
- super(jdbc_column_class.json_to_string(value), column)
884
- elsif column.type == :point # only in AR-4.0
885
- super(jdbc_column_class.point_to_string(value), column)
886
- else super
887
- end
888
- when Hash
889
- if column.type == :hstore # only in AR-4.0
890
- super(jdbc_column_class.hstore_to_string(value), column)
891
- elsif column.type == :json # only in AR-4.0
892
- super(jdbc_column_class.json_to_string(value), column)
893
- elsif column.type == :jsonb # only in AR-4.0
894
- super(jdbc_column_class.json_to_string(value), column)
895
- else super
896
- end
897
- when Range
898
- sql_type = column.respond_to?(:sql_type) && column.sql_type
899
- if sql_type && sql_type[-5, 5] == 'range' && AR40
900
- escaped = quote_string(jdbc_column_class.range_to_string(value))
901
- "'#{escaped}'::#{sql_type}"
902
- else super
903
- end
904
- when IPAddr
905
- if column.type == :inet || column.type == :cidr # only in AR-4.0
906
- super(jdbc_column_class.cidr_to_string(value), column)
907
- else super
908
- end
909
- else
910
- super
911
- end
912
- end unless AR42
913
-
914
- # @private
915
- def _quote(value)
916
- case value
917
- when Type::Binary::Data
918
- "E'#{escape_bytea(value.to_s)}'"
919
- when OID::Xml::Data
920
- "xml '#{quote_string(value.to_s)}'"
921
- when OID::Bit::Data
922
- if value.binary?
923
- "B'#{value}'"
924
- elsif value.hex?
925
- "X'#{value}'"
926
- end
927
- when Float
928
- if value.infinite? || value.nan?
929
- "'#{value}'"
930
- else
931
- super
932
- end
933
- else
934
- super
935
- end
936
- end if AR42
937
- private :_quote if AR42
938
-
939
477
  # Quotes a string, escaping any ' (single quote) and \ (backslash) chars.
940
478
  # @return [String]
941
479
  # @override
@@ -947,24 +485,6 @@ module ArJdbc
947
485
  quoted
948
486
  end
949
487
 
950
- # @return [String]
951
- def quote_bit(value)
952
- case value
953
- # NOTE: as reported with #60 this is not quite "right" :
954
- # "0103" will be treated as hexadecimal string
955
- # "0102" will be treated as hexadecimal string
956
- # "0101" will be treated as binary string
957
- # "0100" will be treated as binary string
958
- # ... but is kept due Rails compatibility
959
- when /\A[01]*\Z/ then "B'#{value}'" # Bit-string notation
960
- when /\A[0-9A-F]*\Z/i then "X'#{value}'" # Hexadecimal notation
961
- end
962
- end
963
-
964
- def quote_bit(value)
965
- "B'#{value}'"
966
- end if AR40
967
-
968
488
  def escape_bytea(string)
969
489
  return unless string
970
490
  if supports_hex_escaped_bytea?
@@ -988,25 +508,11 @@ module ArJdbc
988
508
  end
989
509
  end
990
510
 
991
- # @override
992
- def quote_table_name_for_assignment(table, attr)
993
- quote_column_name(attr)
994
- end if AR40
995
-
996
511
  # @override
997
512
  def quote_column_name(name)
998
513
  %("#{name.to_s.gsub("\"", "\"\"")}")
999
514
  end
1000
-
1001
- # @private
1002
- def quote_default_value(value, column)
1003
- # Do not quote function default values for UUID columns
1004
- if column.type == :uuid && value =~ /\(\)/
1005
- value
1006
- else
1007
- quote(value, column)
1008
- end
1009
- end
515
+ alias_method :quote_schema_name, :quote_column_name
1010
516
 
1011
517
  # Quote date/time values for use in SQL input.
1012
518
  # Includes microseconds if the value is a Time responding to `usec`.
@@ -1020,62 +526,6 @@ module ArJdbc
1020
526
  result
1021
527
  end if ::ActiveRecord::VERSION::MAJOR >= 3
1022
528
 
1023
- # @override
1024
- def supports_disable_referential_integrity?
1025
- true
1026
- end
1027
-
1028
- def disable_referential_integrity
1029
- if supports_disable_referential_integrity?
1030
- begin
1031
- execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER ALL" }.join(";"))
1032
- rescue
1033
- execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER USER" }.join(";"))
1034
- end
1035
- end
1036
- yield
1037
- ensure
1038
- if supports_disable_referential_integrity?
1039
- begin
1040
- execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} ENABLE TRIGGER ALL" }.join(";"))
1041
- rescue
1042
- execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} ENABLE TRIGGER USER" }.join(";"))
1043
- end
1044
- end
1045
- end
1046
-
1047
- def rename_table(table_name, new_name)
1048
- execute "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_table_name(new_name)}"
1049
- pk, seq = pk_and_sequence_for(new_name)
1050
- if seq == "#{table_name}_#{pk}_seq"
1051
- new_seq = "#{new_name}_#{pk}_seq"
1052
- idx = "#{table_name}_pkey"
1053
- new_idx = "#{new_name}_pkey"
1054
- execute "ALTER TABLE #{quote_table_name(seq)} RENAME TO #{quote_table_name(new_seq)}"
1055
- execute "ALTER INDEX #{quote_table_name(idx)} RENAME TO #{quote_table_name(new_idx)}"
1056
- end
1057
- rename_table_indexes(table_name, new_name) if respond_to?(:rename_table_indexes) # AR-4.0 SchemaStatements
1058
- end
1059
-
1060
- # Adds a new column to the named table.
1061
- # See TableDefinition#column for details of the options you can use.
1062
- def add_column(table_name, column_name, type, options = {})
1063
- default = options[:default]
1064
- notnull = options[:null] == false
1065
-
1066
- sql_type = type_to_sql(type, options[:limit], options[:precision], options[:scale])
1067
- sql_type << "[]" if options[:array]
1068
-
1069
- # Add the column.
1070
- execute("ALTER TABLE #{quote_table_name(table_name)} ADD COLUMN #{quote_column_name(column_name)} #{sql_type}")
1071
-
1072
- change_column_default(table_name, column_name, default) if options_include_default?(options)
1073
- change_column_null(table_name, column_name, false, default) if notnull
1074
- end if ::ActiveRecord::VERSION::MAJOR < 4
1075
-
1076
- # @private documented above
1077
- def add_column(table_name, column_name, type, options = {}); super end if AR42
1078
-
1079
529
  # Changes the column of a table.
1080
530
  def change_column(table_name, column_name, type, options = {})
1081
531
  quoted_table_name = quote_table_name(table_name)
@@ -1117,156 +567,13 @@ module ArJdbc
1117
567
  end
1118
568
  private :change_column_pg7
1119
569
 
1120
- # Changes the default value of a table column.
1121
- def change_column_default(table_name, column_name, default)
1122
- if column = column_for(table_name, column_name) # (backwards) compatible with AR 3.x - 4.x
1123
- execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} SET DEFAULT #{quote_default_value(default, column)}"
1124
- else
1125
- execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} SET DEFAULT #{quote(default)}"
1126
- end
1127
- end unless AR42 # unless const_defined? :SchemaCreation
1128
-
1129
- # @private documented above
1130
- def change_column_default(table_name, column_name, default)
1131
- return unless column = column_for(table_name, column_name)
1132
-
1133
- alter_column_query = "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} %s"
1134
- if default.nil?
1135
- # <tt>DEFAULT NULL</tt> results in the same behavior as <tt>DROP DEFAULT</tt>. However, PostgreSQL will
1136
- # cast the default to the columns type, which leaves us with a default like "default NULL::character varying".
1137
- execute alter_column_query % "DROP DEFAULT"
1138
- else
1139
- execute alter_column_query % "SET DEFAULT #{quote_default_value(default, column)}"
1140
- end
1141
- end if AR42
1142
-
1143
- # @private
1144
- def change_column_null(table_name, column_name, null, default = nil)
1145
- unless null || default.nil?
1146
- if column = column_for(table_name, column_name) # (backwards) compatible with AR 3.x - 4.x
1147
- execute "UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote_default_value(default, column)} WHERE #{quote_column_name(column_name)} IS NULL"
1148
- else
1149
- execute "UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL"
1150
- end
1151
- end
1152
- execute("ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL")
1153
- end unless AR42 # unless const_defined? :SchemaCreation
1154
-
1155
- # @private
1156
- def change_column_null(table_name, column_name, null, default = nil)
1157
- unless null || default.nil?
1158
- column = column_for(table_name, column_name)
1159
- execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote_default_value(default, column)} WHERE #{quote_column_name(column_name)} IS NULL") if column
1160
- end
1161
- execute("ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL")
1162
- end if AR42
1163
-
1164
- def rename_column(table_name, column_name, new_column_name)
1165
- execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
1166
- rename_column_indexes(table_name, column_name, new_column_name) if respond_to?(:rename_column_indexes) # AR-4.0 SchemaStatements
1167
- end # unless const_defined? :SchemaCreation
1168
-
1169
- def add_index(table_name, column_name, options = {})
1170
- index_name, index_type, index_columns, index_options, index_algorithm, index_using = add_index_options(table_name, column_name, options)
1171
- execute "CREATE #{index_type} INDEX #{index_algorithm} #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} #{index_using} (#{index_columns})#{index_options}"
1172
- end if AR40
1173
-
1174
570
  def remove_index!(table_name, index_name)
1175
571
  execute "DROP INDEX #{quote_table_name(index_name)}"
1176
572
  end
1177
573
 
1178
- def rename_index(table_name, old_name, new_name)
1179
- validate_index_length!(table_name, new_name) if respond_to?(:validate_index_length!)
1180
-
1181
- execute "ALTER INDEX #{quote_column_name(old_name)} RENAME TO #{quote_table_name(new_name)}"
1182
- end
1183
-
1184
574
  # @override
1185
575
  def supports_foreign_keys?; true end
1186
576
 
1187
- def foreign_keys(table_name)
1188
- fk_info = select_all "" <<
1189
- "SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete " <<
1190
- "FROM pg_constraint c " <<
1191
- "JOIN pg_class t1 ON c.conrelid = t1.oid " <<
1192
- "JOIN pg_class t2 ON c.confrelid = t2.oid " <<
1193
- "JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid " <<
1194
- "JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid " <<
1195
- "JOIN pg_namespace t3 ON c.connamespace = t3.oid " <<
1196
- "WHERE c.contype = 'f' " <<
1197
- " AND t1.relname = #{quote(table_name)} " <<
1198
- " AND t3.nspname = ANY (current_schemas(false)) " <<
1199
- "ORDER BY c.conname "
1200
-
1201
- fk_info.map! do |row|
1202
- options = {
1203
- :column => row['column'], :name => row['name'], :primary_key => row['primary_key']
1204
- }
1205
- options[:on_delete] = extract_foreign_key_action(row['on_delete'])
1206
- options[:on_update] = extract_foreign_key_action(row['on_update'])
1207
-
1208
- ForeignKeyDefinition.new(table_name, row['to_table'], options)
1209
- end
1210
- end if defined? ForeignKeyDefinition
1211
-
1212
- # @private
1213
- def extract_foreign_key_action(specifier)
1214
- case specifier
1215
- when 'c'; :cascade
1216
- when 'n'; :nullify
1217
- when 'r'; :restrict
1218
- end
1219
- end
1220
- private :extract_foreign_key_action
1221
-
1222
- def index_name_length
1223
- 63
1224
- end
1225
-
1226
- # Returns the list of all column definitions for a table.
1227
- def columns(table_name, name = nil)
1228
- column = jdbc_column_class
1229
- column_definitions(table_name).map! do |row|
1230
- # |name, type, default, notnull, oid, fmod|
1231
- name = row[0]; type = row[1]; default = row[2]
1232
- notnull = row[3]; oid = row[4]; fmod = row[5]
1233
- # oid = OID::TYPE_MAP.fetch(oid.to_i, fmod.to_i) { OID::Identity.new }
1234
- notnull = notnull == 't' if notnull.is_a?(String) # JDBC gets true/false
1235
- # for ID columns we get a bit of non-sense default :
1236
- # e.g. "nextval('mixed_cases_id_seq'::regclass"
1237
- if default =~ /^nextval\(.*?\:\:regclass\)$/
1238
- default = nil
1239
- elsif default =~ /^\(([-+]?[\d\.]+)\)$/ # e.g. "(-1)" for a negative default
1240
- default = $1
1241
- end
1242
-
1243
- column.new(name, default, oid, type, ! notnull, fmod, self)
1244
- end
1245
- end
1246
-
1247
- # @private documented above
1248
- def columns(table_name)
1249
- column = jdbc_column_class
1250
- # Limit, precision, and scale are all handled by the superclass.
1251
- column_definitions(table_name).map! do |row|
1252
- # |name, type, default, notnull, oid, fmod|
1253
- name = row[0]; type = row[1]; default = row[2]
1254
- notnull = row[3]; oid = row[4]; fmod = row[5]
1255
- notnull = notnull == 't' if notnull.is_a?(String) # JDBC gets true/false
1256
-
1257
- oid_type = get_oid_type(oid.to_i, fmod.to_i, name, type)
1258
- default_value = extract_value_from_default(oid, default)
1259
- default_function = extract_default_function(default_value, default)
1260
-
1261
- column.new(name, default_value, oid_type, type, ! notnull, default_function, oid, self)
1262
- end
1263
- end if AR42
1264
-
1265
- # @private only for API compatibility
1266
- def new_column(name, default, cast_type, sql_type = nil, null = true, default_function = nil)
1267
- jdbc_column_class.new(name, default, cast_type, sql_type, null, default_function)
1268
- end if AR42
1269
-
1270
577
  # @private
1271
578
  def column_for(table_name, column_name)
1272
579
  column_name = column_name.to_s
@@ -1285,139 +592,84 @@ module ArJdbc
1285
592
  # - format_type includes the column size constraint, e.g. varchar(50)
1286
593
  # - ::regclass is a function that gives the id for a table name
1287
594
  def column_definitions(table_name)
1288
- select_rows(<<-end_sql, 'SCHEMA')
595
+ rows = select_rows(<<-end_sql, 'SCHEMA')
1289
596
  SELECT a.attname, format_type(a.atttypid, a.atttypmod),
1290
- pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod
1291
- FROM pg_attribute a LEFT JOIN pg_attrdef d
1292
- ON a.attrelid = d.adrelid AND a.attnum = d.adnum
597
+ pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
598
+ (SELECT c.collname FROM pg_collation c, pg_type t
599
+ WHERE c.oid = a.attcollation AND t.oid = a.atttypid
600
+ AND a.attcollation <> t.typcollation),
601
+ col_description(a.attrelid, a.attnum) AS comment
602
+ FROM pg_attribute a
603
+ LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
1293
604
  WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass
1294
605
  AND a.attnum > 0 AND NOT a.attisdropped
1295
606
  ORDER BY a.attnum
1296
607
  end_sql
1297
- end
1298
- private :column_definitions
1299
608
 
1300
- # @private
1301
- TABLES_SQL = 'SELECT tablename FROM pg_tables WHERE schemaname = ANY (current_schemas(false))'
1302
- private_constant :TABLES_SQL rescue nil
1303
-
1304
- # @override
1305
- def tables(name = nil)
1306
- select_values(TABLES_SQL, 'SCHEMA')
1307
- end
1308
-
1309
- # @private
1310
- TABLE_EXISTS_SQL_PREFIX = 'SELECT COUNT(*) as table_count FROM pg_class c'
1311
- TABLE_EXISTS_SQL_PREFIX << ' LEFT JOIN pg_namespace n ON n.oid = c.relnamespace'
1312
- if AR42 # -- (r)elation/table, (v)iew, (m)aterialized view
1313
- TABLE_EXISTS_SQL_PREFIX << " WHERE c.relkind IN ('r','v','m')"
1314
- else
1315
- TABLE_EXISTS_SQL_PREFIX << " WHERE c.relkind IN ('r','v')"
1316
- end
1317
- TABLE_EXISTS_SQL_PREFIX << " AND c.relname = ?"
1318
- private_constant :TABLE_EXISTS_SQL_PREFIX rescue nil
1319
-
1320
- # Returns true if table exists.
1321
- # If the schema is not specified as part of +name+ then it will only find tables within
1322
- # the current schema search path (regardless of permissions to access tables in other schemas)
1323
- def table_exists?(name)
1324
- schema, table = extract_schema_and_table(name.to_s)
1325
- return false unless table
1326
-
1327
- binds = [[nil, table]]
1328
- binds << [nil, schema] if schema
1329
-
1330
- sql = "#{TABLE_EXISTS_SQL_PREFIX} AND n.nspname = #{schema ? "?" : 'ANY (current_schemas(false))'}"
1331
-
1332
- log(sql, 'SCHEMA', binds) do
1333
- @connection.execute_query_raw(sql, binds).first['table_count'] > 0
609
+ # Force the notnull attribute to a boolean
610
+ rows.each do |row|
611
+ row[3] = row[3] == 't' if row[3].is_a?(String)
1334
612
  end
1335
613
  end
1336
- alias data_source_exists? table_exists?
1337
-
1338
- # @private
1339
- DATA_SOURCES_SQL = 'SELECT c.relname FROM pg_class c'
1340
- DATA_SOURCES_SQL << ' LEFT JOIN pg_namespace n ON n.oid = c.relnamespace'
1341
- DATA_SOURCES_SQL << " WHERE c.relkind IN ('r', 'v','m')" # -- (r)elation/table, (v)iew, (m)aterialized view
1342
- DATA_SOURCES_SQL << ' AND n.nspname = ANY (current_schemas(false))'
1343
- private_constant :DATA_SOURCES_SQL rescue nil
1344
-
1345
- # @override
1346
- def data_sources
1347
- select_values(DATA_SOURCES_SQL, 'SCHEMA')
1348
- end
1349
-
1350
- def drop_table(table_name, options = {})
1351
- execute "DROP TABLE #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
1352
- end
614
+ private :column_definitions
1353
615
 
1354
616
  def truncate(table_name, name = nil)
1355
617
  execute "TRUNCATE TABLE #{quote_table_name(table_name)}", name
1356
618
  end
1357
619
 
1358
- def index_name_exists?(table_name, index_name, default)
1359
- exec_query(<<-SQL, 'SCHEMA').rows.first[0].to_i > 0
1360
- SELECT COUNT(*)
1361
- FROM pg_class t
1362
- INNER JOIN pg_index d ON t.oid = d.indrelid
1363
- INNER JOIN pg_class i ON d.indexrelid = i.oid
1364
- WHERE i.relkind = 'i'
1365
- AND i.relname = '#{index_name}'
1366
- AND t.relname = '#{table_name}'
1367
- AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = ANY (current_schemas(false)) )
1368
- SQL
1369
- end if AR42
1370
-
1371
620
  # Returns an array of indexes for the given table.
1372
621
  def indexes(table_name, name = nil)
1373
- # NOTE: maybe it's better to leave things of to the JDBC API ?!
1374
- result = select_rows(<<-SQL, 'SCHEMA')
1375
- SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid
1376
- FROM pg_class t
1377
- INNER JOIN pg_index d ON t.oid = d.indrelid
1378
- INNER JOIN pg_class i ON d.indexrelid = i.oid
1379
- WHERE i.relkind = 'i'
1380
- AND d.indisprimary = 'f'
1381
- AND t.relname = '#{table_name}'
1382
- AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = ANY (current_schemas(false)) )
1383
- ORDER BY i.relname
622
+ # FIXME: AR version => table = Utils.extract_schema_qualified_name(table_name.to_s)
623
+ schema, table = extract_schema_and_table(table_name.to_s)
624
+
625
+ result = query(<<-SQL, 'SCHEMA')
626
+ SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid,
627
+ pg_catalog.obj_description(i.oid, 'pg_class') AS comment,
628
+ (SELECT COUNT(*) FROM pg_opclass o
629
+ JOIN (SELECT unnest(string_to_array(d.indclass::text, ' '))::int oid) c
630
+ ON o.oid = c.oid WHERE o.opcdefault = 'f')
631
+ FROM pg_class t
632
+ INNER JOIN pg_index d ON t.oid = d.indrelid
633
+ INNER JOIN pg_class i ON d.indexrelid = i.oid
634
+ LEFT JOIN pg_namespace n ON n.oid = i.relnamespace
635
+ WHERE i.relkind = 'i'
636
+ AND d.indisprimary = 'f'
637
+ AND t.relname = '#{table}'
638
+ AND n.nspname = #{schema ? "'#{schema}'" : 'ANY (current_schemas(false))'}
639
+ ORDER BY i.relname
1384
640
  SQL
1385
641
 
1386
- result.map! do |row|
642
+ result.map do |row|
1387
643
  index_name = row[0]
644
+ # FIXME: These values [1,2] are returned in a different format than AR expects, maybe we could update it on the Java side to be more accurate
1388
645
  unique = row[1].is_a?(String) ? row[1] == 't' : row[1] # JDBC gets us a boolean
1389
646
  indkey = row[2].is_a?(Java::OrgPostgresqlUtil::PGobject) ? row[2].value : row[2]
1390
- indkey = indkey.split(" ")
647
+ indkey = indkey.split(" ").map(&:to_i)
1391
648
  inddef = row[3]
1392
649
  oid = row[4]
650
+ comment = row[5]
651
+ opclass = row[6]
1393
652
 
1394
- columns = select_rows(<<-SQL, "SCHEMA")
1395
- SELECT a.attnum, a.attname
1396
- FROM pg_attribute a
1397
- WHERE a.attrelid = #{oid}
1398
- AND a.attnum IN (#{indkey.join(",")})
1399
- SQL
653
+ using, expressions, where = inddef.scan(/ USING (\w+?) \((.+?)\)(?: WHERE (.+))?\z/).flatten
1400
654
 
1401
- columns = Hash[ columns.each { |column| column[0] = column[0].to_s } ]
1402
- column_names = columns.values_at(*indkey).compact
655
+ if indkey.include?(0) || opclass > 0
656
+ columns = expressions
657
+ else
658
+ columns = Hash[query(<<-SQL.strip_heredoc, "SCHEMA")].values_at(*indkey).compact
659
+ SELECT a.attnum, a.attname
660
+ FROM pg_attribute a
661
+ WHERE a.attrelid = #{oid}
662
+ AND a.attnum IN (#{indkey.join(",")})
663
+ SQL
1403
664
 
1404
- unless column_names.empty?
1405
665
  # add info on sort order for columns (only desc order is explicitly specified, asc is the default)
1406
- desc_order_columns = inddef.scan(/(\w+) DESC/).flatten
1407
- orders = desc_order_columns.any? ? Hash[ desc_order_columns.map { |column| [column, :desc] } ] : {}
1408
-
1409
- if ::ActiveRecord::VERSION::MAJOR > 3 # AR4 supports `where` and `using` index options
1410
- where = inddef.scan(/WHERE (.+)$/).flatten[0]
1411
- using = inddef.scan(/USING (.+?) /).flatten[0].to_sym
1412
-
1413
- IndexDefinition.new(table_name, index_name, unique, column_names, [], orders, where, nil, using)
1414
- else
1415
- new_index_definition(table_name, index_name, unique, column_names, [], orders)
1416
- end
666
+ orders = Hash[
667
+ expressions.scan(/(\w+) DESC/).flatten.map { |order_column| [order_column, :desc] }
668
+ ]
1417
669
  end
1418
- end
1419
- result.compact!
1420
- result
670
+
671
+ IndexDefinition.new(table_name, index_name, unique, columns, [], orders, where, nil, using.to_sym, comment.presence)
672
+ end.compact
1421
673
  end
1422
674
 
1423
675
  # @private
@@ -1428,16 +680,39 @@ module ArJdbc
1428
680
  when 'average' then 'avg'
1429
681
  else operation.downcase
1430
682
  end
1431
- end if AR42
683
+ end
1432
684
 
1433
685
  private
1434
686
 
687
+ # Pulled from ActiveRecord's Postgres adapter and modified to use execute
688
+ def can_perform_case_insensitive_comparison_for?(column)
689
+ @case_insensitive_cache ||= {}
690
+ @case_insensitive_cache[column.sql_type] ||= begin
691
+ sql = <<-end_sql
692
+ SELECT exists(
693
+ SELECT * FROM pg_proc
694
+ WHERE proname = 'lower'
695
+ AND proargtypes = ARRAY[#{quote column.sql_type}::regtype]::oidvector
696
+ ) OR exists(
697
+ SELECT * FROM pg_proc
698
+ INNER JOIN pg_cast
699
+ ON ARRAY[casttarget]::oidvector = proargtypes
700
+ WHERE proname = 'lower'
701
+ AND castsource = #{quote column.sql_type}::regtype
702
+ )
703
+ end_sql
704
+ select_rows(sql, 'SCHEMA').first.first == 't'
705
+ end
706
+ end
707
+
1435
708
  def translate_exception(exception, message)
1436
709
  case exception.message
1437
710
  when /duplicate key value violates unique constraint/
1438
- ::ActiveRecord::RecordNotUnique.new(message, exception)
711
+ ::ActiveRecord::RecordNotUnique.new(message)
1439
712
  when /violates foreign key constraint/
1440
- ::ActiveRecord::InvalidForeignKey.new(message, exception)
713
+ ::ActiveRecord::InvalidForeignKey.new(message)
714
+ when /value too long/
715
+ ::ActiveRecord::ValueTooLong.new(message)
1441
716
  else
1442
717
  super
1443
718
  end
@@ -1477,30 +752,39 @@ require 'arjdbc/util/quoted_cache'
1477
752
 
1478
753
  module ActiveRecord::ConnectionAdapters
1479
754
 
1480
- remove_const(:PostgreSQLColumn) if const_defined?(:PostgreSQLColumn)
1481
-
1482
- class PostgreSQLColumn < JdbcColumn
1483
- include ::ArJdbc::PostgreSQL::Column
1484
- end
1485
-
1486
755
  # NOTE: seems needed on 4.x due loading of '.../postgresql/oid' which
1487
756
  # assumes: class PostgreSQLAdapter < AbstractAdapter
1488
757
  remove_const(:PostgreSQLAdapter) if const_defined?(:PostgreSQLAdapter)
1489
758
 
1490
- class PostgreSQLAdapter < JdbcAdapter
1491
- include ::ArJdbc::PostgreSQL
1492
- include ::ArJdbc::PostgreSQL::ExplainSupport
759
+ class PostgreSQLAdapter < AbstractAdapter
760
+
761
+ # Try to use as much of the built in postgres logic as possible
762
+ # maybe someday we can extend the actual adapter
763
+ include ActiveRecord::ConnectionAdapters::PostgreSQL::ColumnDumper
764
+ include ActiveRecord::ConnectionAdapters::PostgreSQL::ReferentialIntegrity
765
+ include ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaStatements
766
+ include ActiveRecord::ConnectionAdapters::PostgreSQL::Quoting
767
+
768
+ include ArJdbc::Abstract::Core
769
+ include ArJdbc::Abstract::ConnectionManagement
770
+ include ArJdbc::Abstract::DatabaseStatements
771
+ include ArJdbc::Abstract::StatementCache
772
+ include ArJdbc::Abstract::TransactionSupport
773
+ include ArJdbc::PostgreSQL
1493
774
 
1494
- require 'arjdbc/postgresql/oid_types' if ::ArJdbc::AR40
1495
- include ::ArJdbc::PostgreSQL::OIDTypes if ::ArJdbc::PostgreSQL.const_defined?(:OIDTypes)
775
+ require 'arjdbc/postgresql/oid_types'
776
+ include ::ArJdbc::PostgreSQL::OIDTypes
1496
777
 
1497
- load 'arjdbc/postgresql/_bc_time_cast_patch.rb' if ::ArJdbc::AR42
778
+ load 'arjdbc/postgresql/_bc_time_cast_patch.rb'
1498
779
 
1499
- include ::ArJdbc::PostgreSQL::ColumnHelpers if ::ArJdbc::AR42
780
+ include ::ArJdbc::PostgreSQL::ColumnHelpers
1500
781
 
1501
782
  include ::ArJdbc::Util::QuotedCache
1502
783
 
1503
- def initialize(*args)
784
+ # AR expects OID to be available on the adapter
785
+ OID = ActiveRecord::ConnectionAdapters::PostgreSQL::OID
786
+
787
+ def initialize(connection, logger = nil, config = {})
1504
788
  # @local_tz is initialized as nil to avoid warnings when connect tries to use it
1505
789
  @local_tz = nil
1506
790
 
@@ -1508,7 +792,7 @@ module ActiveRecord::ConnectionAdapters
1508
792
 
1509
793
  @table_alias_length = nil
1510
794
 
1511
- initialize_type_map(@type_map = Type::HashLookupTypeMap.new) if ::ArJdbc::AR42
795
+ initialize_type_map(@type_map = Type::HashLookupTypeMap.new)
1512
796
 
1513
797
  @use_insert_returning = @config.key?(:insert_returning) ?
1514
798
  self.class.type_cast_config_to_boolean(@config[:insert_returning]) : nil
@@ -1518,34 +802,50 @@ module ActiveRecord::ConnectionAdapters
1518
802
  Arel::Visitors::PostgreSQL.new(self)
1519
803
  end
1520
804
 
1521
- if ::ArJdbc::AR42
1522
- require 'active_record/connection_adapters/postgresql/schema_definitions'
1523
- else
1524
- require 'arjdbc/postgresql/base/schema_definitions'
1525
- end
805
+ require 'active_record/connection_adapters/postgresql/schema_definitions'
1526
806
 
1527
807
  ColumnDefinition = ActiveRecord::ConnectionAdapters::PostgreSQL::ColumnDefinition
1528
-
1529
808
  ColumnMethods = ActiveRecord::ConnectionAdapters::PostgreSQL::ColumnMethods
1530
809
  TableDefinition = ActiveRecord::ConnectionAdapters::PostgreSQL::TableDefinition
810
+ Table = ActiveRecord::ConnectionAdapters::PostgreSQL::Table
1531
811
 
1532
- def table_definition(*args)
1533
- new_table_definition(TableDefinition, *args)
812
+ def create_table_definition(*args) # :nodoc:
813
+ TableDefinition.new(*args)
1534
814
  end
1535
815
 
1536
- Table = ActiveRecord::ConnectionAdapters::PostgreSQL::Table
816
+ def exec_query(sql, name = nil, binds = [], prepare: false)
817
+ super
818
+ rescue ActiveRecord::StatementInvalid => e
819
+ raise unless e.cause.message.include?('cached plan must not change result type'.freeze)
820
+
821
+ if open_transactions > 0
822
+ # In a transaction, have to fail it - See AR code for details
823
+ raise ActiveRecord::PreparedStatementCacheExpired.new(e.cause.message)
824
+ else
825
+ # Not in a transaction, clear the prepared statement and try again
826
+ delete_cached_statement(sql)
827
+ retry
828
+ end
829
+ end
830
+
831
+ def schema_creation # :nodoc:
832
+ PostgreSQL::SchemaCreation.new self
833
+ end
1537
834
 
1538
835
  def update_table_definition(table_name, base)
1539
836
  Table.new(table_name, base)
1540
- end if ::ActiveRecord::VERSION::MAJOR > 3
837
+ end
1541
838
 
1542
839
  def jdbc_connection_class(spec)
1543
840
  ::ArJdbc::PostgreSQL.jdbc_connection_class
1544
841
  end
1545
842
 
1546
- if ::ActiveRecord::VERSION::MAJOR < 4 # Rails 3.x compatibility
1547
- PostgreSQLJdbcConnection.raw_array_type = true if PostgreSQLJdbcConnection.raw_array_type? == nil
1548
- PostgreSQLJdbcConnection.raw_hstore_type = true if PostgreSQLJdbcConnection.raw_hstore_type? == nil
843
+ private
844
+
845
+ # Prepared statements aren't schema aware so we need to make sure we
846
+ # store different PreparedStatement objects for different schemas
847
+ def cached_statement_key(sql)
848
+ "#{schema_search_path}-#{sql}"
1549
849
  end
1550
850
 
1551
851
  end