add batch remove batch split batch comment selection show hidden batches hide batch highlight batch
db<>fiddle
donate feedback about
By using db<>fiddle, you agree to license everything you submit by Creative Commons CC0.
Help with an interesting Postgres question: Why isn't an Index Only Scan used on a partition accessed via the parent table?.
/* --without the missing test case, this would be enough
CREATE TABLE excllock (
id BIGSERIAL PRIMARY KEY,
myrange INT8RANGE NOT NULL,
key UUID NOT NULL,
isread BOOLEAN NOT NULL,
EXCLUDE USING gist (
myrange WITH &&,
key WITH =,
isread with <>
)
);
*/
CREATE TABLE excllock (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
myrange INT8RANGE NOT NULL,
key UUID NOT NULL,
isread BOOLEAN NOT NULL,
CONSTRAINT e1 EXCLUDE USING gist (
myrange WITH &&,
key WITH = ,
isread with <> --same-type locks can overlap, different lock types can't
),
CONSTRAINT e2 EXCLUDE USING gist (
myrange WITH &&,
key WITH =
)WHERE(NOT isread)--write locks can't overlap write locks
); --combined with `e1`, can't overlap anything
CREATE TABLE
-- ALLOWED read lock on a free range
INSERT INTO excllock (myrange, key, isread)
VALUES ('[1,10)', '00000000-0000-0000-0000-000000000001', TRUE);
INSERT 0 1
-- ALLOWED read lock overlapping read-locked range
INSERT INTO excllock (myrange, key, isread)
VALUES ('[5,15)', '00000000-0000-0000-0000-000000000001', TRUE);
INSERT 0 1
-- CONFLICTING write lock overlapping read-locked range
INSERT INTO excllock (myrange, key, isread)
VALUES ('[1,10)', '00000000-0000-0000-0000-000000000001', FALSE);
ERROR:  conflicting key value violates exclusion constraint "e1"
DETAIL:  Key (myrange, key, isread)=([1,10), 00000000-0000-0000-0000-000000000001, f) conflicts with existing key (myrange, key, isread)=([1,10), 00000000-0000-0000-0000-000000000001, t).
-- ALLOWED write lock on a free range
INSERT INTO excllock (myrange, key, isread)
VALUES ('[100,1000)', '00000000-0000-0000-0000-000000000001', FALSE);
INSERT 0 1
-- CONFLICTING read lock inside the write-locked range
INSERT INTO excllock (myrange, key, isread)
VALUES ('[105,900)', '00000000-0000-0000-0000-000000000001', TRUE);
ERROR:  conflicting key value violates exclusion constraint "e1"
DETAIL:  Key (myrange, key, isread)=([105,900), 00000000-0000-0000-0000-000000000001, t) conflicts with existing key (myrange, key, isread)=([100,1000), 00000000-0000-0000-0000-000000000001, f).
--this test case was missing

-- CONFLICTING write lock overlapping a write-locked range
INSERT INTO excllock (myrange, key, isread)
VALUES ('[105,900)', '00000000-0000-0000-0000-000000000001', FALSE);
ERROR:  conflicting key value violates exclusion constraint "e2"
DETAIL:  Key (myrange, key)=([105,900), 00000000-0000-0000-0000-000000000001) conflicts with existing key (myrange, key)=([100,1000), 00000000-0000-0000-0000-000000000001).
DROP TABLE IF EXISTS excllock;
CREATE TABLE excllock (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
myrange INT8RANGE NOT NULL,
key UUID NOT NULL,
isread BOOLEAN NOT NULL,
CONSTRAINT e1 EXCLUDE USING gist (
myrange WITH &&,
key WITH = ,
isread with <> --same-type locks can overlap, different lock types can't
),
CONSTRAINT e2 EXCLUDE USING gist (
myrange WITH &&,
key WITH =
)WHERE(NOT isread)--write locks can't overlap write locks
); --combined with `e1`, can't overlap anything

select setseed(.43);
drop table if exists timing;
create table timing as select clock_timestamp() as started;
do $f$
declare
i int; loops int:=6e4;
begin
for i in 0..loops loop
begin
execute format(
$q$INSERT INTO excllock (myrange, key, isread)
VALUES ( INT8RANGE(%1$s,%1$s+(random()*500)::bigint,'[)')
,'00000000-0000-0000-0000-000000000001'
,random()>.2)
$q$,(random()*1e4)::bigint);
exception when others then null;
end;
end loop;
end$f$;
DROP TABLE
CREATE TABLE
setseed
SELECT 1
DROP TABLE
SELECT 1
DO
?column?
00:00:13.006983
SELECT 1
count
33123
SELECT 1
pg_total_relation_size pg_size_pretty
11386880 11 MB
SELECT 1
DROP TABLE IF EXISTS excllock;
CREATE TABLE excllock (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
myrange INT8RANGE NOT NULL,
key UUID NOT NULL,
isread BOOLEAN NOT NULL,
EXCLUDE USING gist (
myrange WITH &&,
key WITH =,
(CASE WHEN isread THEN int8range(id, id, '[]')
ELSE int8range(null,null) END) WITH &&
)
);

select setseed(.43);
drop table if exists timing;
create table timing as select clock_timestamp() as started;
do $f$
declare
i int; loops int:=6e4;
begin
for i in 0..loops loop
begin
execute format(
$q$INSERT INTO excllock (myrange, key, isread)
VALUES ( INT8RANGE(%1$s,%1$s+(random()*500)::bigint,'[)')
,'00000000-0000-0000-0000-000000000001'
,random()>.2)
$q$,(random()*1e4)::bigint);
exception when others then null;
end;
end loop;
end$f$;

select clock_timestamp()-started from timing;
select count(*) from excllock;
DROP TABLE
CREATE TABLE
setseed
SELECT 1
DROP TABLE
SELECT 1
DO
?column?
00:00:15.205212
SELECT 1
count
33123
SELECT 1
pg_total_relation_size pg_size_pretty
13320192 13 MB
SELECT 1