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 |