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.
- data/.gitignore +1 -0
- data/.travis.yml +5 -1
- data/Appraisals +5 -5
- data/Gemfile +9 -1
- data/Gemfile.lock +44 -10
- data/History.txt +126 -2
- data/README.md +246 -0
- data/Rakefile +34 -25
- data/activerecord-jdbc-adapter.gemspec +1 -1
- data/gemfiles/rails23.gemfile +5 -3
- data/gemfiles/rails23.gemfile.lock +26 -18
- data/gemfiles/rails30.gemfile +4 -2
- data/gemfiles/rails30.gemfile.lock +16 -8
- data/gemfiles/rails31.gemfile +4 -2
- data/gemfiles/rails31.gemfile.lock +16 -9
- data/gemfiles/rails32.gemfile +4 -2
- data/gemfiles/rails32.gemfile.lock +15 -8
- data/lib/active_record/connection_adapters/db2_adapter.rb +1 -0
- data/lib/arel/visitors/sql_server.rb +3 -0
- data/lib/arjdbc.rb +3 -5
- data/lib/arjdbc/db2.rb +1 -0
- data/lib/arjdbc/db2/adapter.rb +302 -196
- data/lib/arjdbc/db2/connection_methods.rb +18 -0
- data/lib/arjdbc/derby/active_record_patch.rb +12 -0
- data/lib/arjdbc/derby/adapter.rb +180 -158
- data/lib/arjdbc/derby/connection_methods.rb +5 -1
- data/lib/arjdbc/firebird/adapter.rb +27 -19
- data/lib/arjdbc/h2/adapter.rb +162 -7
- data/lib/arjdbc/h2/connection_methods.rb +5 -1
- data/lib/arjdbc/hsqldb.rb +1 -1
- data/lib/arjdbc/hsqldb/adapter.rb +96 -61
- data/lib/arjdbc/hsqldb/connection_methods.rb +5 -1
- data/lib/arjdbc/hsqldb/explain_support.rb +35 -0
- data/lib/arjdbc/informix/adapter.rb +56 -55
- data/lib/arjdbc/jdbc/adapter.rb +173 -86
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/column.rb +28 -23
- data/lib/arjdbc/jdbc/connection.rb +10 -6
- data/lib/arjdbc/jdbc/driver.rb +13 -5
- data/lib/arjdbc/jdbc/serialized_attributes_helper.rb +21 -0
- data/lib/arjdbc/mssql.rb +1 -1
- data/lib/arjdbc/mssql/adapter.rb +51 -53
- data/lib/arjdbc/mssql/connection_methods.rb +8 -1
- data/lib/arjdbc/mysql.rb +1 -1
- data/lib/arjdbc/mysql/adapter.rb +186 -150
- data/lib/arjdbc/mysql/connection_methods.rb +9 -9
- data/lib/arjdbc/mysql/explain_support.rb +85 -0
- data/lib/arjdbc/oracle.rb +1 -1
- data/lib/arjdbc/oracle/adapter.rb +232 -125
- data/lib/arjdbc/oracle/connection_methods.rb +2 -2
- data/lib/arjdbc/postgresql.rb +1 -1
- data/lib/arjdbc/postgresql/adapter.rb +134 -86
- data/lib/arjdbc/postgresql/connection_methods.rb +6 -4
- data/lib/arjdbc/postgresql/explain_support.rb +55 -0
- data/lib/arjdbc/sqlite3.rb +1 -1
- data/lib/arjdbc/sqlite3/adapter.rb +176 -108
- data/lib/arjdbc/sqlite3/connection_methods.rb +5 -5
- data/lib/arjdbc/sqlite3/explain_support.rb +32 -0
- data/lib/arjdbc/sybase/adapter.rb +7 -6
- data/lib/arjdbc/version.rb +1 -1
- data/pom.xml +1 -1
- data/rakelib/02-test.rake +9 -11
- data/rakelib/rails.rake +18 -10
- data/src/java/arjdbc/db2/DB2Module.java +70 -0
- data/src/java/arjdbc/derby/DerbyModule.java +24 -5
- data/src/java/arjdbc/hsqldb/HSQLDBModule.java +66 -0
- data/src/java/arjdbc/jdbc/AdapterJavaService.java +14 -7
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +111 -89
- data/src/java/arjdbc/mysql/MySQLModule.java +79 -70
- data/src/java/arjdbc/oracle/OracleModule.java +74 -0
- data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +5 -10
- data/src/java/arjdbc/sqlite3/SQLite3Module.java +77 -0
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +127 -0
- data/src/java/arjdbc/sqlite3/Sqlite3RubyJdbcConnection.java +25 -111
- data/src/java/arjdbc/util/QuotingUtils.java +104 -0
- data/test/abstract_db_create.rb +6 -6
- data/test/activerecord/connection_adapters/type_conversion_test.rb +2 -2
- data/test/assets/flowers.jpg +0 -0
- data/test/binary.rb +67 -0
- data/test/db/db2.rb +30 -7
- data/test/db/jdbc.rb +4 -2
- data/test/db/oracle.rb +18 -27
- data/test/db2_binary_test.rb +6 -0
- data/test/db2_serialize_test.rb +6 -0
- data/test/db2_simple_test.rb +20 -25
- data/test/db2_test.rb +71 -0
- data/test/derby_binary_test.rb +6 -0
- data/test/derby_migration_test.rb +42 -35
- data/test/derby_reset_column_information_test.rb +1 -0
- data/test/derby_row_locking_test.rb +17 -0
- data/test/derby_schema_dump_test.rb +9 -0
- data/test/derby_serialize_test.rb +6 -0
- data/test/derby_simple_test.rb +59 -17
- data/test/generic_jdbc_connection_test.rb +112 -5
- data/test/h2_binary_test.rb +6 -0
- data/test/h2_change_column_test.rb +1 -1
- data/test/h2_schema_dump_test.rb +25 -0
- data/test/h2_serialize_test.rb +6 -0
- data/test/h2_simple_test.rb +23 -9
- data/test/has_many_through.rb +18 -4
- data/test/hsqldb_binary_test.rb +6 -0
- data/test/hsqldb_schema_dump_test.rb +15 -0
- data/test/hsqldb_serialize_test.rb +6 -0
- data/test/hsqldb_simple_test.rb +1 -0
- data/test/informix_simple_test.rb +1 -1
- data/test/jdbc/db2.rb +23 -0
- data/test/jdbc/oracle.rb +23 -0
- data/test/jdbc_common.rb +3 -110
- data/test/jndi_callbacks_test.rb +0 -2
- data/test/jndi_test.rb +2 -0
- data/test/models/binary.rb +18 -0
- data/test/models/custom_pk_name.rb +1 -0
- data/test/models/data_types.rb +11 -2
- data/test/models/entry.rb +1 -1
- data/test/models/string_id.rb +2 -2
- data/test/models/thing.rb +1 -1
- data/test/models/topic.rb +32 -0
- data/test/mssql_legacy_types_test.rb +1 -1
- data/test/mssql_limit_offset_test.rb +13 -3
- data/test/mssql_serialize_test.rb +6 -0
- data/test/mysql_binary_test.rb +6 -0
- data/test/mysql_schema_dump_test.rb +220 -0
- data/test/mysql_serialize_test.rb +6 -0
- data/test/mysql_simple_test.rb +22 -2
- data/test/mysql_test.rb +93 -0
- data/test/oracle_binary_test.rb +6 -0
- data/test/oracle_limit_test.rb +2 -1
- data/test/oracle_serialize_test.rb +6 -0
- data/test/oracle_simple_test.rb +61 -0
- data/test/oracle_specific_test.rb +77 -26
- data/test/postgres_binary_test.rb +6 -0
- data/test/postgres_native_type_mapping_test.rb +12 -11
- data/test/postgres_nonseq_pkey_test.rb +1 -0
- data/test/postgres_reserved_test.rb +1 -0
- data/test/postgres_reset_column_information_test.rb +1 -0
- data/test/postgres_row_locking_test.rb +21 -0
- data/test/postgres_schema_dump_test.rb +88 -0
- data/test/postgres_schema_search_path_test.rb +1 -0
- data/test/postgres_simple_test.rb +62 -89
- data/test/postgres_table_alias_length_test.rb +1 -0
- data/test/postgres_test.rb +31 -0
- data/test/postgres_type_conversion_test.rb +16 -16
- data/test/row_locking.rb +69 -64
- data/test/schema_dump.rb +168 -0
- data/test/serialize.rb +277 -0
- data/test/simple.rb +326 -122
- data/test/sqlite3_serialize_test.rb +6 -0
- data/test/sqlite3_simple_test.rb +51 -84
- data/test/sqlite3_type_conversion_test.rb +101 -0
- data/test/test_helper.rb +224 -0
- metadata +325 -366
- data/README.rdoc +0 -214
- data/test/db/logger.rb +0 -3
- data/test/derby_multibyte_test.rb +0 -11
- data/test/mysql_info_test.rb +0 -123
data/lib/arjdbc/postgresql.rb
CHANGED
@@ -1,6 +1,4 @@
|
|
1
|
-
|
2
|
-
PostgreSQLAdapter = Class.new(AbstractAdapter) unless const_defined?(:PostgreSQLAdapter)
|
3
|
-
end
|
1
|
+
require 'arjdbc/postgresql/explain_support'
|
4
2
|
|
5
3
|
module ::ArJdbc
|
6
4
|
module PostgreSQL
|
@@ -167,29 +165,16 @@ module ::ArJdbc
|
|
167
165
|
# constants taken from postgresql_adapter in rails project
|
168
166
|
ADAPTER_NAME = 'PostgreSQL'
|
169
167
|
|
170
|
-
NATIVE_DATABASE_TYPES = {
|
171
|
-
:primary_key => "serial primary key",
|
172
|
-
:string => { :name => "character varying", :limit => 255 },
|
173
|
-
:text => { :name => "text" },
|
174
|
-
:integer => { :name => "integer" },
|
175
|
-
:float => { :name => "float" },
|
176
|
-
:decimal => { :name => "decimal" },
|
177
|
-
:datetime => { :name => "timestamp" },
|
178
|
-
:timestamp => { :name => "timestamp" },
|
179
|
-
:time => { :name => "time" },
|
180
|
-
:date => { :name => "date" },
|
181
|
-
:binary => { :name => "bytea" },
|
182
|
-
:boolean => { :name => "boolean" },
|
183
|
-
:xml => { :name => "xml" },
|
184
|
-
:tsvector => { :name => "tsvector" }
|
185
|
-
}
|
186
|
-
|
187
168
|
def adapter_name #:nodoc:
|
188
169
|
ADAPTER_NAME
|
189
170
|
end
|
190
171
|
|
191
172
|
def self.arel2_visitors(config)
|
192
|
-
{
|
173
|
+
{
|
174
|
+
'postgresql' => ::Arel::Visitors::PostgreSQL,
|
175
|
+
'jdbcpostgresql' => ::Arel::Visitors::PostgreSQL,
|
176
|
+
'pg' => ::Arel::Visitors::PostgreSQL
|
177
|
+
}
|
193
178
|
end
|
194
179
|
|
195
180
|
def postgresql_version
|
@@ -204,66 +189,94 @@ module ::ArJdbc
|
|
204
189
|
end
|
205
190
|
end
|
206
191
|
|
192
|
+
NATIVE_DATABASE_TYPES = {
|
193
|
+
:primary_key => "serial primary key",
|
194
|
+
:string => { :name => "character varying", :limit => 255 },
|
195
|
+
:text => { :name => "text" },
|
196
|
+
:integer => { :name => "integer" },
|
197
|
+
:float => { :name => "float" },
|
198
|
+
:decimal => { :name => "decimal" },
|
199
|
+
:datetime => { :name => "timestamp" },
|
200
|
+
:timestamp => { :name => "timestamp" },
|
201
|
+
:time => { :name => "time" },
|
202
|
+
:date => { :name => "date" },
|
203
|
+
:binary => { :name => "bytea" },
|
204
|
+
:boolean => { :name => "boolean" },
|
205
|
+
:xml => { :name => "xml" },
|
206
|
+
:tsvector => { :name => "tsvector" }
|
207
|
+
}
|
208
|
+
|
207
209
|
def native_database_types
|
208
210
|
NATIVE_DATABASE_TYPES
|
209
211
|
end
|
210
|
-
|
211
|
-
# Does PostgreSQL support migrations?
|
212
|
-
def supports_migrations?
|
213
|
-
true
|
214
|
-
end
|
215
|
-
|
212
|
+
|
216
213
|
# Enable standard-conforming strings if available.
|
217
214
|
def standard_conforming_strings=(enable)
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
215
|
+
client_min_messages = self.client_min_messages
|
216
|
+
begin
|
217
|
+
self.client_min_messages = 'panic'
|
218
|
+
value = enable ? "on" : "off"
|
219
|
+
execute("SET standard_conforming_strings = #{value}", 'SCHEMA')
|
220
|
+
@standard_conforming_strings = ( value == "on" )
|
221
|
+
rescue
|
222
|
+
@standard_conforming_strings = :unsupported
|
223
|
+
ensure
|
224
|
+
self.client_min_messages = client_min_messages
|
225
|
+
end
|
226
226
|
end
|
227
227
|
|
228
|
-
def standard_conforming_strings?
|
228
|
+
def standard_conforming_strings? # :nodoc:
|
229
229
|
if @standard_conforming_strings.nil?
|
230
|
+
client_min_messages = self.client_min_messages
|
230
231
|
begin
|
231
|
-
|
232
|
+
self.client_min_messages = 'panic'
|
232
233
|
value = select_one('SHOW standard_conforming_strings', 'SCHEMA')['standard_conforming_strings']
|
233
|
-
@standard_conforming_strings = (value == "on")
|
234
|
+
@standard_conforming_strings = ( value == "on" )
|
234
235
|
rescue
|
235
236
|
@standard_conforming_strings = :unsupported
|
236
237
|
ensure
|
237
|
-
self.client_min_messages =
|
238
|
+
self.client_min_messages = client_min_messages
|
238
239
|
end
|
239
240
|
end
|
241
|
+
@standard_conforming_strings == true # return false if :unsupported
|
242
|
+
end
|
240
243
|
|
241
|
-
|
242
|
-
|
244
|
+
# Does PostgreSQL support migrations?
|
245
|
+
def supports_migrations? # :nodoc:
|
246
|
+
true
|
243
247
|
end
|
244
248
|
|
249
|
+
# Does PostgreSQL support finding primary key on non-Active Record tables?
|
250
|
+
def supports_primary_key? # :nodoc:
|
251
|
+
true
|
252
|
+
end
|
253
|
+
|
245
254
|
# Does PostgreSQL support standard conforming strings?
|
246
|
-
def supports_standard_conforming_strings?
|
255
|
+
def supports_standard_conforming_strings? # :nodoc:
|
247
256
|
standard_conforming_strings?
|
248
257
|
@standard_conforming_strings != :unsupported
|
249
258
|
end
|
250
259
|
|
251
|
-
def supports_hex_escaped_bytea?
|
260
|
+
def supports_hex_escaped_bytea? # :nodoc:
|
252
261
|
postgresql_version >= 90000
|
253
262
|
end
|
254
263
|
|
255
|
-
def supports_insert_with_returning?
|
264
|
+
def supports_insert_with_returning? # :nodoc:
|
256
265
|
postgresql_version >= 80200
|
257
266
|
end
|
258
267
|
|
259
|
-
def supports_ddl_transactions?
|
268
|
+
def supports_ddl_transactions? # :nodoc:
|
260
269
|
true
|
261
270
|
end
|
262
271
|
|
263
|
-
def
|
272
|
+
def supports_index_sort_order? # :nodoc:
|
264
273
|
true
|
265
274
|
end
|
266
|
-
|
275
|
+
|
276
|
+
def supports_savepoints? # :nodoc:
|
277
|
+
true
|
278
|
+
end
|
279
|
+
|
267
280
|
def create_savepoint
|
268
281
|
execute("SAVEPOINT #{current_savepoint_name}")
|
269
282
|
end
|
@@ -364,10 +377,8 @@ module ::ArJdbc
|
|
364
377
|
if supports_insert_with_returning? && id_value.nil?
|
365
378
|
pk, sequence_name = *pk_and_sequence_for(table) unless pk
|
366
379
|
if pk
|
367
|
-
sql =
|
368
|
-
|
369
|
-
clear_query_cache #FIXME: Why now?
|
370
|
-
return id_value
|
380
|
+
sql = to_sql(sql, binds)
|
381
|
+
return select_value("#{sql} RETURNING #{quote_column_name(pk)}")
|
371
382
|
end
|
372
383
|
end
|
373
384
|
|
@@ -390,14 +401,8 @@ module ::ArJdbc
|
|
390
401
|
end
|
391
402
|
id_value
|
392
403
|
end
|
393
|
-
|
394
|
-
|
395
|
-
pk_and_sequence = pk_and_sequence_for(table)
|
396
|
-
pk_and_sequence && pk_and_sequence.first
|
397
|
-
end
|
398
|
-
|
399
|
-
# taken from rails postgresql adapter
|
400
|
-
# https://github.com/gfmurphy/rails/blob/master/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L611
|
404
|
+
|
405
|
+
# taken from rails postgresql_adapter.rb
|
401
406
|
def sql_for_insert(sql, pk, id_value, sequence_name, binds)
|
402
407
|
unless pk
|
403
408
|
table_ref = extract_table_ref_from_insert_sql(sql)
|
@@ -408,6 +413,11 @@ module ::ArJdbc
|
|
408
413
|
|
409
414
|
[sql, binds]
|
410
415
|
end
|
416
|
+
|
417
|
+
def primary_key(table)
|
418
|
+
pk_and_sequence = pk_and_sequence_for(table)
|
419
|
+
pk_and_sequence && pk_and_sequence.first
|
420
|
+
end
|
411
421
|
|
412
422
|
def pg_columns(table_name, name=nil)
|
413
423
|
column_definitions(table_name).map do |row|
|
@@ -502,7 +512,7 @@ module ::ArJdbc
|
|
502
512
|
def create_database(name, options = {})
|
503
513
|
options = options.with_indifferent_access
|
504
514
|
create_query = "CREATE DATABASE \"#{name}\" ENCODING='#{options[:encoding] || 'utf8'}'"
|
505
|
-
create_query += options.symbolize_keys.sum do |key, value|
|
515
|
+
create_query += options.symbolize_keys.sum('') do |key, value|
|
506
516
|
case key
|
507
517
|
when :owner
|
508
518
|
" OWNER = \"#{value}\""
|
@@ -548,7 +558,7 @@ module ::ArJdbc
|
|
548
558
|
ENV['PGHOST'] = @config[:host] if @config[:host]
|
549
559
|
ENV['PGPORT'] = @config[:port].to_s if @config[:port]
|
550
560
|
ENV['PGPASSWORD'] = @config[:password].to_s if @config[:password]
|
551
|
-
search_path = "--schema=#{schema_search_path}" if schema_search_path
|
561
|
+
search_path = "--schema=#{@config[:schema_search_path]}" if @config[:schema_search_path]
|
552
562
|
|
553
563
|
@connection.connection.close
|
554
564
|
begin
|
@@ -643,10 +653,16 @@ module ::ArJdbc
|
|
643
653
|
"'#{value}'"
|
644
654
|
when String
|
645
655
|
case column.sql_type
|
646
|
-
when 'bytea' then "E'#{escape_bytea(value)}'::bytea"
|
656
|
+
when 'bytea' then "E'#{escape_bytea(value)}'::bytea" # "'#{escape_bytea(value)}'"
|
647
657
|
when 'xml' then "xml '#{quote_string(value)}'"
|
648
658
|
when /^bit/
|
649
659
|
case value
|
660
|
+
# NOTE: as reported with #60 this is not quite "right" :
|
661
|
+
# "0103" will be treated as hexadecimal string
|
662
|
+
# "0102" will be treated as hexadecimal string
|
663
|
+
# "0101" will be treated as binary string
|
664
|
+
# "0100" will be treated as binary string
|
665
|
+
# ... but is kept due Rails compatibility
|
650
666
|
when /^[01]*$/ then "B'#{value}'" # Bit-string notation
|
651
667
|
when /^[0-9A-F]*$/i then "X'#{value}'" # Hexadecimal notation
|
652
668
|
end
|
@@ -660,30 +676,29 @@ module ::ArJdbc
|
|
660
676
|
|
661
677
|
# Quotes a string, escaping any ' (single quote) and \ (backslash)
|
662
678
|
# characters.
|
663
|
-
def quote_string(
|
664
|
-
quoted =
|
665
|
-
|
679
|
+
def quote_string(string)
|
680
|
+
quoted = string.gsub("'", "''")
|
681
|
+
unless standard_conforming_strings?
|
666
682
|
quoted.gsub!(/\\/, '\&\&')
|
667
683
|
end
|
668
|
-
|
669
684
|
quoted
|
670
685
|
end
|
671
686
|
|
672
|
-
def escape_bytea(
|
673
|
-
if
|
687
|
+
def escape_bytea(string)
|
688
|
+
if string
|
674
689
|
if supports_hex_escaped_bytea?
|
675
|
-
"\\\\x#{
|
690
|
+
"\\\\x#{string.unpack("H*")[0]}"
|
676
691
|
else
|
677
692
|
result = ''
|
678
|
-
|
693
|
+
string.each_byte { |c| result << sprintf('\\\\%03o', c) }
|
679
694
|
result
|
680
695
|
end
|
681
696
|
end
|
682
697
|
end
|
683
|
-
|
698
|
+
|
684
699
|
def quote_table_name(name)
|
685
700
|
schema, name_part = extract_pg_identifier_from_name(name.to_s)
|
686
|
-
|
701
|
+
|
687
702
|
unless name_part
|
688
703
|
quote_column_name(schema)
|
689
704
|
else
|
@@ -691,11 +706,11 @@ module ::ArJdbc
|
|
691
706
|
"#{quote_column_name(schema)}.#{quote_column_name(table_name)}"
|
692
707
|
end
|
693
708
|
end
|
694
|
-
|
709
|
+
|
695
710
|
def quote_column_name(name)
|
696
711
|
%("#{name.to_s.gsub("\"", "\"\"")}")
|
697
712
|
end
|
698
|
-
|
713
|
+
|
699
714
|
def quoted_date(value) #:nodoc:
|
700
715
|
if value.acts_like?(:time) && value.respond_to?(:usec)
|
701
716
|
"#{super}.#{sprintf("%06d", value.usec)}"
|
@@ -704,7 +719,7 @@ module ::ArJdbc
|
|
704
719
|
end
|
705
720
|
end
|
706
721
|
|
707
|
-
def disable_referential_integrity
|
722
|
+
def disable_referential_integrity # :nodoc:
|
708
723
|
execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER ALL" }.join(";"))
|
709
724
|
yield
|
710
725
|
ensure
|
@@ -785,17 +800,22 @@ module ::ArJdbc
|
|
785
800
|
|
786
801
|
# Maps logical Rails types to PostgreSQL-specific data types.
|
787
802
|
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
803
|
+
case type.to_sym
|
804
|
+
when :integer
|
805
|
+
return 'integer' unless limit
|
806
|
+
case limit.to_i
|
807
|
+
when 1, 2; 'smallint'
|
808
|
+
when 3, 4; 'integer'
|
809
|
+
when 5..8; 'bigint'
|
810
|
+
else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
|
811
|
+
end
|
812
|
+
when :binary
|
813
|
+
super(type, nil, nil, nil)
|
814
|
+
else
|
815
|
+
super
|
796
816
|
end
|
797
817
|
end
|
798
|
-
|
818
|
+
|
799
819
|
def tables(name = nil)
|
800
820
|
exec_query(<<-SQL, 'SCHEMA').map { |row| row["tablename"] }
|
801
821
|
SELECT tablename
|
@@ -886,11 +906,12 @@ module ::ArJdbc
|
|
886
906
|
end
|
887
907
|
end
|
888
908
|
|
889
|
-
# from rails
|
890
|
-
def extract_table_ref_from_insert_sql(sql)
|
909
|
+
# taken from rails postgresql_adapter.rb
|
910
|
+
def extract_table_ref_from_insert_sql(sql) # :nodoc:
|
891
911
|
sql[/into\s+([^\(]*).*values\s*\(/i]
|
892
912
|
$1.strip if $1
|
893
913
|
end
|
914
|
+
|
894
915
|
end
|
895
916
|
end
|
896
917
|
|
@@ -926,6 +947,7 @@ module ActiveRecord::ConnectionAdapters
|
|
926
947
|
|
927
948
|
class PostgreSQLAdapter < JdbcAdapter
|
928
949
|
include ArJdbc::PostgreSQL
|
950
|
+
include ArJdbc::PostgreSQL::ExplainSupport
|
929
951
|
|
930
952
|
def initialize(*args)
|
931
953
|
super
|
@@ -957,5 +979,31 @@ module ActiveRecord::ConnectionAdapters
|
|
957
979
|
end
|
958
980
|
|
959
981
|
alias_chained_method :columns, :query_cache, :pg_columns
|
982
|
+
|
983
|
+
# some QUOTING caching :
|
984
|
+
|
985
|
+
@@quoted_table_names = {}
|
986
|
+
|
987
|
+
def quote_table_name(name)
|
988
|
+
unless quoted = @@quoted_table_names[name]
|
989
|
+
quoted = super
|
990
|
+
@@quoted_table_names[name] = quoted.freeze
|
991
|
+
end
|
992
|
+
quoted
|
993
|
+
end
|
994
|
+
|
995
|
+
@@quoted_column_names = {}
|
996
|
+
|
997
|
+
def quote_column_name(name)
|
998
|
+
unless quoted = @@quoted_column_names[name]
|
999
|
+
quoted = super
|
1000
|
+
@@quoted_column_names[name] = quoted.freeze
|
1001
|
+
end
|
1002
|
+
quoted
|
1003
|
+
end
|
1004
|
+
|
960
1005
|
end
|
961
1006
|
end
|
1007
|
+
|
1008
|
+
# Don't need to load native postgres adapter
|
1009
|
+
$LOADED_FEATURES << 'active_record/connection_adapters/postgresql_adapter.rb'
|
@@ -1,11 +1,13 @@
|
|
1
|
-
# Don't need to load native postgres adapter
|
2
|
-
$LOADED_FEATURES << "active_record/connection_adapters/postgresql_adapter.rb"
|
3
|
-
|
4
1
|
class ActiveRecord::Base
|
5
2
|
class << self
|
6
3
|
def postgresql_connection(config)
|
7
|
-
|
4
|
+
begin
|
5
|
+
require 'jdbc/postgres'
|
6
|
+
::Jdbc::Postgres.load_driver(:require) if defined?(::Jdbc::Postgres.load_driver)
|
7
|
+
rescue LoadError # assuming driver.jar is on the class-path
|
8
|
+
end
|
8
9
|
|
10
|
+
config[:username] ||= Java::JavaLang::System.get_property("user.name")
|
9
11
|
config[:host] ||= "localhost"
|
10
12
|
config[:port] ||= 5432
|
11
13
|
config[:url] ||= "jdbc:postgresql://#{config[:host]}:#{config[:port]}/#{config[:database]}"
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module ::ArJdbc
|
2
|
+
module PostgreSQL
|
3
|
+
module ExplainSupport
|
4
|
+
def supports_explain?
|
5
|
+
true
|
6
|
+
end
|
7
|
+
|
8
|
+
def explain(arel, binds = [])
|
9
|
+
sql = "EXPLAIN #{to_sql(arel, binds)}"
|
10
|
+
raw_result = execute(sql, "EXPLAIN", binds)
|
11
|
+
# TODO we should refactor to exce_query once it returns Result ASAP :
|
12
|
+
keys = raw_result[0] ? raw_result[0].keys : {}
|
13
|
+
rows = raw_result.map { |hash| hash.values }
|
14
|
+
ExplainPrettyPrinter.new.pp ActiveRecord::Result.new(keys, rows)
|
15
|
+
end
|
16
|
+
|
17
|
+
class ExplainPrettyPrinter # :nodoc:
|
18
|
+
# Pretty prints the result of a EXPLAIN in a way that resembles the output of the
|
19
|
+
# PostgreSQL shell:
|
20
|
+
#
|
21
|
+
# QUERY PLAN
|
22
|
+
# ------------------------------------------------------------------------------
|
23
|
+
# Nested Loop Left Join (cost=0.00..37.24 rows=8 width=0)
|
24
|
+
# Join Filter: (posts.user_id = users.id)
|
25
|
+
# -> Index Scan using users_pkey on users (cost=0.00..8.27 rows=1 width=4)
|
26
|
+
# Index Cond: (id = 1)
|
27
|
+
# -> Seq Scan on posts (cost=0.00..28.88 rows=8 width=4)
|
28
|
+
# Filter: (posts.user_id = 1)
|
29
|
+
# (6 rows)
|
30
|
+
#
|
31
|
+
def pp(result)
|
32
|
+
header = result.columns.first
|
33
|
+
lines = result.rows.map(&:first)
|
34
|
+
|
35
|
+
# We add 2 because there's one char of padding at both sides, note
|
36
|
+
# the extra hyphens in the example above.
|
37
|
+
width = [header, *lines].map(&:length).max + 2
|
38
|
+
|
39
|
+
pp = []
|
40
|
+
|
41
|
+
pp << header.center(width).rstrip
|
42
|
+
pp << '-' * width
|
43
|
+
|
44
|
+
pp += lines.map {|line| " #{line}"}
|
45
|
+
|
46
|
+
nrows = result.rows.length
|
47
|
+
rows_label = nrows == 1 ? 'row' : 'rows'
|
48
|
+
pp << "(#{nrows} #{rows_label})"
|
49
|
+
|
50
|
+
pp.join("\n") + "\n"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|