Skip to content

Commit

Permalink
Use the generic type map for all PG type registrations
Browse files Browse the repository at this point in the history
We're going to want all of the benefits of the type map object for
registrations, including block registration and real aliasing. Moves
type name registrations to the adapter, and aliases the OIDs to the
named types
  • Loading branch information
sgrif committed May 22, 2014
1 parent 110d3d0 commit 4826a4a
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 84 deletions.
Expand Up @@ -27,73 +27,6 @@ module ActiveRecord
module ConnectionAdapters
module PostgreSQL
module OID # :nodoc:
# When the PG adapter connects, the pg_type table is queried. The
# key of this hash maps to the `typname` column from the table.
# type_map is then dynamically built with oids as the key and type
# objects as values.
NAMES = Hash.new { |h,k| # :nodoc:
h[k] = Type::Value.new
}

# Register an OID type named +name+ with a typecasting object in
# +type+. +name+ should correspond to the `typname` column in
# the `pg_type` table.
def self.register_type(name, type)
NAMES[name] = type
end

# Alias the +old+ type to the +new+ type.
def self.alias_type(new, old)
NAMES[new] = NAMES[old]
end

# Is +name+ a registered type?
def self.registered_type?(name)
NAMES.key? name
end

register_type 'int2', OID::Integer.new
alias_type 'int4', 'int2'
alias_type 'int8', 'int2'
alias_type 'oid', 'int2'
register_type 'numeric', OID::Decimal.new
register_type 'float4', OID::Float.new
alias_type 'float8', 'float4'
register_type 'text', Type::Text.new
register_type 'varchar', Type::String.new
alias_type 'char', 'varchar'
alias_type 'name', 'varchar'
alias_type 'bpchar', 'varchar'
register_type 'bool', Type::Boolean.new
register_type 'bit', OID::Bit.new
alias_type 'varbit', 'bit'
register_type 'timestamp', OID::DateTime.new
alias_type 'timestamptz', 'timestamp'
register_type 'date', OID::Date.new
register_type 'time', OID::Time.new

register_type 'money', OID::Money.new
register_type 'bytea', OID::Bytea.new
register_type 'point', OID::Point.new
register_type 'hstore', OID::Hstore.new
register_type 'json', OID::Json.new
register_type 'cidr', OID::Cidr.new
register_type 'inet', OID::Inet.new
register_type 'uuid', OID::Uuid.new
register_type 'xml', SpecializedString.new(:xml)
register_type 'tsvector', SpecializedString.new(:tsvector)
register_type 'macaddr', SpecializedString.new(:macaddr)
register_type 'citext', SpecializedString.new(:citext)
register_type 'ltree', SpecializedString.new(:ltree)

# FIXME: why are we keeping these types as strings?
alias_type 'interval', 'varchar'
alias_type 'path', 'varchar'
alias_type 'line', 'varchar'
alias_type 'polygon', 'varchar'
alias_type 'circle', 'varchar'
alias_type 'lseg', 'varchar'
alias_type 'box', 'varchar'
end
end
end
Expand Down
Expand Up @@ -13,7 +13,8 @@ def initialize(store)
end

def run(records)
mapped, nodes = records.partition { |row| OID.registered_type? row['typname'] }
nodes = records.reject { |row| @store.key? row['oid'].to_i }
mapped, nodes = nodes.partition { |row| @store.key? row['typname'] }
ranges, nodes = nodes.partition { |row| row['typtype'] == 'r' }
enums, nodes = nodes.partition { |row| row['typtype'] == 'e' }
domains, nodes = nodes.partition { |row| row['typtype'] == 'd' }
Expand All @@ -30,7 +31,7 @@ def run(records)

private
def register_mapped_type(row)
register row['oid'], OID::NAMES[row['typname']]
alias_type row['oid'], row['typname']
end

def register_enum_type(row)
Expand Down Expand Up @@ -64,12 +65,18 @@ def register_composite_type(row)
end

