Software /
code /
prosody
Comparison
plugins/mod_storage_sql.lua @ 13633:6b84d11aa09b
mod_storage_sql: Detect SQLite3 without UPSERT (or SQLCipher 3.x)
SQLCipher v3.4.1 (the version in Debian 12) is based on SQLite3 v3.15.2,
while UPSERT support was introduced in SQLite3 v3.24.0
This check was not needed before because we v3.24.0 has not been in a
version of Debian we support for a long, long time.
Note however that SQLCipher databases are not compatible across major
versions, upgrading from v3.x to v4.x requires executing a migration.
Attempts at making `prosodyctl mod_storage_sql upgrade` perform such a
migration has not been successful.
Executing the following in the `sqlcipher` tool should do the migration:
PRAGMA key = '<key material>';
PRAGMA cipher_migrate;
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Thu, 23 Jan 2025 19:33:05 +0100 |
parent | 13611:3a23116cf063 |
child | 13634:7209769e88bc |
comparison
equal
deleted
inserted
replaced
13632:844e7bf7b48a | 13633:6b84d11aa09b |
---|---|
34 local row = result_(); | 34 local row = result_(); |
35 if row ~= nil then | 35 if row ~= nil then |
36 return unpack(row); | 36 return unpack(row); |
37 end | 37 end |
38 end, result, nil; | 38 end, result, nil; |
39 end | |
40 | |
41 -- COMPAT Support for UPSERT is not in all versions of all compatible databases. | |
42 local function has_upsert(engine) | |
43 if engine.params.driver == "SQLite3" then | |
44 -- SQLite3 >= 3.24.0 | |
45 return (engine.sqlite_version[2] or 0) >= 24; | |
46 elseif engine.params.driver == "PostgreSQL" then | |
47 -- PostgreSQL >= 9.5 | |
48 -- Versions without support have long since reached end of life. | |
49 return true; | |
50 end | |
51 -- We don't support UPSERT on MySQL/MariaDB, they seem to have a completely different syntax, uncertaint from which versions. | |
52 return false | |
39 end | 53 end |
40 | 54 |
41 local default_params = { driver = "SQLite3" }; | 55 local default_params = { driver = "SQLite3" }; |
42 | 56 |
43 local engine; | 57 local engine; |
223 FROM "prosody" | 237 FROM "prosody" |
224 WHERE "host"=? AND "user"=? AND "store"=? AND "key"=? | 238 WHERE "host"=? AND "user"=? AND "store"=? AND "key"=? |
225 LIMIT 1; | 239 LIMIT 1; |
226 ]]; | 240 ]]; |
227 for key, data in pairs(keydatas) do | 241 for key, data in pairs(keydatas) do |
228 if type(key) == "string" and key ~= "" and engine.params.driver ~= "MySQL" and data ~= self.remove then | 242 if type(key) == "string" and key ~= "" and has_upsert(engine) and data ~= self.remove then |
229 local t, value = assert(serialize(data)); | 243 local t, value = assert(serialize(data)); |
230 engine:insert(upsert_sql, host, username or "", self.store, key, t, value, t, value); | 244 engine:insert(upsert_sql, host, username or "", self.store, key, t, value, t, value); |
231 elseif type(key) == "string" and key ~= "" then | 245 elseif type(key) == "string" and key ~= "" then |
232 engine:delete(delete_sql, | 246 engine:delete(delete_sql, |
233 host, username or "", self.store, key); | 247 host, username or "", self.store, key); |
931 for row in engine:select("PRAGMA compile_options") do | 945 for row in engine:select("PRAGMA compile_options") do |
932 local option = row[1]:lower(); | 946 local option = row[1]:lower(); |
933 local opt, val = option:match("^([^=]+)=(.*)$"); | 947 local opt, val = option:match("^([^=]+)=(.*)$"); |
934 compile_options[opt or option] = tonumber(val) or val or true; | 948 compile_options[opt or option] = tonumber(val) or val or true; |
935 end | 949 end |
950 -- COMPAT Need to check SQLite3 version because SQLCipher 3.x was based on SQLite3 prior to 3.24.0 when UPSERT was introduced | |
951 for row in engine:select("SELECT sqlite_version()") do | |
952 local version = {}; | |
953 for n in row[1]:gmatch("%d+") do | |
954 table.insert(version, tonumber(n)); | |
955 end | |
956 engine.sqlite_version = version; | |
957 end | |
936 engine.sqlite_compile_options = compile_options; | 958 engine.sqlite_compile_options = compile_options; |
937 | 959 |
938 local journal_mode = "delete"; | 960 local journal_mode = "delete"; |
939 for row in engine:select[[PRAGMA journal_mode;]] do | 961 for row in engine:select[[PRAGMA journal_mode;]] do |
940 journal_mode = row[1]; | 962 journal_mode = row[1]; |