From 1d8d5a74b81b8aab1f5e6d233d509a92525ed4e1 Mon Sep 17 00:00:00 2001 From: Lars Kanis Date: Sat, 21 Mar 2015 21:51:55 +0100 Subject: [PATCH] PostgreSQL, Fix OID based type casts in C for primitive types. The type map was introduced in aafee23, but wasn't properly filled. This mainly adjusts many locations, that expected strings instead of integers or boolean. add_pg_decoders is moved after setup of the StatementPool, because execute_and_clear could potentially make use of it. --- .../postgresql/oid/type_map_initializer.rb | 2 +- .../postgresql/schema_statements.rb | 6 +++--- .../connection_adapters/postgresql_adapter.rb | 12 ++++++------ .../cases/adapters/postgresql/numbers_test.rb | 2 +- .../postgresql/postgresql_adapter_test.rb | 16 ++++++++-------- .../postgresql/referential_integrity_test.rb | 2 +- .../cases/adapters/postgresql/schema_test.rb | 6 +++--- activerecord/test/cases/query_cache_test.rb | 2 +- 8 files changed, 24 insertions(+), 24 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb index 9b3de41fab..9d421d6975 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb @@ -19,7 +19,7 @@ module ActiveRecord enums, nodes = nodes.partition { |row| row['typtype'] == 'e' } domains, nodes = nodes.partition { |row| row['typtype'] == 'd' } arrays, nodes = nodes.partition { |row| row['typinput'] == 'array_in' } - composites, nodes = nodes.partition { |row| row['typelem'] != '0' } + composites, nodes = nodes.partition { |row| row['typelem'].to_i != 0 } mapped.each { |row| register_mapped_type(row) } enums.each { |row| register_enum_type(row) } diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb index eeb141dd1e..cb0b9cdbe9 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -129,8 +129,8 @@ module ActiveRecord result.map do |row| index_name = row[0] - unique = row[1] == 't' - indkey = row[2].split(" ") + unique = row[1] + indkey = row[2].split(" ").map(&:to_i) inddef = row[3] oid = row[4] @@ -164,7 +164,7 @@ module ActiveRecord type_metadata = fetch_type_metadata(column_name, type, oid, fmod) default_value = extract_value_from_default(default) default_function = extract_default_function(default_value, default) - new_column(column_name, default_value, type_metadata, notnull == 'f', default_function) + new_column(column_name, default_value, type_metadata, !notnull, default_function) end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 96a3ac7c31..37bf4d77f8 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -278,8 +278,6 @@ module ActiveRecord @table_alias_length = nil connect - add_pg_decoders - @statements = StatementPool.new @connection, self.class.type_cast_config_to_integer(config.fetch(:statement_limit) { 1000 }) @@ -287,6 +285,8 @@ module ActiveRecord raise "Your version of PostgreSQL (#{postgresql_version}) is too old, please upgrade!" end + add_pg_decoders + @type_map = Type::HashLookupTypeMap.new initialize_type_map(type_map) @local_tz = execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"] @@ -798,7 +798,7 @@ module ActiveRecord ) end_sql execute_and_clear(sql, "SCHEMA", []) do |result| - result.getvalue(0, 0) == 't' + result.getvalue(0, 0) end end end @@ -814,12 +814,12 @@ module ActiveRecord 'bool' => PG::TextDecoder::Boolean, } query = <<-SQL - SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, t.typtype, t.typbasetype + SELECT t.oid, t.typname FROM pg_type as t SQL coders = execute_and_clear(query, "SCHEMA", []) do |result| result - .map { |row| construct_coder(row, coders_by_name['typname']) } + .map { |row| construct_coder(row, coders_by_name[row['typname']]) } .compact end @@ -830,7 +830,7 @@ module ActiveRecord def construct_coder(row, coder_class) return unless coder_class - coder_class.new(oid: row['oid'], name: row['typname']) + coder_class.new(oid: row['oid'].to_i, name: row['typname']) end ActiveRecord::Type.add_modifier({ array: true }, OID::Array, adapter: :postgresql) diff --git a/activerecord/test/cases/adapters/postgresql/numbers_test.rb b/activerecord/test/cases/adapters/postgresql/numbers_test.rb index 093b81fe8d..d8e01e3b89 100644 --- a/activerecord/test/cases/adapters/postgresql/numbers_test.rb +++ b/activerecord/test/cases/adapters/postgresql/numbers_test.rb @@ -31,7 +31,7 @@ class PostgresqlNumberTest < ActiveRecord::TestCase assert_equal 123456.789, first.double assert_equal(-::Float::INFINITY, second.single) assert_equal ::Float::INFINITY, second.double - assert_same ::Float::NAN, third.double + assert_send [third.double, :nan?] end def test_update diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb index a934180a43..9a1b889d4d 100644 --- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb +++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb @@ -68,7 +68,7 @@ module ActiveRecord def test_insert_sql_with_proprietary_returning_clause with_example_table do id = @connection.insert_sql("insert into ex (number) values(5150)", nil, "number") - assert_equal "5150", id + assert_equal 5150, id end end @@ -106,21 +106,21 @@ module ActiveRecord connection = connection_without_insert_returning id = connection.insert_sql("insert into postgresql_partitioned_table_parent (number) VALUES (1)") expect = connection.query('select max(id) from postgresql_partitioned_table_parent').first.first - assert_equal expect, id + assert_equal expect.to_i, id end def test_exec_insert_with_returning_disabled connection = connection_without_insert_returning result = connection.exec_insert("insert into postgresql_partitioned_table_parent (number) VALUES (1)", nil, [], 'id', 'postgresql_partitioned_table_parent_id_seq') expect = connection.query('select max(id) from postgresql_partitioned_table_parent').first.first - assert_equal expect, result.rows.first.first + assert_equal expect.to_i, result.rows.first.first end def test_exec_insert_with_returning_disabled_and_no_sequence_name_given connection = connection_without_insert_returning result = connection.exec_insert("insert into postgresql_partitioned_table_parent (number) VALUES (1)", nil, [], 'id') expect = connection.query('select max(id) from postgresql_partitioned_table_parent').first.first - assert_equal expect, result.rows.first.first + assert_equal expect.to_i, result.rows.first.first end def test_sql_for_insert_with_returning_disabled @@ -238,7 +238,7 @@ module ActiveRecord result = @connection.exec_query('SELECT number FROM ex WHERE number = 10') assert_equal 1, result.rows.length - assert_equal "10", result.rows.last.last + assert_equal 10, result.rows.last.last end end @@ -274,7 +274,7 @@ module ActiveRecord assert_equal 1, result.rows.length assert_equal 2, result.columns.length - assert_equal [['1', 'foo']], result.rows + assert_equal [[1, 'foo']], result.rows end end @@ -288,7 +288,7 @@ module ActiveRecord assert_equal 1, result.rows.length assert_equal 2, result.columns.length - assert_equal [['1', 'foo']], result.rows + assert_equal [[1, 'foo']], result.rows end end @@ -304,7 +304,7 @@ module ActiveRecord assert_equal 1, result.rows.length assert_equal 2, result.columns.length - assert_equal [['1', 'foo']], result.rows + assert_equal [[1, 'foo']], result.rows end end diff --git a/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb b/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb index d76e762815..7200ed2771 100644 --- a/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb +++ b/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb @@ -106,6 +106,6 @@ class PostgreSQLReferentialIntegrityTest < ActiveRecord::TestCase private def assert_transaction_is_not_broken - assert_equal "1", @connection.select_value("SELECT 1") + assert_equal 1, @connection.select_value("SELECT 1") end end diff --git a/activerecord/test/cases/adapters/postgresql/schema_test.rb b/activerecord/test/cases/adapters/postgresql/schema_test.rb index c1be340e7c..f925dcad97 100644 --- a/activerecord/test/cases/adapters/postgresql/schema_test.rb +++ b/activerecord/test/cases/adapters/postgresql/schema_test.rb @@ -384,16 +384,16 @@ class SchemaTest < ActiveRecord::TestCase def test_reset_pk_sequence sequence_name = "#{SCHEMA_NAME}.#{UNMATCHED_SEQUENCE_NAME}" @connection.execute "SELECT setval('#{sequence_name}', 123)" - assert_equal "124", @connection.select_value("SELECT nextval('#{sequence_name}')") + assert_equal 124, @connection.select_value("SELECT nextval('#{sequence_name}')") @connection.reset_pk_sequence!("#{SCHEMA_NAME}.#{UNMATCHED_PK_TABLE_NAME}") - assert_equal "1", @connection.select_value("SELECT nextval('#{sequence_name}')") + assert_equal 1, @connection.select_value("SELECT nextval('#{sequence_name}')") end def test_set_pk_sequence table_name = "#{SCHEMA_NAME}.#{PK_TABLE_NAME}" _, sequence_name = @connection.pk_and_sequence_for table_name @connection.set_pk_sequence! table_name, 123 - assert_equal "124", @connection.select_value("SELECT nextval('#{sequence_name}')") + assert_equal 124, @connection.select_value("SELECT nextval('#{sequence_name}')") @connection.reset_pk_sequence! table_name end diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb index 744f9edc47..2f0b5df286 100644 --- a/activerecord/test/cases/query_cache_test.rb +++ b/activerecord/test/cases/query_cache_test.rb @@ -184,7 +184,7 @@ class QueryCacheTest < ActiveRecord::TestCase # Oracle adapter returns count() as Fixnum or Float if current_adapter?(:OracleAdapter) assert_kind_of Numeric, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks") - elsif current_adapter?(:SQLite3Adapter, :Mysql2Adapter) + elsif current_adapter?(:SQLite3Adapter, :Mysql2Adapter, :PostgreSQLAdapter) # Future versions of the sqlite3 adapter will return numeric assert_instance_of Fixnum, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")