def register(oid, oid_type)
oid = oid.to_i
oid = assert_valid_registration(oid, oid_type)
@store.register_type(oid, oid_type)
end

raise ArgumentError, "can't register nil type for OID #{oid}" if oid_type.nil?
return if @store.key?(oid)
def alias_type(oid, target)
oid = assert_valid_registration(oid, target)
@store.alias_type(oid, target)
end

@store.register_type(oid, oid_type)
def assert_valid_registration(oid, oid_type)
raise ArgumentError, "can't register nil type for OID #{oid}" if oid_type.nil?
oid.to_i
end
end
end
Expand Down
Expand Up @@ -540,7 +540,7 @@ def translate_exception(exception, message)

def get_oid_type(oid, fmod, column_name)
if !type_map.key?(oid)
initialize_type_map(type_map, [oid])
load_additional_types(type_map, [oid])
end

type_map.fetch(normalize_oid_type(oid, fmod)) {
Expand All @@ -566,7 +566,54 @@ def normalize_oid_type(ftype, fmod)
end
end

def initialize_type_map(type_map, oids = nil)
def initialize_type_map(m)
m.register_type 'int2', OID::Integer.new
m.alias_type 'int4', 'int2'
m.alias_type 'int8', 'int2'
m.alias_type 'oid', 'int2'
m.register_type 'numeric', OID::Decimal.new
m.register_type 'float4', OID::Float.new
m.alias_type 'float8', 'float4'
m.register_type 'text', Type::Text.new
m.register_type 'varchar', Type::String.new
m.alias_type 'char', 'varchar'
m.alias_type 'name', 'varchar'
m.alias_type 'bpchar', 'varchar'
m.register_type 'bool', Type::Boolean.new
m.register_type 'bit', OID::Bit.new
m.alias_type 'varbit', 'bit'
m.register_type 'timestamp', OID::DateTime.new
m.alias_type 'timestamptz', 'timestamp'
m.register_type 'date', OID::Date.new
m.register_type 'time', OID::Time.new

m.register_type 'money', OID::Money.new
m.register_type 'bytea', OID::Bytea.new
m.register_type 'point', OID::Point.new
m.register_type 'hstore', OID::Hstore.new
m.register_type 'json', OID::Json.new
m.register_type 'cidr', OID::Cidr.new
m.register_type 'inet', OID::Inet.new
m.register_type 'uuid', OID::Uuid.new
m.register_type 'xml', OID::SpecializedString.new(:xml)
m.register_type 'tsvector', OID::SpecializedString.new(:tsvector)
m.register_type 'macaddr', OID::SpecializedString.new(:macaddr)
m.register_type 'citext', OID::SpecializedString.new(:citext)
m.register_type 'ltree', OID::SpecializedString.new(:ltree)

# FIXME: why are we keeping these types as strings?
m.alias_type 'interval', 'varchar'
m.alias_type 'path', 'varchar'
m.alias_type 'line', 'varchar'
m.alias_type 'polygon', 'varchar'
m.alias_type 'circle', 'varchar'
m.alias_type 'lseg', 'varchar'
m.alias_type 'box', 'varchar'

load_additional_types(m)
end

def load_additional_types(type_map, oids = nil)
if supports_ranges?
query = <<-SQL
SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
Expand Down
10 changes: 1 addition & 9 deletions activerecord/test/cases/adapters/postgresql/composite_test.rb
Expand Up @@ -102,15 +102,7 @@ def type_cast_for_write(value)
def setup
super

@registration = ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::OID
@registration.register_type "full_address", FullAddressType.new
end

def teardown
super

# there is currently no clean way to unregister a OID::Type
@registration::NAMES.delete("full_address")
@connection.type_map.register_type "full_address", FullAddressType.new
end

def test_column
Expand Down

0 comments on commit 4826a4a

Please sign in to comment.