aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/connection_adapters
diff options
context:
space:
mode:
authorAaron Patterson <aaron.patterson@gmail.com>2012-02-10 14:52:27 -0800
committerAaron Patterson <aaron.patterson@gmail.com>2012-02-10 14:52:27 -0800
commitfa6cda53ebc7fd186a91fd0983dc9ddf20e9d39a (patch)
tree392f138adb0902afd424ba8af4bb64d639f74a8a /activerecord/lib/active_record/connection_adapters
parentf7b915b50718c86d3644941cd0bbe7df08888a5b (diff)
downloadrails-fa6cda53ebc7fd186a91fd0983dc9ddf20e9d39a.tar.gz
rails-fa6cda53ebc7fd186a91fd0983dc9ddf20e9d39a.tar.bz2
rails-fa6cda53ebc7fd186a91fd0983dc9ddf20e9d39a.zip
dynamically populate casting objects via the pg_type table
Diffstat (limited to 'activerecord/lib/active_record/connection_adapters')
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid.rb92
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb17
2 files changed, 74 insertions, 35 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
index 8110db78c4..8e1348a38d 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
@@ -150,6 +150,10 @@ module ActiveRecord
@mapping[oid]
end
+ def key?(oid)
+ @mapping.key? oid
+ end
+
def fetch(ftype, fmod)
# The type for the numeric depends on the width of the field,
# so we'll do something special here.
@@ -168,53 +172,71 @@ module ActiveRecord
TYPE_MAP = TypeMap.new # :nodoc:
- TYPE_MAP[23] = OID::Integer.new # int4
- TYPE_MAP[20] = TYPE_MAP[23] # int8
- TYPE_MAP[21] = TYPE_MAP[23] # int2
- TYPE_MAP[26] = TYPE_MAP[23] # oid
+ # 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] = OID::Identity.new
+ }
+
- TYPE_MAP[1700] = OID::Decimal.new # decimal
+ # Register an OID type named +name+ with a typcasting 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
- TYPE_MAP[25] = OID::Identity.new # text
- TYPE_MAP[19] = TYPE_MAP[25] # name
- TYPE_MAP[1043] = TYPE_MAP[25] # varchar
+ # 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 'text', OID::Identity.new
+ alias_type 'varchar', 'text'
+ alias_type 'char', 'text'
# FIXME: why are we keeping these types as strings?
- TYPE_MAP[3614] = TYPE_MAP[25] # tsvector
- TYPE_MAP[1186] = TYPE_MAP[25] # interval
- TYPE_MAP[650] = TYPE_MAP[25] # cidr
- TYPE_MAP[869] = TYPE_MAP[25] # inet
- TYPE_MAP[829] = TYPE_MAP[25] # macaddr
- TYPE_MAP[1560] = TYPE_MAP[25] # bit
- TYPE_MAP[1562] = TYPE_MAP[25] # varbit
+ alias_type 'tsvector', 'text'
+ alias_type 'interval', 'text'
+ alias_type 'cidr', 'text'
+ alias_type 'inet', 'text'
+ alias_type 'macaddr', 'text'
+ alias_type 'bit', 'text'
+ alias_type 'varbit', 'text'
# FIXME: I don't think this is correct. We should probably be returning a parsed date,
# but the tests pass with a string returned.
- TYPE_MAP[1184] = OID::Identity.new # timestamptz
+ register_type 'timestamptz', OID::Identity.new
- TYPE_MAP[790] = OID::Money.new # money
- TYPE_MAP[17] = OID::Bytea.new # bytea
- TYPE_MAP[16] = OID::Boolean.new # bool
+ register_type 'money', OID::Money.new
+ register_type 'bytea', OID::Bytea.new
+ register_type 'bool', OID::Boolean.new
- TYPE_MAP[700] = OID::Float.new # float4
- TYPE_MAP[701] = TYPE_MAP[700] # float8
+ register_type 'float4', OID::Float.new
+ alias_type 'float8', 'float4'
- TYPE_MAP[1114] = OID::Timestamp.new # timestamp
- TYPE_MAP[1082] = OID::Date.new # date
- TYPE_MAP[1083] = OID::Time.new # time
+ register_type 'timestamp', OID::Timestamp.new
+ register_type 'date', OID::Date.new
+ register_type 'time', OID::Time.new
- TYPE_MAP[1009] = OID::Vector.new(',', TYPE_MAP[25]) # _text
- TYPE_MAP[1007] = OID::Vector.new(',', TYPE_MAP[23]) # _int4
- TYPE_MAP[600] = OID::Vector.new(',', TYPE_MAP[701]) # point
- TYPE_MAP[601] = OID::Vector.new(',', TYPE_MAP[600]) # lseg
- TYPE_MAP[602] = OID::Identity.new # path
- TYPE_MAP[603] = OID::Vector.new(';', TYPE_MAP[600]) # box
- TYPE_MAP[604] = OID::Identity.new # polygon
- TYPE_MAP[718] = OID::Identity.new # circle
-
- TYPE_MAP[1399854] = OID::Hstore.new # hstore
+ register_type 'path', OID::Identity.new
+ register_type 'polygon', OID::Identity.new
+ register_type 'circle', OID::Identity.new
+ register_type 'hstore', OID::Hstore.new
end
end
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 eccf3595aa..187d5651e6 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -383,6 +383,7 @@ module ActiveRecord
raise "Your version of PostgreSQL (#{postgresql_version}) is too old, please upgrade!"
end
+ initialize_type_map
@local_tz = execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"]
end
@@ -1188,6 +1189,22 @@ module ActiveRecord
end
private
+ def initialize_type_map
+ result = execute('SELECT oid, typname, typelem, typdelim FROM pg_type', 'SCHEMA')
+ leaves, nodes = result.partition { |row| row['typelem'] == '0' }
+
+ # populate the leaf nodes
+ leaves.find_all { |row| OID.registered_type? row['typname'] }.each do |row|
+ OID::TYPE_MAP[row['oid'].to_i] = OID::NAMES[row['typname']]
+ end
+
+ # populate composite types
+ nodes.find_all { |row| OID::TYPE_MAP.key? row['typelem'].to_i }.each do |row|
+ vector = OID::Vector.new row['typdelim'], OID::TYPE_MAP[row['typelem'].to_i]
+ OID::TYPE_MAP[row['oid'].to_i] = vector
+ end
+ end
+
FEATURE_NOT_SUPPORTED = "0A000" # :nodoc:
def exec_no_cache(sql, binds)