@@ -91,9 +91,10 @@ def extensions
91
91
end
92
92
93
93
def get_oid_type ( oid , fmod , column_name , sql_type = '' ) # :nodoc:
94
- if !type_map . key? ( oid )
95
- load_additional_types ( type_map , oid )
96
- end
94
+ # This is unhappy with oid of regproc
95
+ #if !type_map.key?(oid)
96
+ # load_additional_types([oid])
97
+ #end
97
98
98
99
type_map . fetch ( oid , fmod , sql_type ) {
99
100
warn "unknown OID #{ oid } : failed to recognize type of '#{ column_name } '. It will be treated as String."
@@ -103,15 +104,92 @@ def get_oid_type(oid, fmod, column_name, sql_type = '') # :nodoc:
103
104
}
104
105
end
105
106
107
+ def reload_type_map
108
+ type_map . clear
109
+ initialize_type_map
110
+ end
111
+
112
+ def initialize_type_map_inner ( m )
113
+ m . register_type "int2" , Type ::Integer . new ( limit : 2 )
114
+ m . register_type "int4" , Type ::Integer . new ( limit : 4 )
115
+ m . register_type "int8" , Type ::Integer . new ( limit : 8 )
116
+ m . register_type "oid" , OID ::Oid . new
117
+ m . register_type "float4" , Type ::Float . new
118
+ m . alias_type "float8" , "float4"
119
+ m . register_type "text" , Type ::Text . new
120
+ register_class_with_limit m , "varchar" , Type ::String
121
+ m . alias_type "char" , "varchar"
122
+ m . alias_type "name" , "varchar"
123
+ m . alias_type "bpchar" , "varchar"
124
+ m . register_type "bool" , Type ::Boolean . new
125
+ register_class_with_limit m , "bit" , OID ::Bit
126
+ register_class_with_limit m , "varbit" , OID ::BitVarying
127
+ m . register_type "date" , OID ::Date . new
128
+
129
+ m . register_type "money" , OID ::Money . new
130
+ m . register_type "bytea" , OID ::Bytea . new
131
+ m . register_type "point" , OID ::Point . new
132
+ m . register_type "hstore" , OID ::Hstore . new
133
+ m . register_type "json" , Type ::Json . new
134
+ m . register_type "jsonb" , OID ::Jsonb . new
135
+ m . register_type "cidr" , OID ::Cidr . new
136
+ m . register_type "inet" , OID ::Inet . new
137
+ m . register_type "uuid" , OID ::Uuid . new
138
+ m . register_type "xml" , OID ::Xml . new
139
+ m . register_type "tsvector" , OID ::SpecializedString . new ( :tsvector )
140
+ m . register_type "macaddr" , OID ::Macaddr . new
141
+ m . register_type "citext" , OID ::SpecializedString . new ( :citext )
142
+ m . register_type "ltree" , OID ::SpecializedString . new ( :ltree )
143
+ m . register_type "line" , OID ::SpecializedString . new ( :line )
144
+ m . register_type "lseg" , OID ::SpecializedString . new ( :lseg )
145
+ m . register_type "box" , OID ::SpecializedString . new ( :box )
146
+ m . register_type "path" , OID ::SpecializedString . new ( :path )
147
+ m . register_type "polygon" , OID ::SpecializedString . new ( :polygon )
148
+ m . register_type "circle" , OID ::SpecializedString . new ( :circle )
149
+
150
+ register_class_with_precision m , "time" , Type ::Time
151
+ register_class_with_precision m , "timestamp" , OID ::Timestamp
152
+ register_class_with_precision m , "timestamptz" , OID ::TimestampWithTimeZone
153
+
154
+ m . register_type "numeric" do |_ , fmod , sql_type |
155
+ precision = extract_precision ( sql_type )
156
+ scale = extract_scale ( sql_type )
157
+
158
+ # The type for the numeric depends on the width of the field,
159
+ # so we'll do something special here.
160
+ #
161
+ # When dealing with decimal columns:
162
+ #
163
+ # places after decimal = fmod - 4 & 0xffff
164
+ # places before decimal = (fmod - 4) >> 16 & 0xffff
165
+ if fmod && ( fmod - 4 & 0xffff ) . zero?
166
+ # FIXME: Remove this class, and the second argument to
167
+ # lookups on PG
168
+ Type ::DecimalWithoutScale . new ( precision : precision )
169
+ else
170
+ OID ::Decimal . new ( precision : precision , scale : scale )
171
+ end
172
+ end
173
+
174
+ m . register_type "interval" do |*args , sql_type |
175
+ precision = extract_precision ( sql_type )
176
+ OID ::Interval . new ( precision : precision )
177
+ end
178
+
179
+ # pgjdbc returns these if the column is auto-incrmenting
180
+ m . alias_type 'serial' , 'int4'
181
+ m . alias_type 'bigserial' , 'int8'
182
+ end
183
+
184
+
185
+ # We differ from AR here because we will initialize type_map when adapter initializes
106
186
def type_map
107
187
@type_map
108
188
end
109
189
110
- def reload_type_map
111
- if ( @type_map ||= nil )
112
- @type_map . clear
113
- initialize_type_map ( @type_map )
114
- end
190
+ def initialize_type_map ( m = type_map )
191
+ initialize_type_map_inner ( m )
192
+ load_additional_types
115
193
end
116
194
117
195
private
@@ -124,117 +202,45 @@ def register_class_with_precision(...)
124
202
::ActiveRecord ::ConnectionAdapters ::AbstractAdapter . send ( :register_class_with_precision , ...)
125
203
end
126
204
127
- def initialize_type_map ( m = type_map )
128
- m . register_type "int2" , Type ::Integer . new ( limit : 2 )
129
- m . register_type "int4" , Type ::Integer . new ( limit : 4 )
130
- m . register_type "int8" , Type ::Integer . new ( limit : 8 )
131
- m . register_type "oid" , OID ::Oid . new
132
- m . register_type "float4" , Type ::Float . new
133
- m . alias_type "float8" , "float4"
134
- m . register_type "text" , Type ::Text . new
135
- register_class_with_limit m , "varchar" , Type ::String
136
- m . alias_type "char" , "varchar"
137
- m . alias_type "name" , "varchar"
138
- m . alias_type "bpchar" , "varchar"
139
- m . register_type "bool" , Type ::Boolean . new
140
- register_class_with_limit m , "bit" , OID ::Bit
141
- register_class_with_limit m , "varbit" , OID ::BitVarying
142
- m . register_type "date" , OID ::Date . new
143
-
144
- m . register_type "money" , OID ::Money . new
145
- m . register_type "bytea" , OID ::Bytea . new
146
- m . register_type "point" , OID ::Point . new
147
- m . register_type "hstore" , OID ::Hstore . new
148
- m . register_type "json" , Type ::Json . new
149
- m . register_type "jsonb" , OID ::Jsonb . new
150
- m . register_type "cidr" , OID ::Cidr . new
151
- m . register_type "inet" , OID ::Inet . new
152
- m . register_type "uuid" , OID ::Uuid . new
153
- m . register_type "xml" , OID ::Xml . new
154
- m . register_type "tsvector" , OID ::SpecializedString . new ( :tsvector )
155
- m . register_type "macaddr" , OID ::Macaddr . new
156
- m . register_type "citext" , OID ::SpecializedString . new ( :citext )
157
- m . register_type "ltree" , OID ::SpecializedString . new ( :ltree )
158
- m . register_type "line" , OID ::SpecializedString . new ( :line )
159
- m . register_type "lseg" , OID ::SpecializedString . new ( :lseg )
160
- m . register_type "box" , OID ::SpecializedString . new ( :box )
161
- m . register_type "path" , OID ::SpecializedString . new ( :path )
162
- m . register_type "polygon" , OID ::SpecializedString . new ( :polygon )
163
- m . register_type "circle" , OID ::SpecializedString . new ( :circle )
164
-
165
- register_class_with_precision m , "time" , Type ::Time
166
- register_class_with_precision m , "timestamp" , OID ::Timestamp
167
- register_class_with_precision m , "timestamptz" , OID ::TimestampWithTimeZone
168
-
169
- m . register_type "numeric" do |_ , fmod , sql_type |
170
- precision = extract_precision ( sql_type )
171
- scale = extract_scale ( sql_type )
172
-
173
- # The type for the numeric depends on the width of the field,
174
- # so we'll do something special here.
175
- #
176
- # When dealing with decimal columns:
177
- #
178
- # places after decimal = fmod - 4 & 0xffff
179
- # places before decimal = (fmod - 4) >> 16 & 0xffff
180
- if fmod && ( fmod - 4 & 0xffff ) . zero?
181
- # FIXME: Remove this class, and the second argument to
182
- # lookups on PG
183
- Type ::DecimalWithoutScale . new ( precision : precision )
184
- else
185
- OID ::Decimal . new ( precision : precision , scale : scale )
205
+ def load_additional_types ( oids = nil ) # :nodoc:
206
+ initializer = ArjdbcTypeMapInitializer . new ( type_map )
207
+ load_types_queries ( initializer , oids ) do |query |
208
+ execute_and_clear ( query , "SCHEMA" , [ ] ) do |records |
209
+ initializer . run ( records )
186
210
end
187
211
end
188
-
189
- m . register_type "interval" do |*args , sql_type |
190
- precision = extract_precision ( sql_type )
191
- OID ::Interval . new ( precision : precision )
192
- end
193
-
194
- # pgjdbc returns these if the column is auto-incrmenting
195
- m . alias_type 'serial' , 'int4'
196
- m . alias_type 'bigserial' , 'int8'
197
212
end
198
213
199
- def load_additional_types ( type_map , oid = nil ) # :nodoc:
200
- initializer = ArjdbcTypeMapInitializer . new ( type_map )
201
-
202
- if supports_ranges?
203
- query = <<-SQL
204
- SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype,
205
- ns.nspname, ns.nspname = ANY(current_schemas(true)) in_ns
206
- FROM pg_type as t
207
- LEFT JOIN pg_range as r ON oid = rngtypid
208
- JOIN pg_namespace AS ns ON t.typnamespace = ns.oid
209
- SQL
214
+ def load_types_queries ( initializer , oids )
215
+ query = <<~SQL
216
+ SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
217
+ FROM pg_type as t
218
+ LEFT JOIN pg_range as r ON oid = rngtypid
219
+ SQL
220
+ if oids
221
+ yield query + "WHERE t.oid IN (%s)" % oids . join ( ", " )
210
222
else
211
- query = <<-SQL
212
- SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, t.typtype, t.typbasetype,
213
- ns.nspname, ns.nspname = ANY(current_schemas(true)) in_ns
214
- FROM pg_type as t
215
- JOIN pg_namespace AS ns ON t.typnamespace = ns.oid
216
- SQL
223
+ yield query + initializer . query_conditions_for_known_type_names
224
+ yield query + initializer . query_conditions_for_known_type_types
225
+ yield query + initializer . query_conditions_for_array_types
217
226
end
227
+ end
218
228
219
- if oid
220
- if oid . is_a? Numeric || oid . match ( /^\d +$/ )
221
- # numeric OID
222
- query += "WHERE t.oid = %s" % oid
229
+ def update_typemap_for_default_timezone
230
+ if @default_timezone != ActiveRecord . default_timezone && @timestamp_decoder
231
+ decoder_class = ActiveRecord . default_timezone == :utc ?
232
+ PG ::TextDecoder ::TimestampUtc :
233
+ PG ::TextDecoder ::TimestampWithoutTimeZone
223
234
224
- elsif m = oid . match ( /"?(\w +)"?\. "?(\w +)"?/ )
225
- # namespace and type name
226
- query += "WHERE ns.nspname = '%s' AND t.typname = '%s'" % [ m [ 1 ] , m [ 2 ] ]
235
+ @timestamp_decoder = decoder_class . new ( @timestamp_decoder . to_h )
236
+ @connection . type_map_for_results . add_coder ( @timestamp_decoder )
227
237
228
- else
229
- # only type name
230
- query += "WHERE t.typname = '%s' AND ns.nspname = ANY(current_schemas(true))" % oid
231
- end
232
- else
233
- query += initializer . query_conditions_for_initial_load
234
- end
238
+ @default_timezone = ActiveRecord . default_timezone
235
239
236
- records = execute ( query , 'SCHEMA' )
237
- initializer . run ( records )
240
+ # if default timezone has changed, we need to reconfigure the connection
241
+ # (specifically, the session time zone)
242
+ configure_connection
243
+ end
238
244
end
239
245
240
246
def extract_scale ( sql_type )
0 commit comments