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 Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ MODULE_big = lolor

EXTENSION = lolor
DATA = lolor--1.0.sql \
lolor--1.0--1.2.1.sql
lolor--1.0--1.2.1.sql lolor--1.2.1--1.2.2.sql
PGFILEDESC = "lolor - drop in large objects replacement for logical replication"

OBJS = src/lolor.o src/lolor_fsstubs.o src/lolor_inv_api.o src/lolor_largeobject.o
Expand Down
109 changes: 108 additions & 1 deletion expected/lolor.out
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
-- Basic checks
\set VERBOSITY terse
LOAD 'lolor';
SET lolor.node = 1;
CREATE EXTENSION lolor;
SELECT lo_creat(-1) AS loid \gset
SELECT lo_from_bytea(:loid, 'Example large object'); -- ERROR
ERROR: duplicate key value violates unique constraint "pg_largeobject_metadata_pkey"
DETAIL: Key (oid)=(262769) already exists.
BEGIN;
SELECT lo_open(:loid, x'60000'::int) AS fd \gset
SELECT lowrite(:fd, 'Example large object');
Expand Down Expand Up @@ -68,3 +68,110 @@ SELECT lo_close(:fd);

END;
DROP EXTENSION lolor;
-- Check extension upgrade
CREATE EXTENSION lolor VERSION '1.0';
SELECT lo_creat(-1) AS loid \gset
ALTER EXTENSION lolor UPDATE TO '1.2.1';
BEGIN;
SELECT lo_open(:loid, x'60000'::int) AS fd \gset
SELECT lowrite(:fd, 'Example large object');
lowrite
---------
20
(1 row)

END;
ALTER EXTENSION lolor UPDATE TO '1.2.2';
BEGIN;
SELECT lo_open(:loid, 262144) AS fd \gset
SELECT convert_from(loread(:fd, 1024), 'UTF8');
convert_from
----------------------
Example large object
(1 row)

END;
--
-- Basic checks for enable/disable routines.
--
SELECT lolor.enable(); -- ERROR
NOTICE: lolor still not disabled
enable
--------
f
(1 row)

SELECT lo_from_bytea(1, 'Example large object stored in lolor LO storage');
lo_from_bytea
---------------
1
(1 row)

SELECT lolor.disable();
disable
---------
t
(1 row)

SELECT lo_open(1, 262144); -- 'not found' ERROR
ERROR: large object 1 does not exist
SELECT lo_from_bytea(2, 'Example large object stored in built-in LO storage');
lo_from_bytea
---------------
2
(1 row)

-- We should see the object
SELECT lolor.enable();
enable
--------
t
(1 row)

SELECT lo_open(2, 262144); -- 'not found' ERROR
ERROR: large object 2 does not exist
BEGIN;
SELECT lo_open(1, 262144) AS fd \gset
SELECT convert_from(loread(:fd, 1024), 'UTF8'); -- OK, see the object
convert_from
-------------------------------------------------
Example large object stored in lolor LO storage
(1 row)

END;
-- To be sure that the behaviour is repeatable
SELECT lolor.disable();
disable
---------
t
(1 row)

SELECT lolor.enable();
enable
--------
t
(1 row)

-- Check that no tails existing after the extension drop in both enabled and
-- disabled states.
DROP EXTENSION lolor;
SELECT oid, proname FROM pg_proc WHERE proname IN ('lo_open_orig',
'lolor_lo_open');
oid | proname
-----+---------
(0 rows)

CREATE EXTENSION lolor;
SELECT lolor.disable();
disable
---------
t
(1 row)

DROP EXTENSION lolor;
SELECT oid, proname FROM pg_proc WHERE proname IN ('lo_open_orig',
'lolor_lo_open');
oid | proname
-----+---------
(0 rows)

202 changes: 202 additions & 0 deletions lolor--1.2.1--1.2.2.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
/* lolor--1.2.1--1.2.2.sql */

-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "CREATE EXTENSION lolor" to load this file. \quit

