Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
115 changes: 115 additions & 0 deletions t/005_logical_replication.pl
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,121 @@
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.
$publisher->wait_for_catchup('lolor_sub');

$pos = $subscriber->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 on subscriber");

# 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