@@ -14,12 +14,7 @@ module OIDTypes
1414
1515 OID = ActiveRecord ::ConnectionAdapters ::PostgreSQL ::OID
1616
17- def get_oid_type ( oid , fmod , column_name )
18- type_map . fetch ( oid , fmod ) {
19- warn "unknown OID #{ oid } : failed to recognize type of '#{ column_name } '. It will be treated as String."
20- type_map [ oid ] = OID ::Identity . new
21- }
22- end
17+ Type = ActiveRecord ::Type if AR42_COMPAT
2318
2419 # @override
2520 def enable_extension ( name )
@@ -42,13 +37,40 @@ def extensions
4237 @extensions ||= super
4338 end
4439
40+ def get_oid_type ( oid , fmod , column_name )
41+ type_map . fetch ( oid , fmod ) {
42+ warn "unknown OID #{ oid } : failed to recognize type of '#{ column_name } '. It will be treated as String."
43+ type_map [ oid ] = OID ::Identity . new
44+ }
45+ end unless AR42_COMPAT
46+
47+ def get_oid_type ( oid , fmod , column_name , sql_type = '' ) # :nodoc:
48+ if !type_map . key? ( oid )
49+ load_additional_types ( type_map , [ oid ] )
50+ end
51+
52+ type_map . fetch ( oid , fmod , sql_type ) {
53+ warn "unknown OID #{ oid } : failed to recognize type of '#{ column_name } '. It will be treated as String."
54+ Type ::Value . new . tap do |cast_type |
55+ type_map . register_type ( oid , cast_type )
56+ end
57+ }
58+ end if AR42_COMPAT
59+
4560 private
4661
4762 @@type_map_cache = { }
4863 @@type_map_cache_lock = Mutex . new
4964
65+ if AR42_COMPAT
66+ TypeMap = ActiveRecord ::Type ::HashLookupTypeMap
67+ else
68+ TypeMap = OID ::TypeMap
69+ end
70+
71+ # @see #type_map
5072 # @private
51- class OID :: TypeMap
73+ TypeMap . class_eval do
5274 def dup
5375 dup = super # make sure @mapping is not shared
5476 dup . instance_variable_set ( :@mapping , @mapping . dup )
@@ -62,7 +84,7 @@ def type_map
6284 if type_map = @@type_map_cache [ type_cache_key ]
6385 type_map . dup
6486 else
65- type_map = OID :: TypeMap . new
87+ type_map = TypeMap . new
6688 initialize_type_map ( type_map )
6789 cache_type_map ( type_map )
6890 type_map
@@ -126,7 +148,101 @@ def initialize_type_map(type_map)
126148 array = OID ::Array . new type_map [ row [ 'typelem' ] . to_i ]
127149 type_map [ row [ 'oid' ] . to_i ] = array
128150 end
129- end
151+ end unless AR42_COMPAT
152+
153+ def initialize_type_map ( m ) # :nodoc:
154+ register_class_with_limit m , 'int2' , OID ::Integer
155+ m . alias_type 'int4' , 'int2'
156+ m . alias_type 'int8' , 'int2'
157+ m . alias_type 'oid' , 'int2'
158+ m . register_type 'float4' , OID ::Float . new
159+ m . alias_type 'float8' , 'float4'
160+ m . register_type 'text' , Type ::Text . new
161+ register_class_with_limit m , 'varchar' , Type ::String
162+ m . alias_type 'char' , 'varchar'
163+ m . alias_type 'name' , 'varchar'
164+ m . alias_type 'bpchar' , 'varchar'
165+ m . register_type 'bool' , Type ::Boolean . new
166+ register_class_with_limit m , 'bit' , OID ::Bit
167+ register_class_with_limit m , 'varbit' , OID ::BitVarying
168+ m . alias_type 'timestamptz' , 'timestamp'
169+ m . register_type 'date' , OID ::Date . new
170+ m . register_type 'time' , OID ::Time . new
171+
172+ m . register_type 'money' , OID ::Money . new
173+ m . register_type 'bytea' , OID ::Bytea . new
174+ m . register_type 'point' , OID ::Point . new
175+ m . register_type 'hstore' , OID ::Hstore . new
176+ m . register_type 'json' , OID ::Json . new
177+ m . register_type 'jsonb' , OID ::Jsonb . new
178+ m . register_type 'cidr' , OID ::Cidr . new
179+ m . register_type 'inet' , OID ::Inet . new
180+ m . register_type 'uuid' , OID ::Uuid . new
181+ m . register_type 'xml' , OID ::Xml . new
182+ m . register_type 'tsvector' , OID ::SpecializedString . new ( :tsvector )
183+ m . register_type 'macaddr' , OID ::SpecializedString . new ( :macaddr )
184+ m . register_type 'citext' , OID ::SpecializedString . new ( :citext )
185+ m . register_type 'ltree' , OID ::SpecializedString . new ( :ltree )
186+
187+ # FIXME: why are we keeping these types as strings?
188+ m . alias_type 'interval' , 'varchar'
189+ m . alias_type 'path' , 'varchar'
190+ m . alias_type 'line' , 'varchar'
191+ m . alias_type 'polygon' , 'varchar'
192+ m . alias_type 'circle' , 'varchar'
193+ m . alias_type 'lseg' , 'varchar'
194+ m . alias_type 'box' , 'varchar'
195+
196+ m . register_type 'timestamp' do |_ , _ , sql_type |
197+ precision = extract_precision ( sql_type )
198+ OID ::DateTime . new ( precision : precision )
199+ end
200+
201+ m . register_type 'numeric' do |_ , fmod , sql_type |
202+ precision = extract_precision ( sql_type )
203+ scale = extract_scale ( sql_type )
204+
205+ # The type for the numeric depends on the width of the field,
206+ # so we'll do something special here.
207+ #
208+ # When dealing with decimal columns:
209+ #
210+ # places after decimal = fmod - 4 & 0xffff
211+ # places before decimal = (fmod - 4) >> 16 & 0xffff
212+ if fmod && ( fmod - 4 & 0xffff ) . zero?
213+ # FIXME: Remove this class, and the second argument to
214+ # lookups on PG
215+ Type ::DecimalWithoutScale . new ( precision : precision )
216+ else
217+ OID ::Decimal . new ( precision : precision , scale : scale )
218+ end
219+ end
220+
221+ load_additional_types ( m )
222+ end if AR42_COMPAT
223+
224+ def load_additional_types ( type_map , oids = nil ) # :nodoc:
225+ if supports_ranges?
226+ query = <<-SQL
227+ SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
228+ FROM pg_type as t
229+ LEFT JOIN pg_range as r ON oid = rngtypid
230+ SQL
231+ else
232+ query = <<-SQL
233+ SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, t.typtype, t.typbasetype
234+ FROM pg_type as t
235+ SQL
236+ end
237+
238+ if oids
239+ query += "WHERE t.oid::integer IN (%s)" % oids . join ( ", " )
240+ end
241+
242+ initializer = OID ::TypeMapInitializer . new ( type_map )
243+ records = execute ( query , 'SCHEMA' )
244+ initializer . run ( records )
245+ end if AR42_COMPAT
130246
131247 end
132248 end
0 commit comments