Software /
code /
prosody
Comparison
tools/migration/migrator/prosody_sql.lua @ 8063:605fa6bfafd1
migrator.prosody_sql: Switch to util.sql (#635)
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Fri, 07 Apr 2017 13:16:12 +0200 |
parent | 7881:4e3067272fae |
child | 8064:ffb36d1ae23b |
comparison
equal
deleted
inserted
replaced
8062:739bb455cafd | 8063:605fa6bfafd1 |
---|---|
1 | 1 |
2 local assert = assert; | 2 local assert = assert; |
3 local have_DBI, DBI = pcall(require,"DBI"); | 3 local have_DBI = pcall(require,"DBI"); |
4 local print = print; | 4 local print = print; |
5 local type = type; | 5 local type = type; |
6 local next = next; | 6 local next = next; |
7 local pairs = pairs; | 7 local pairs = pairs; |
8 local t_sort = table.sort; | 8 local t_sort = table.sort; |
13 | 13 |
14 if not have_DBI then | 14 if not have_DBI then |
15 error("LuaDBI (required for SQL support) was not found, please see http://prosody.im/doc/depends#luadbi", 0); | 15 error("LuaDBI (required for SQL support) was not found, please see http://prosody.im/doc/depends#luadbi", 0); |
16 end | 16 end |
17 | 17 |
18 local sql = require "util.sql"; | |
18 | 19 |
19 local function create_table(connection, params) | 20 local function create_table(engine, name) -- luacheck: ignore 431/engine |
20 local create_sql = "CREATE TABLE `prosody` (`host` TEXT, `user` TEXT, `store` TEXT, `key` TEXT, `type` TEXT, `value` TEXT);"; | 21 local Table, Column, Index = sql.Table, sql.Column, sql.Index; |
21 if params.driver == "PostgreSQL" then | |
22 create_sql = create_sql:gsub("`", "\""); | |
23 elseif params.driver == "MySQL" then | |
24 create_sql = create_sql:gsub("`value` TEXT", "`value` MEDIUMTEXT"); | |
25 end | |
26 | 22 |
27 local stmt = connection:prepare(create_sql); | 23 local ProsodyTable = Table { |
28 if stmt then | 24 name= name or "prosody"; |
29 local ok = stmt:execute(); | 25 Column { name="host", type="TEXT", nullable=false }; |
30 local commit_ok = connection:commit(); | 26 Column { name="user", type="TEXT", nullable=false }; |
31 if ok and commit_ok then | 27 Column { name="store", type="TEXT", nullable=false }; |
32 local index_sql = "CREATE INDEX `prosody_index` ON `prosody` (`host`, `user`, `store`, `key`)"; | 28 Column { name="key", type="TEXT", nullable=false }; |
33 if params.driver == "PostgreSQL" then | 29 Column { name="type", type="TEXT", nullable=false }; |
34 index_sql = index_sql:gsub("`", "\""); | 30 Column { name="value", type="MEDIUMTEXT", nullable=false }; |
35 elseif params.driver == "MySQL" then | 31 Index { name="prosody_index", "host", "user", "store", "key" }; |
36 index_sql = index_sql:gsub("`([,)])", "`(20)%1"); | 32 }; |
37 end | 33 engine:transaction(function() |
38 local stmt, err = connection:prepare(index_sql); | 34 ProsodyTable:create(engine); |
39 local ok, commit_ok, commit_err; | 35 end); |
40 if stmt then | 36 |
41 ok, err = assert(stmt:execute()); | |
42 commit_ok, commit_err = assert(connection:commit()); | |
43 end | |
44 elseif params.driver == "MySQL" then -- COMPAT: Upgrade tables from 0.8.0 | |
45 -- Failed to create, but check existing MySQL table here | |
46 local stmt = connection:prepare("SHOW COLUMNS FROM prosody WHERE Field='value' and Type='text'"); | |
47 local ok = stmt:execute(); | |
48 local commit_ok = connection:commit(); | |
49 if ok and commit_ok then | |
50 if stmt:rowcount() > 0 then | |
51 local stmt = connection:prepare("ALTER TABLE prosody MODIFY COLUMN `value` MEDIUMTEXT"); | |
52 local ok = stmt:execute(); | |
53 local commit_ok = connection:commit(); | |
54 if ok and commit_ok then | |
55 print("Database table automatically upgraded"); | |
56 end | |
57 end | |
58 repeat until not stmt:fetch(); | |
59 end | |
60 end | |
61 end | |
62 end | 37 end |
63 | 38 |
64 local function serialize(value) | 39 local function serialize(value) |
65 local t = type(value); | 40 local t = type(value); |
66 if t == "string" or t == "boolean" or t == "number" then | 41 if t == "string" or t == "boolean" or t == "number" then |
108 end | 83 end |
109 return userdata; | 84 return userdata; |
110 end | 85 end |
111 | 86 |
112 local function reader(input) | 87 local function reader(input) |
113 local dbh = assert(DBI.Connect( | 88 local engine = assert(sql:create_engine(input); |
114 assert(input.driver, "no input.driver specified"), | |
115 assert(input.database, "no input.database specified"), | |
116 input.username, input.password, | |
117 input.host, input.port | |
118 )); | |
119 assert(dbh:ping()); | |
120 local stmt = assert(dbh:prepare("SELECT * FROM prosody")); | |
121 assert(stmt:execute()); | |
122 local keys = {"host", "user", "store", "key", "type", "value"}; | 89 local keys = {"host", "user", "store", "key", "type", "value"}; |
123 local f,s,val = stmt:rows(true); | 90 assert(engine:connect()); |
91 local f,s,val = assert(engine:select("SELECT `host`, `user`, `store`, `key`, `type`, `value` FROM `prosody`;")); | |
124 -- get SQL rows, sorted | 92 -- get SQL rows, sorted |
125 local iter = mtools.sorted { | 93 local iter = mtools.sorted { |
126 reader = function() val = f(s, val); return val; end; | 94 reader = function() val = f(s, val); return val; end; |
127 filter = function(x) | 95 filter = function(x) |
128 for i=1,#keys do | 96 for i=1,#keys do |
129 if not x[keys[i]] then return false; end -- TODO log error, missing field | 97 x[ keys[i] ] = x[i]; |
130 end | 98 end |
131 if x.host == "" then x.host = nil; end | 99 if x.host == "" then x.host = nil; end |
132 if x.user == "" then x.user = nil; end | 100 if x.user == "" then x.user = nil; end |
133 if x.store == "" then x.store = nil; end | 101 if x.store == "" then x.store = nil; end |
134 return x; | 102 return x; |
152 return x and decode_user(x); | 120 return x and decode_user(x); |
153 end; | 121 end; |
154 end | 122 end |
155 | 123 |
156 local function writer(output, iter) | 124 local function writer(output, iter) |
157 local dbh = assert(DBI.Connect( | 125 local engine = assert(sql:create_engine(output, function (engine) -- luacheck: ignore 431/engine |
158 assert(output.driver, "no output.driver specified"), | 126 create_table(engine); |
159 assert(output.database, "no output.database specified"), | 127 end)); |
160 output.username, output.password, | 128 assert(engine:connect()); |
161 output.host, output.port | 129 assert(engine:delete("DELETE FROM prosody")); |
162 )); | |
163 assert(dbh:ping()); | |
164 create_table(dbh, output); | |
165 local stmt = assert(dbh:prepare("SELECT * FROM prosody")); | |
166 assert(stmt:execute()); | |
167 local stmt = assert(dbh:prepare("DELETE FROM prosody")); | |
168 assert(stmt:execute()); | |
169 local insert_sql = "INSERT INTO `prosody` (`host`,`user`,`store`,`key`,`type`,`value`) VALUES (?,?,?,?,?,?)"; | 130 local insert_sql = "INSERT INTO `prosody` (`host`,`user`,`store`,`key`,`type`,`value`) VALUES (?,?,?,?,?,?)"; |
170 if output.driver == "PostgreSQL" then | |
171 insert_sql = insert_sql:gsub("`", "\""); | |
172 end | |
173 local insert = assert(dbh:prepare(insert_sql)); | |
174 | 131 |
175 return function(item) | 132 return function(item) |
176 if not item then assert(dbh:commit()) return dbh:close(); end -- end of input | 133 if not item then return end -- end of input |
177 local host = item.host or ""; | 134 local host = item.host or ""; |
178 local user = item.user or ""; | 135 local user = item.user or ""; |
179 for store, data in pairs(item.stores) do | 136 for store, data in pairs(item.stores) do |
180 -- TODO transactions | 137 -- TODO transactions |
181 local extradata = {}; | 138 local extradata = {}; |
182 for key, value in pairs(data) do | 139 for key, value in pairs(data) do |
183 if type(key) == "string" and key ~= "" then | 140 if type(key) == "string" and key ~= "" then |
184 local t, value = assert(serialize(value)); | 141 local t, value = assert(serialize(value)); |
185 local ok, err = assert(insert:execute(host, user, store, key, t, value)); | 142 local ok, err = assert(engine:insert(insert_sql, host, user, store, key, t, value)); |
186 else | 143 else |
187 extradata[key] = value; | 144 extradata[key] = value; |
188 end | 145 end |
189 end | 146 end |
190 if next(extradata) ~= nil then | 147 if next(extradata) ~= nil then |
191 local t, extradata = assert(serialize(extradata)); | 148 local t, extradata = assert(serialize(extradata)); |
192 local ok, err = assert(insert:execute(host, user, store, "", t, extradata)); | 149 local ok, err = assert(engine:insert(insert_sql, host, user, store, "", t, extradata)); |
193 end | 150 end |
194 end | 151 end |
195 end; | 152 end; |
196 end | 153 end |
197 | 154 |