Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docker/Dockerfile.tester
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.22.4
FROM debian:bookworm

RUN apt -y update && \
apt -y install \
Expand Down
9 changes: 0 additions & 9 deletions docker/run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,3 @@ cd /home/pgedge/lolor/tests/python
cp ../../docker/test-configs/test.properties.py test.properties
python3 lolor_tests.py -v &>> /home/pgedge/lolor/tests/out.txt

sleep 10

#==================== Golang tests ====================

cd /home/pgedge/lolor/tests/go
go get github.com/jackc/pgx/v5
go get github.com/magiconair/properties
cp ../../docker/test-configs/test.properties.go test.properties
go test -v &>> /home/pgedge/lolor/tests/out.txt
9 changes: 0 additions & 9 deletions docker/test-configs/test.properties.go

This file was deleted.

149 changes: 149 additions & 0 deletions expected/lolor.out
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,155 @@ SELECT lo_close(:fd);
0
(1 row)

END;
--
-- lo_lseek: seek to an offset, overwrite partial content, verify result.
-- Expected: first 15 chars unchanged, next 11 replaced by '<ADDEDDATA>',
-- trailing chars from original string preserved.
--
SELECT lo_creat(-1) AS loid \gset
BEGIN;
SELECT lo_open(:loid, x'60000'::int) AS fd \gset
SELECT lowrite(:fd, '0123456789abcdefghijklmnopqrstuvwxyz');
lowrite
---------
36
(1 row)

SELECT lo_lseek(:fd, 15, 0);
lo_lseek
----------
15
(1 row)

SELECT lowrite(:fd, '<ADDEDDATA>');
lowrite
---------
11
(1 row)

SELECT lo_close(:fd);
lo_close
----------
0
(1 row)

END;
BEGIN;
SELECT lo_open(:loid, 262144) AS fd \gset
SELECT convert_from(loread(:fd, 1024), 'UTF8');
convert_from
--------------------------------------
0123456789abcde<ADDEDDATA>qrstuvwxyz
(1 row)

SELECT lo_close(:fd);
lo_close
----------
0
(1 row)

END;
--
-- lo_tell: verify cursor position before and after a write.
-- Expected: position 0 before write, position 11 after writing 11 bytes;
-- content has first 11 chars overwritten by '<ADDEDDATA>'.
--
SELECT lo_creat(-1) AS loid \gset
BEGIN;
SELECT lo_open(:loid, x'60000'::int) AS fd \gset
SELECT lowrite(:fd, '0123456789abcdefghijklmnopqrstuvwxyz');
lowrite
---------
36
(1 row)

SELECT lo_lseek(:fd, 0, 0);
lo_lseek
----------
0
(1 row)

SELECT lo_tell(:fd);
lo_tell
---------
0
(1 row)

SELECT lowrite(:fd, '<ADDEDDATA>');
lowrite
---------
11
(1 row)

SELECT lo_tell(:fd);
lo_tell
---------
11
(1 row)

SELECT lo_close(:fd);
lo_close
----------
0
(1 row)

END;
BEGIN;
SELECT lo_open(:loid, 262144) AS fd \gset
SELECT convert_from(loread(:fd, 1024), 'UTF8');
convert_from
--------------------------------------
<ADDEDDATA>bcdefghijklmnopqrstuvwxyz
(1 row)

SELECT lo_close(:fd);
lo_close
----------
0
(1 row)

END;
--
-- lo_truncate: truncate to 10 bytes, verify only the prefix survives.
-- Expected: only "0123456789" readable after truncation.
--
SELECT lo_creat(-1) AS loid \gset
BEGIN;
SELECT lo_open(:loid, x'60000'::int) AS fd \gset
SELECT lowrite(:fd, '0123456789abcdefghijklmnopqrstuvwxyz');
lowrite
---------
36
(1 row)

SELECT lo_truncate(:fd, 10);
lo_truncate
-------------
0
(1 row)