/*
* Disable lolor functionality.
*
* Renames LO-related routines referencing lolor C-functions to corresponding
* pg_catalog.lolor_* ones. Afterwards, renames pg_catalog.*_orig routines to
* corresponding LO ones. If the lolor is disabled, do nothing.
* Designed to not create / drop any database objects.
*
* Returns true on success, false on a handled error and an ERROR otherwise.
*/
CREATE FUNCTION lolor.disable()
RETURNS boolean AS $$
BEGIN
-- Doesn't protect a lot but provides a user with meaningful peace of information
IF NOT EXISTS (SELECT 1 FROM pg_proc where proname = 'lo_close_orig') THEN
raise NOTICE 'lolor still not enabled';
RETURN false;
END IF;
IF EXISTS (SELECT 1 FROM pg_proc where proname = 'lolor_lo_open') THEN
raise NOTICE 'lolor.disable() has been called before';
RETURN false;
END IF;

ALTER FUNCTION pg_catalog.lo_open(oid, int4) RENAME TO lolor_lo_open;
ALTER FUNCTION pg_catalog.lo_open_orig(oid, int4) RENAME TO lo_open;

ALTER FUNCTION pg_catalog.lo_close(int4) RENAME TO lolor_lo_close;
ALTER FUNCTION pg_catalog.lo_close_orig(int4) RENAME TO lo_close;

ALTER FUNCTION pg_catalog.lo_creat(integer) RENAME TO lolor_lo_creat;
ALTER FUNCTION pg_catalog.lo_creat_orig(integer) RENAME TO lo_creat;

ALTER FUNCTION pg_catalog.lo_create(oid) RENAME TO lolor_lo_create;
ALTER FUNCTION pg_catalog.lo_create_orig(oid) RENAME TO lo_create;

ALTER FUNCTION pg_catalog.loread(integer, integer) RENAME TO lolor_loread;
ALTER FUNCTION pg_catalog.loread_orig(integer, integer) RENAME TO loread;

ALTER FUNCTION pg_catalog.lowrite(integer, bytea) RENAME TO lolor_lowrite;
ALTER FUNCTION pg_catalog.lowrite_orig(integer, bytea) RENAME TO lowrite;

ALTER FUNCTION pg_catalog.lo_export(oid, text) RENAME TO lolor_lo_export;
ALTER FUNCTION pg_catalog.lo_export_orig(oid, text) RENAME TO lo_export;

ALTER FUNCTION pg_catalog.lo_from_bytea(oid, bytea) RENAME TO lolor_lo_from_bytea;
ALTER FUNCTION pg_catalog.lo_from_bytea_orig(oid, bytea) RENAME TO lo_from_bytea;

ALTER FUNCTION pg_catalog.lo_get(oid) RENAME TO lolor_lo_get;
ALTER FUNCTION pg_catalog.lo_get_orig(oid) RENAME TO lo_get;

ALTER FUNCTION pg_catalog.lo_get(oid, bigint, integer) RENAME TO lolor_lo_get;
ALTER FUNCTION pg_catalog.lo_get_orig(oid, bigint, integer) RENAME TO lo_get;

ALTER FUNCTION pg_catalog.lo_import(text) RENAME TO lolor_lo_import;
ALTER FUNCTION pg_catalog.lo_import_orig(text) RENAME TO lo_import;

ALTER FUNCTION pg_catalog.lo_import(text, oid) RENAME TO lolor_lo_import;
ALTER FUNCTION pg_catalog.lo_import_orig(text, oid) RENAME TO lo_import;

ALTER FUNCTION pg_catalog.lo_lseek(integer, integer, integer) RENAME TO lolor_lo_lseek;
ALTER FUNCTION pg_catalog.lo_lseek_orig(integer, integer, integer) RENAME TO lo_lseek;

ALTER FUNCTION pg_catalog.lo_lseek64(integer, bigint, integer) RENAME TO lolor_lo_lseek64;
ALTER FUNCTION pg_catalog.lo_lseek64_orig(integer, bigint, integer) RENAME TO lo_lseek64;

