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
110
|
# File 'lib/schema_plus_pg_indexes/middleware/postgresql/schema.rb', line 20
def implement(env)
result = env.connection.query(<<-SQL, 'SCHEMA')
SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid,
m.amname, pg_get_expr(d.indpred, t.oid) as conditions, pg_get_expr(d.indexprs, t.oid) as expression,
d.indclass
FROM pg_class t
INNER JOIN pg_index d ON t.oid = d.indrelid
INNER JOIN pg_class i ON d.indexrelid = i.oid
INNER JOIN pg_am m ON i.relam = m.oid
WHERE i.relkind = 'i'
AND d.indisprimary = 'f'
AND t.relname = '#{table_name_without_namespace(env.table_name)}'
AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = #{namespace_sql(env.table_name)} )
ORDER BY i.relname
SQL
env.index_definitions += result.map do |(index_name, unique, indkey, inddef, oid, using, conditions, expression, indclass)|
index_keys = indkey.split(" ")
opclasses = indclass.split(" ")
rows = env.connection.query(<<-SQL, 'SCHEMA')
SELECT CAST(a.attnum as VARCHAR), a.attname, t.typname
FROM pg_attribute a
INNER JOIN pg_type t ON a.atttypid = t.oid
WHERE a.attrelid = #{oid}
SQL
columns = {}
types = {}
rows.each do |num, name, type|
columns[num] = name
types[name] = type
end
column_names = columns.values_at(*index_keys).compact
case_sensitive = true
if expression
rexp_lower = %r{\blower\(\(?([^)]+)(\)::text)?\)}
if expression.match /\A#{rexp_lower}(?:, #{rexp_lower})*\z/i
case_insensitive_columns = expression.scan(rexp_lower).map(&:first).select{|column| %W[char varchar text].include? types[column]}
if case_insensitive_columns.any?
case_sensitive = false
column_names = index_keys.map { |index_key|
index_key == '0' ? case_insensitive_columns.shift : columns[index_key]
}.compact | column_names
end
end
end
get_opclass_names(env, opclasses)
operator_classes = Hash[
index_keys.zip(opclasses).map { |index_key, opclass| [columns[index_key], @opclass_names[opclass]] }
]
operator_classes.delete_if{|k,v| v.nil?}
desc_order_columns = inddef.scan(/(\w+) DESC/).flatten
orders = desc_order_columns.any? ? Hash[column_names.map {|column| [column, desc_order_columns.include?(column) ? :desc : :asc]}] : {}
::ActiveRecord::ConnectionAdapters::IndexDefinition.new(env.table_name, column_names,
:name => index_name,
:unique => (unique == 't'),
:orders => orders,
:where => conditions,
:case_sensitive => case_sensitive,
:using => using.downcase == "btree" ? nil : using.to_sym,
:operator_classes => operator_classes,
:expression => expression)
end
end
|