SELECT lo_close(:fd);
lo_close
----------
0
(1 row)

END;
BEGIN;
SELECT lo_open(:loid, 262144) AS fd \gset
SELECT convert_from(loread(:fd, 1024), 'UTF8');
convert_from
--------------
0123456789
(1 row)

SELECT lo_close(:fd);
lo_close
----------
0
(1 row)

END;
DROP EXTENSION lolor;
-- Check extension upgrade
Expand Down
57 changes: 57 additions & 0 deletions sql/lolor.sql
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,63 @@ SELECT convert_from(loread(:fd, 1024), 'UTF8');
SELECT lo_close(:fd);
END;

--
-- lo_lseek: seek to an offset, overwrite partial content, verify result.
-- Expected: first 15 chars unchanged, next 11 replaced by '<ADDEDDATA>',
-- trailing chars from original string preserved.
--
SELECT lo_creat(-1) AS loid \gset
BEGIN;
SELECT lo_open(:loid, x'60000'::int) AS fd \gset
SELECT lowrite(:fd, '0123456789abcdefghijklmnopqrstuvwxyz');
SELECT lo_lseek(:fd, 15, 0);
SELECT lowrite(:fd, '<ADDEDDATA>');
SELECT lo_close(:fd);
END;
BEGIN;
SELECT lo_open(:loid, 262144) AS fd \gset
SELECT convert_from(loread(:fd, 1024), 'UTF8');
SELECT lo_close(:fd);
END;

--
-- lo_tell: verify cursor position before and after a write.
-- Expected: position 0 before write, position 11 after writing 11 bytes;
-- content has first 11 chars overwritten by '<ADDEDDATA>'.
--
SELECT lo_creat(-1) AS loid \gset
BEGIN;
SELECT lo_open(:loid, x'60000'::int) AS fd \gset
SELECT lowrite(:fd, '0123456789abcdefghijklmnopqrstuvwxyz');
SELECT lo_lseek(:fd, 0, 0);
SELECT lo_tell(:fd);
SELECT lowrite(:fd, '<ADDEDDATA>');
SELECT lo_tell(:fd);
SELECT lo_close(:fd);
END;
BEGIN;
SELECT lo_open(:loid, 262144) AS fd \gset
SELECT convert_from(loread(:fd, 1024), 'UTF8');
SELECT lo_close(:fd);
END;

--
-- lo_truncate: truncate to 10 bytes, verify only the prefix survives.
-- Expected: only "0123456789" readable after truncation.
--
SELECT lo_creat(-1) AS loid \gset
BEGIN;
SELECT lo_open(:loid, x'60000'::int) AS fd \gset
SELECT lowrite(:fd, '0123456789abcdefghijklmnopqrstuvwxyz');
SELECT lo_truncate(:fd, 10);
SELECT lo_close(:fd);
END;
BEGIN;
SELECT lo_open(:loid, 262144) AS fd \gset
SELECT convert_from(loread(:fd, 1024), 'UTF8');
SELECT lo_close(:fd);
END;

DROP EXTENSION lolor;

-- Check extension upgrade
Expand Down
102 changes: 102 additions & 0 deletions t/005_logical_replication.pl
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,108 @@
is($result, 'post-subscription LO',
"Post-subscription LO replicated via logical streaming");

# lo_lseek: seek to offset 15, overwrite 11 bytes, verify on both nodes
$publisher->safe_psql('postgres',
qq(SELECT lo_from_bytea(3, '0123456789abcdefghijklmnopqrstuvwxyz')));
$publisher->safe_psql('postgres', qq(
BEGIN;
SELECT lo_open(3, x'60000'::int) AS fd \\gset
SELECT lo_lseek(:fd, 15, 0);
SELECT lowrite(:fd, '<ADDEDDATA>');
SELECT lo_close(:fd);
END;
));
$publisher->wait_for_catchup('lolor_sub');