ALTER FUNCTION pg_catalog.lo_put(oid, bigint, bytea) RENAME TO lolor_lo_put;
ALTER FUNCTION pg_catalog.lo_put_orig(oid, bigint, bytea) RENAME TO lo_put;

ALTER FUNCTION pg_catalog.lo_tell(integer) RENAME TO lolor_lo_tell;
ALTER FUNCTION pg_catalog.lo_tell_orig(integer) RENAME TO lo_tell;

ALTER FUNCTION pg_catalog.lo_tell64(integer) RENAME TO lolor_lo_tell64;
ALTER FUNCTION pg_catalog.lo_tell64_orig(integer) RENAME TO lo_tell64;

ALTER FUNCTION pg_catalog.lo_truncate(integer, integer) RENAME TO lolor_lo_truncate;
ALTER FUNCTION pg_catalog.lo_truncate_orig(integer, integer) RENAME TO lo_truncate;

ALTER FUNCTION pg_catalog.lo_truncate64(integer, bigint) RENAME TO lolor_lo_truncate64;
ALTER FUNCTION pg_catalog.lo_truncate64_orig(integer, bigint) RENAME TO lo_truncate64;

ALTER FUNCTION pg_catalog.lo_unlink(oid) RENAME TO lolor_lo_unlink;
ALTER FUNCTION pg_catalog.lo_unlink_orig(oid) RENAME TO lo_unlink;

RETURN true;
END;
$$ LANGUAGE plpgsql STRICT VOLATILE;

/*
* Enable lolor functionality, disabled by the lolor.disable() call.
*
* Renames LO-related routines to corresponding pg_catalog.*_orig. Afterwards,
* renames pg_catalog.lolor_* routines to corresponding LO ones. If the lolor is
* enabled, do nothing.
* Designed to not create / drop any database objects.
*
* Returns true on success, false on a handled error and an ERROR otherwise.
*/
CREATE FUNCTION lolor.enable()
RETURNS boolean AS $$
BEGIN
-- Doesn't protect a lot but provides a user with meaningful peace of information
IF NOT EXISTS (SELECT 1 FROM pg_proc where proname = 'lolor_lo_open') THEN
raise NOTICE 'lolor still not disabled';
RETURN false;
END IF;
IF EXISTS (SELECT 1 FROM pg_proc where proname = 'lo_close_orig') THEN
raise NOTICE 'lolor.enable() has been called before';
RETURN false;
END IF;

ALTER FUNCTION pg_catalog.lo_open(oid, int4) RENAME TO lo_open_orig;
ALTER FUNCTION pg_catalog.lolor_lo_open(oid, int4) RENAME TO lo_open;

ALTER FUNCTION pg_catalog.lo_close(int4) RENAME TO lo_close_orig;
ALTER FUNCTION pg_catalog.lolor_lo_close(int4) RENAME TO lo_close;

ALTER FUNCTION pg_catalog.lo_creat(integer) RENAME TO lo_creat_orig;
ALTER FUNCTION pg_catalog.lolor_lo_creat(integer) RENAME TO lo_creat;

ALTER FUNCTION pg_catalog.lo_create(oid) RENAME TO lo_create_orig;
ALTER FUNCTION pg_catalog.lolor_lo_create(oid) RENAME TO lo_create;

ALTER FUNCTION pg_catalog.loread(integer, integer) RENAME TO loread_orig;
ALTER FUNCTION pg_catalog.lolor_loread(integer, integer) RENAME TO loread;

ALTER FUNCTION pg_catalog.lowrite(integer, bytea) RENAME TO lowrite_orig;
ALTER FUNCTION pg_catalog.lolor_lowrite(integer, bytea) RENAME TO lowrite;

ALTER FUNCTION pg_catalog.lo_export(oid, text) RENAME TO lo_export_orig;
ALTER FUNCTION pg_catalog.lolor_lo_export(oid, text) RENAME TO lo_export;

ALTER FUNCTION pg_catalog.lo_from_bytea(oid, bytea) RENAME TO lo_from_bytea_orig;
ALTER FUNCTION pg_catalog.lolor_lo_from_bytea(oid, bytea) RENAME TO lo_from_bytea;

