create table users ( id bigserial not null, ip_address cidr not null, created date default now()::date not null, primary key (id), unique (ip_address) ); create table user_colors ( user_id bigint not null, color integer not null, primary key (user_id, color), foreign key (user_id) references users ); create table pixels ( x smallint not null, y smallint not null, color integer not null, user_id bigint not null, last_update timestamp default now() not null, primary key (x, y), foreign key (user_id) references users ); create table history ( id bigserial not null, user_id bigint not null, time timestamp default now() not null, primary key (id), foreign key (user_id) references users ); create table requests ( id bigserial not null, ip_address cidr not null, method text not null, url text not null, is_secure bool not null, user_agent character varying (4096), referer character varying (2048), time timestamp default now() not null, primary key (id) ); create function pixels_history() returns trigger as $$ begin insert into history ( user_id ) values ( new.user_id ); return new; end; $$ language plpgsql; create trigger pixels_history after insert or update on pixels for each row execute procedure pixels_history(); create procedure put_pixel( _x smallint, _y smallint, _color integer, _ip_address cidr ) as $$ declare _user_id bigint; begin insert into users ( ip_address ) values ( _ip_address ) on conflict ( ip_address ) do nothing; _user_id = ( select users.id from users where users.ip_address = _ip_address ); insert into pixels ( x, y, color, user_id, last_update ) values ( _x, _y, _color, _user_id, default ) on conflict ( x, y ) do update set color = excluded.color, user_id = excluded.user_id, last_update = excluded.last_update; end; $$ language plpgsql; -- truncate pixels;