$result = $publisher->safe_psql('postgres', qq(
BEGIN;
SELECT lo_open(3, 262144) AS fd \\gset
SELECT convert_from(loread(:fd, 1024), 'UTF8');
END;
));
is($result, '0123456789abcde<ADDEDDATA>qrstuvwxyz',
"lo_lseek: overwritten content correct on publisher");

$result = $subscriber->safe_psql('postgres', qq(
BEGIN;
SELECT lo_open(3, 262144) AS fd \\gset
SELECT convert_from(loread(:fd, 1024), 'UTF8');
END;
));
is($result, '0123456789abcde<ADDEDDATA>qrstuvwxyz',
"lo_lseek: seeked/overwritten content replicated to subscriber");

# lo_tell: verify cursor positions (publisher only — tell is a local cursor op).
# Two separate transactions: first confirms position is 0 on a fresh open;
# second confirms position advances to 11 after writing 11 bytes.
$publisher->safe_psql('postgres',
qq(SELECT lo_from_bytea(4, '0123456789abcdefghijklmnopqrstuvwxyz')));

# \gset suppresses lo_open output; only lo_tell and lo_close print a row each.
my $pos = $publisher->safe_psql('postgres', qq(
BEGIN;
SELECT lo_open(4, 262144) AS fd \\gset
SELECT lo_tell(:fd);
SELECT lo_close(:fd);
END;
));
is((split /\n/, $pos)[0], '0', "lo_tell: position at open is 0");

# lowrite prints one row, then lo_tell prints one row, then lo_close one row.
$pos = $publisher->safe_psql('postgres', qq(
BEGIN;
SELECT lo_open(4, x'60000'::int) AS fd \\gset
SELECT lowrite(:fd, '<ADDEDDATA>');
SELECT lo_tell(:fd);
SELECT lo_close(:fd);
END;
));
is((split /\n/, $pos)[1], '11', "lo_tell: position after 11-byte write is 11");

Comment thread
danolivo marked this conversation as resolved.
# lo_truncate: truncate to 10 bytes, verify prefix on both nodes
$publisher->safe_psql('postgres',
qq(SELECT lo_from_bytea(5, '0123456789abcdefghijklmnopqrstuvwxyz')));
$publisher->safe_psql('postgres', qq(
BEGIN;
SELECT lo_open(5, x'60000'::int) AS fd \\gset
SELECT lo_truncate(:fd, 10);
SELECT lo_close(:fd);
END;
));
$publisher->wait_for_catchup('lolor_sub');

$result = $publisher->safe_psql('postgres', qq(
BEGIN;
SELECT lo_open(5, 262144) AS fd \\gset
SELECT convert_from(loread(:fd, 1024), 'UTF8');
END;
));
is($result, '0123456789', "lo_truncate: only prefix survives on publisher");

$result = $subscriber->safe_psql('postgres', qq(
BEGIN;
SELECT lo_open(5, 262144) AS fd \\gset
SELECT convert_from(loread(:fd, 1024), 'UTF8');
END;
));
is($result, '0123456789', "lo_truncate: truncated content replicated to subscriber");

# Catalog consistency: pg_largeobject_metadata and pg_largeobject row counts
# must match between publisher and subscriber after all operations.
my $pub_meta = $publisher->safe_psql('postgres',
"SELECT count(*) FROM lolor.pg_largeobject_metadata");
my $sub_meta = $subscriber->safe_psql('postgres',
"SELECT count(*) FROM lolor.pg_largeobject_metadata");
is($sub_meta, $pub_meta,
"catalog consistency: pg_largeobject_metadata row count matches across nodes");

my $pub_lo = $publisher->safe_psql('postgres',
"SELECT count(*) FROM lolor.pg_largeobject");
my $sub_lo = $subscriber->safe_psql('postgres',
"SELECT count(*) FROM lolor.pg_largeobject");
is($sub_lo, $pub_lo,
"catalog consistency: pg_largeobject row count matches across nodes");

$subscriber->stop;
$publisher->stop;

Expand Down
Loading
Loading