diff --git a/docker/postgres/init/002-fmsgd-dd.sql b/docker/postgres/init/002-fmsgd-dd.sql index f5ded0d..0519f7c 100644 --- a/docker/postgres/init/002-fmsgd-dd.sql +++ b/docker/postgres/init/002-fmsgd-dd.sql @@ -413,6 +413,11 @@ declare message_id bigint; frozen boolean; begin + -- A message is removed from this host only on purpose: a transaction that + -- sets fmsg.purge (SET LOCAL fmsg.purge = 'on') may delete its parts, so + -- the message can then be deleted. Once its row is gone, a reply to it is + -- rejected as parent not found. + if TG_OP='DELETE' and current_setting('fmsg.purge', true) = 'on' then return OLD; end if; -- Delivery and read receipts do not change a protocol recipient. if TG_OP='UPDATE' then if TG_TABLE_NAME='msg_to' then diff --git a/docker/postgres/init/002-fmsgid-dd.sql b/docker/postgres/init/002-fmsgid-dd.sql index 193b8f1..1376c1d 100644 --- a/docker/postgres/init/002-fmsgid-dd.sql +++ b/docker/postgres/init/002-fmsgid-dd.sql @@ -59,7 +59,7 @@ create table if not exists address_tx ( id bigserial primary key, address_lower text not null references address (address_lower) , ts timestamptz not null, - type smallint not null, -- 1 for recv, 2 for send + type smallint not null, -- 1 recv, 2 send, 3 recv released, 4 send released size int not null ); diff --git a/docker/postgres/init/003-fmsg-webapi-dd.sql b/docker/postgres/init/003-fmsg-webapi-dd.sql index aa17f29..eba7b67 100644 --- a/docker/postgres/init/003-fmsg-webapi-dd.sql +++ b/docker/postgres/init/003-fmsg-webapi-dd.sql @@ -74,3 +74,37 @@ CREATE INDEX IF NOT EXISTS fmsg_api_sub_account_sub_idx CREATE UNIQUE INDEX IF NOT EXISTS fmsg_api_sub_account_owner_sub_unique ON fmsg_api_sub_account ((lower(owner_addr)), (lower(sub_addr))) WHERE agent <> ''; + +-- Trash: what each address has deleted. A row marks one message for one +-- address (lower-cased). thread marks the whole thread below that message; +-- time_purged means deleted for good: never shown to that address again, +-- nor anything that replies to it. Rows go with their message when it is +-- removed from the host. +CREATE TABLE IF NOT EXISTS fmsg_api_trash ( + addr text NOT NULL, + msg_id bigint NOT NULL REFERENCES msg (id) ON DELETE CASCADE, + thread boolean NOT NULL DEFAULT false, + time_deleted double precision NOT NULL, + time_purged double precision, + PRIMARY KEY (addr, msg_id) +); + +-- fmsg_api_trash_state is where a message stands for an address: 'purged' +-- when it or an ancestor is deleted for good, 'thread' when it or an ancestor +-- carries a thread mark, 'message' when it is deleted itself, NULL when it +-- isn't deleted. addr must be lower-cased. +CREATE OR REPLACE FUNCTION fmsg_api_trash_state(p_addr text, p_msg bigint) RETURNS text +LANGUAGE sql STABLE AS $$ + WITH RECURSIVE up(id, depth) AS ( + SELECT p_msg, 0 + UNION ALL + SELECT m.pid, up.depth + 1 FROM msg m JOIN up ON m.id = up.id + WHERE m.pid IS NOT NULL AND up.depth < 1000 + ) + SELECT CASE + WHEN bool_or(t.time_purged IS NOT NULL) THEN 'purged' + WHEN bool_or(t.thread) THEN 'thread' + WHEN bool_or(up.depth = 0) THEN 'message' + END + FROM up JOIN fmsg_api_trash t ON t.addr = p_addr AND t.msg_id = up.id +$$;