-- SQL support for fake lobs for ACS/Postgres.
-- Don Baccus February 2000

-- for each user table my_table in which you want to stuff large
-- amounts of data:

-- define a column "lob integer references lobs"
-- do "create trigger my_table_lob_trig before delete or update or insert
-- on my_table for each row execute procedure on_lob_ref()"

-- to initialize a row's lob column,  use empty_lob():

-- insert into my_table (lob) values(empty_lob());

-- deletes and updates on my_table use reference count information
-- to delete data from lobs and lob_data when appropriate.


create sequence lob_sequence;

create table lobs (
	lob_id			integer not null primary key,
	refcount		integer not null default 0
);

create function on_lobs_delete() returns opaque as '
begin
	delete from lob_data where lob_id = old.lob_id;
	return old;
end;' language 'plpgsql';

create trigger lobs_delete_trig before delete on lobs
for each row execute procedure on_lobs_delete();

create table lob_data (
	lob_id			integer not null references lobs,
	segment			integer not null,
	byte_len		integer not null,
	data			bytea not null,
	primary key (lob_id, segment)
);

create index lob_data_index on lob_data(lob_id);

-- Note - race conditions might cause problems here, but I 
-- couldn't get locking to work consistently between PG 6.5
-- and PG 7.0.  The ACS doesn't share LOBs between tables
-- or rows within a table anyway, I don't think/hope.

create function on_lob_ref() returns opaque as '
begin
	if TG_OP = ''UPDATE'' then
		if new.lob = old.lob then
			return new;
		end if;
	end if;

	if TG_OP = ''INSERT'' or TG_OP = ''UPDATE'' then
		if new.lob is not null then
			insert into lobs select new.lob, 0
				where 0 = (select count(*) from lobs where lob_id = new.lob);
			update lobs set refcount = refcount + 1 where lob_id = new.lob;
		end if;
	end if;

	if TG_OP <> ''INSERT'' then
		if old.lob is not null then
			update lobs set refcount = refcount - 1 where lob_id = old.lob;
			delete from lobs where lob_id = old.lob and refcount = 0;
		end if;
	end if;

	if TG_OP = ''INSERT'' or TG_OP = ''UPDATE'' then return new;
	else return old;
	end if;

end;' language 'plpgsql';

create function empty_lob() returns integer as '
begin
	return nextval(''lob_sequence'');
end;' language 'plpgsql';
