forked from pingcap/discourse
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdb_helper.rb
110 lines (83 loc) · 3.13 KB
/
db_helper.rb
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
110
# frozen_string_literal: true
require_dependency "migration/base_dropper"
class DbHelper
REMAP_SQL ||= <<~SQL
SELECT table_name, column_name
FROM information_schema.columns
WHERE table_schema = :schema
AND (data_type LIKE '%char%' OR data_type LIKE '%text%')
ORDER BY table_name, column_name
SQL
TRIGGERS_SQL ||= <<~SQL
SELECT trigger_name
FROM information_schema.triggers
WHERE trigger_name LIKE '%_readonly'
SQL
def self.remap(from, to, anchor_left: false, anchor_right: false, excluded_tables: [])
like = "#{anchor_left ? '' : "%"}#{from}#{anchor_right ? '' : "%"}"
triggers = DB.query(TRIGGERS_SQL).map(&:trigger_name).to_set
text_columns = Hash.new { |h, k| h[k] = [] }
DB.query(REMAP_SQL, schema: ActiveRecord::Base.connection.instance_eval{|x| @config[:database]}).each do |r|
unless triggers.include?(Migration::BaseDropper.readonly_trigger_name(r.table_name, r.column_name))
text_columns[r.table_name] << r.column_name
end
end
text_columns.each do |table, columns|
next if excluded_tables.include?(table)
set = columns.map do |column|
"#{column} = REPLACE(#{column}, :from, :to)"
end.join(", ")
where = columns.map do |column|
"#{column} IS NOT NULL AND #{column} LIKE :like"
end.join(" OR ")
DB.exec(<<~SQL, from: from, to: to, like: like)
UPDATE #{table}
SET #{set}
WHERE #{where}
SQL
end
SiteSetting.refresh!
end
def self.regexp_replace(pattern, replacement, flags: "gi", match: "~*", excluded_tables: [])
triggers = DB.query(TRIGGERS_SQL).map(&:trigger_name).to_set
text_columns = Hash.new { |h, k| h[k] = [] }
DB.query(REMAP_SQL, schema: ActiveRecord::Base.connection.instance_eval{|x| @config[:database]}).each do |r|
unless triggers.include?(Migration::BaseDropper.readonly_trigger_name(r.table_name, r.column_name))
text_columns[r.table_name] << r.column_name
end
end
text_columns.each do |table, columns|
next if excluded_tables.include?(table)
set = columns.map do |column|
"#{column} = REGEXP_REPLACE(#{column}, :pattern, :replacement, :flags)"
end.join(", ")
where = columns.map do |column|
"#{column} IS NOT NULL AND #{column} #{match} :pattern"
end.join(" OR ")
DB.exec(<<~SQL, pattern: pattern, replacement: replacement, flags: flags, match: match)
UPDATE #{table}
SET #{set}
WHERE #{where}
SQL
end
SiteSetting.refresh!
end
def self.find(needle, anchor_left: false, anchor_right: false, excluded_tables: [])
found = {}
like = "#{anchor_left ? '' : "%"}#{needle}#{anchor_right ? '' : "%"}"
DB.query(REMAP_SQL).each do |r|
next if excluded_tables.include?(r.table_name)
rows = DB.query(<<~SQL, like: like)
SELECT #{r.column_name}
FROM #{r.table_name}
WHERE #{r.column_name} LIKE :like
SQL
if rows.size > 0
found["#{r.table_name}.#{r.column_name}"] = rows.map do |row|
row.public_send(r.column_name)
end
end
end
found
end
end