1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
module ActiveRecord
module ConnectionAdapters
module PostgreSQL
module OID # :nodoc:
# This class uses the data from PostgreSQL pg_type table to build
# the OID -> Type mapping.
# - OID is an integer representing the type.
# - Type is an OID::Type object.
# This class has side effects on the +store+ passed during initialization.
class TypeMapInitializer # :nodoc:
def initialize(store)
@store = store
end
def run(records)
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".freeze }
enums, nodes = nodes.partition { |row| row["typtype"] == "e".freeze }
domains, nodes = nodes.partition { |row| row["typtype"] == "d".freeze }
arrays, nodes = nodes.partition { |row| row["typinput"] == "array_in".freeze }
composites, nodes = nodes.partition { |row| row["typelem"].to_i != 0 }
mapped.each { |row| register_mapped_type(row) }
enums.each { |row| register_enum_type(row) }
domains.each { |row| register_domain_type(row) }
arrays.each { |row| register_array_type(row) }
ranges.each { |row| register_range_type(row) }
composites.each { |row| register_composite_type(row) }
end
def query_conditions_for_initial_load(type_map)
known_type_names = type_map.keys.map { |n| "'#{n}'" }
known_type_types = %w('r' 'e' 'd')
<<-SQL % [known_type_names.join(", "), known_type_types.join(", ")]
WHERE
t.typname IN (%s)
OR t.typtype IN (%s)
OR t.typinput = 'array_in(cstring,oid,integer)'::regprocedure
OR t.typelem != 0
SQL
end
private
def register_mapped_type(row)
alias_type row["oid"], row["typname"]
end
def register_enum_type(row)
register row["oid"], OID::Enum.new
end
def register_array_type(row)
register_with_subtype(row["oid"], row["typelem"].to_i) do |subtype|
OID::Array.new(subtype, row["typdelim"])
end
end
def register_range_type(row)
register_with_subtype(row["oid"], row["rngsubtype"].to_i) do |subtype|
OID::Range.new(subtype, row["typname"].to_sym)
end
end
def register_domain_type(row)
if base_type = @store.lookup(row["typbasetype"].to_i)
register row["oid"], base_type
else
warn "unknown base type (OID: #{row["typbasetype"]}) for domain #{row["typname"]}."
end
end
def register_composite_type(row)
if subtype = @store.lookup(row["typelem"].to_i)
register row["oid"], OID::Vector.new(row["typdelim"], subtype)
end
end
def register(oid, oid_type = nil, &block)
oid = assert_valid_registration(oid, oid_type || block)
if block_given?
@store.register_type(oid, &block)
else
@store.register_type(oid, oid_type)
end
end
def alias_type(oid, target)
oid = assert_valid_registration(oid, target)
@store.alias_type(oid, target)
end
def register_with_subtype(oid, target_oid)
if @store.key?(target_oid)
register(oid) do |_, *args|
yield @store.lookup(target_oid, *args)
end
end
end
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
end
end
end
|