ALTER FUNCTION pg_catalog.lo_get(oid) RENAME TO lo_get_orig;
ALTER FUNCTION pg_catalog.lolor_lo_get(oid) RENAME TO lo_get;

ALTER FUNCTION pg_catalog.lo_get(oid, bigint, integer) RENAME TO lo_get_orig;
ALTER FUNCTION pg_catalog.lolor_lo_get(oid, bigint, integer) RENAME TO lo_get;

ALTER FUNCTION pg_catalog.lo_import(text) RENAME TO lo_import_orig;
ALTER FUNCTION pg_catalog.lolor_lo_import(text) RENAME TO lo_import;

ALTER FUNCTION pg_catalog.lo_import(text, oid) RENAME TO lo_import_orig;
ALTER FUNCTION pg_catalog.lolor_lo_import(text, oid) RENAME TO lo_import;

ALTER FUNCTION pg_catalog.lo_lseek(integer, integer, integer) RENAME TO lo_lseek_orig;
ALTER FUNCTION pg_catalog.lolor_lo_lseek(integer, integer, integer) RENAME TO lo_lseek;

ALTER FUNCTION pg_catalog.lo_lseek64(integer, bigint, integer) RENAME TO lo_lseek64_orig;
ALTER FUNCTION pg_catalog.lolor_lo_lseek64(integer, bigint, integer) RENAME TO lo_lseek64;

ALTER FUNCTION pg_catalog.lo_put(oid, bigint, bytea) RENAME TO lo_put_orig;
ALTER FUNCTION pg_catalog.lolor_lo_put(oid, bigint, bytea) RENAME TO lo_put;

ALTER FUNCTION pg_catalog.lo_tell(integer) RENAME TO lo_tell_orig;
ALTER FUNCTION pg_catalog.lolor_lo_tell(integer) RENAME TO lo_tell;

ALTER FUNCTION pg_catalog.lo_tell64(integer) RENAME TO lo_tell64_orig;
ALTER FUNCTION pg_catalog.lolor_lo_tell64(integer) RENAME TO lo_tell64;

ALTER FUNCTION pg_catalog.lo_truncate(integer, integer) RENAME TO lo_truncate_orig;
ALTER FUNCTION pg_catalog.lolor_lo_truncate(integer, integer) RENAME TO lo_truncate;

ALTER FUNCTION pg_catalog.lo_truncate64(integer, bigint) RENAME TO lo_truncate64_orig;
ALTER FUNCTION pg_catalog.lolor_lo_truncate64(integer, bigint) RENAME TO lo_truncate64;

ALTER FUNCTION pg_catalog.lo_unlink(oid) RENAME TO lo_unlink_orig;
ALTER FUNCTION pg_catalog.lolor_lo_unlink(oid) RENAME TO lo_unlink;

RETURN true;
END;
$$ LANGUAGE plpgsql STRICT VOLATILE;

--
-- Check if lolor functions replaces core LO routines at the moment.
--
CREATE FUNCTION lolor.is_enabled()
RETURNS boolean AS $$
BEGIN
-- Doesn't protect a lot but provides a user with meaningful peace of information
IF NOT EXISTS (SELECT 1 FROM pg_proc
WHERE proname IN ('lolor_lo_open', 'lo_open_orig')) THEN
raise EXCEPTION 'lolor is in inconsistent state';
ELSIF EXISTS (SELECT 1 WHERE
EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'lolor_lo_open') AND
EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'lo_open_orig')) THEN
raise EXCEPTION 'lolor is in inconsistent state';
END IF;

IF EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'lolor_lo_open') THEN
RETURN false;
END IF;

RETURN true;
END;
$$ LANGUAGE plpgsql STRICT STABLE;
2 changes: 1 addition & 1 deletion lolor.control
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# lolor extension
comment = 'Large Objects support for logical replication'
default_version = '1.2.1'
default_version = '1.2.2'
module_pathname = '$libdir/lolor'
relocatable = false
trusted = true
Expand Down
Loading