diff --git a/Makefile b/Makefile index 3efc056..caf9241 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/expected/lolor.out b/expected/lolor.out index e626580..1409abe 100644 --- a/expected/lolor.out +++ b/expected/lolor.out @@ -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'); @@ -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) + diff --git a/lolor--1.2.1--1.2.2.sql b/lolor--1.2.1--1.2.2.sql new file mode 100644 index 0000000..9c62315 --- /dev/null +++ b/lolor--1.2.1--1.2.2.sql @@ -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; diff --git a/lolor.control b/lolor.control index dc528b8..e8a0385 100644 --- a/lolor.control +++ b/lolor.control @@ -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 diff --git a/sql/lolor.sql b/sql/lolor.sql index 2aab313..78546ee 100644 --- a/sql/lolor.sql +++ b/sql/lolor.sql @@ -1,4 +1,5 @@ -- Basic checks +\set VERBOSITY terse LOAD 'lolor'; SET lolor.node = 1; @@ -33,3 +34,50 @@ 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'); +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'); +END; + +-- +-- Basic checks for enable/disable routines. +-- + +SELECT lolor.enable(); -- ERROR +SELECT lo_from_bytea(1, 'Example large object stored in lolor LO storage'); +SELECT lolor.disable(); +SELECT lo_open(1, 262144); -- 'not found' ERROR +SELECT lo_from_bytea(2, 'Example large object stored in built-in LO storage'); + +-- We should see the object +SELECT lolor.enable(); +SELECT lo_open(2, 262144); -- 'not found' ERROR +BEGIN; +SELECT lo_open(1, 262144) AS fd \gset +SELECT convert_from(loread(:fd, 1024), 'UTF8'); -- OK, see the object +END; + +-- To be sure that the behaviour is repeatable +SELECT lolor.disable(); +SELECT lolor.enable(); + +-- 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'); +CREATE EXTENSION lolor; +SELECT lolor.disable(); +DROP EXTENSION lolor; +SELECT oid, proname FROM pg_proc WHERE proname IN ('lo_open_orig', + 'lolor_lo_open'); diff --git a/src/lolor.c b/src/lolor.c index 42131a9..41df671 100644 --- a/src/lolor.c +++ b/src/lolor.c @@ -188,7 +188,7 @@ _PG_init(void) * * We cannot drop our own functions here as the dependencies of * the extension itself won't allow that. Likewise we cannot - * drop the origial PostgreSQL functions because the PostgreSQL + * drop the original PostgreSQL functions because the PostgreSQL * system depends on them. But we can get around that with * renaming (which makes no sense). */ @@ -247,107 +247,8 @@ lolor_on_drop_extension(PG_FUNCTION_ARGS) */ SPI_connect(); - SPI_execute("ALTER FUNCTION pg_catalog.lo_open(oid, int4)" - " RENAME TO lo_open_to_drop", false, 0); - SPI_execute("ALTER FUNCTION pg_catalog.lo_open_orig(oid, int4)" - " RENAME TO lo_open", false, 0); - - SPI_execute("ALTER FUNCTION pg_catalog.lo_close(int4)" - " RENAME TO lo_close_to_drop", false, 0); - SPI_execute("ALTER FUNCTION pg_catalog.lo_close_orig(int4)" - " RENAME TO lo_close", false, 0); - - SPI_execute("ALTER FUNCTION pg_catalog.lo_creat(integer)" - " RENAME TO lo_creat_to_drop", false, 0); - SPI_execute("ALTER FUNCTION pg_catalog.lo_creat_orig(integer)" - " RENAME TO lo_creat", false, 0); - - SPI_execute("ALTER FUNCTION pg_catalog.lo_create(oid)" - " RENAME TO lo_create_to_drop", false, 0); - SPI_execute("ALTER FUNCTION pg_catalog.lo_create_orig(oid)" - " RENAME TO lo_create", false, 0); - - SPI_execute("ALTER FUNCTION pg_catalog.loread(integer, integer)" - " RENAME TO loread_to_drop", false, 0); - SPI_execute("ALTER FUNCTION pg_catalog.loread_orig(integer, integer)" - " RENAME TO loread", false, 0); - - SPI_execute("ALTER FUNCTION pg_catalog.lowrite(integer, bytea)" - " RENAME TO lowrite_to_drop", false, 0); - SPI_execute("ALTER FUNCTION pg_catalog.lowrite_orig(integer, bytea)" - " RENAME TO lowrite", false, 0); - - - SPI_execute("ALTER FUNCTION pg_catalog.lo_export(oid, text)" - " RENAME TO lo_export_to_drop;", false, 0); - SPI_execute("ALTER FUNCTION pg_catalog.lo_export_orig(oid, text)" - " RENAME TO lo_export;", false, 0); - - SPI_execute("ALTER FUNCTION pg_catalog.lo_from_bytea(oid, bytea)" - " RENAME TO lo_from_bytea_to_drop;", false, 0); - SPI_execute("ALTER FUNCTION pg_catalog.lo_from_bytea_orig(oid, bytea)" - " RENAME TO lo_from_bytea;", false, 0); - - SPI_execute("ALTER FUNCTION pg_catalog.lo_get(oid)" - " RENAME TO lo_get_to_drop;", false, 0); - SPI_execute("ALTER FUNCTION pg_catalog.lo_get_orig(oid)" - " RENAME TO lo_get;", false, 0); - - SPI_execute("ALTER FUNCTION pg_catalog.lo_get(oid, bigint, integer)" - " RENAME TO lo_get_to_drop;", false, 0); - SPI_execute("ALTER FUNCTION pg_catalog.lo_get_orig(oid, bigint, integer)" - " RENAME TO lo_get;", false, 0); - - SPI_execute("ALTER FUNCTION pg_catalog.lo_import(text)" - " RENAME TO lo_import_to_drop;", false, 0); - SPI_execute("ALTER FUNCTION pg_catalog.lo_import_orig(text)" - " RENAME TO lo_import;", false, 0); - - SPI_execute("ALTER FUNCTION pg_catalog.lo_import(text, oid)" - " RENAME TO lo_import_to_drop;", false, 0); - SPI_execute("ALTER FUNCTION pg_catalog.lo_import_orig(text, oid)" - " RENAME TO lo_import;", false, 0); - - SPI_execute("ALTER FUNCTION pg_catalog.lo_lseek(integer, integer, integer)" - " RENAME TO lo_lseek_to_drop;", false, 0); - SPI_execute("ALTER FUNCTION pg_catalog.lo_lseek_orig(integer, integer, integer)" - " RENAME TO lo_lseek;", false, 0); - - SPI_execute("ALTER FUNCTION pg_catalog.lo_lseek64(integer, bigint, integer)" - " RENAME TO lo_lseek64_to_drop;", false, 0); - SPI_execute("ALTER FUNCTION pg_catalog.lo_lseek64_orig(integer, bigint, integer)" - " RENAME TO lo_lseek64;", false, 0); - - SPI_execute("ALTER FUNCTION pg_catalog.lo_put(oid, bigint, bytea)" - " RENAME TO lo_put_to_drop;", false, 0); - SPI_execute("ALTER FUNCTION pg_catalog.lo_put_orig(oid, bigint, bytea)" - " RENAME TO lo_put;", false, 0); - - SPI_execute("ALTER FUNCTION pg_catalog.lo_tell(integer)" - " RENAME TO lo_tell_to_drop;", false, 0); - SPI_execute("ALTER FUNCTION pg_catalog.lo_tell_orig(integer)" - " RENAME TO lo_tell;", false, 0); - - SPI_execute("ALTER FUNCTION pg_catalog.lo_tell64(integer)" - " RENAME TO lo_tell64_to_drop;", false, 0); - SPI_execute("ALTER FUNCTION pg_catalog.lo_tell64_orig(integer)" - " RENAME TO lo_tell64;", false, 0); - - SPI_execute("ALTER FUNCTION pg_catalog.lo_truncate(integer, integer)" - " RENAME TO lo_truncate_to_drop;", false, 0); - SPI_execute("ALTER FUNCTION pg_catalog.lo_truncate_orig(integer, integer)" - " RENAME TO lo_truncate;", false, 0); - - SPI_execute("ALTER FUNCTION pg_catalog.lo_truncate64(integer, bigint)" - " RENAME TO lo_truncate64_to_drop;", false, 0); - SPI_execute("ALTER FUNCTION pg_catalog.lo_truncate64_orig(integer, bigint)" - " RENAME TO lo_truncate64;", false, 0); - - SPI_execute("ALTER FUNCTION pg_catalog.lo_unlink(oid)" - " RENAME TO lo_unlink_to_drop;", false, 0); - SPI_execute("ALTER FUNCTION pg_catalog.lo_unlink_orig(oid)" - " RENAME TO lo_unlink;", false, 0); - + SPI_execute("SELECT CASE WHEN lolor.is_enabled() THEN lolor.disable() ELSE 'true' END CASE", + false, 0); SPI_finish(); PG_RETURN_NULL(); diff --git a/t/001_lolor_basic.pl b/t/001_lolor_basic.pl index bdd1c02..8502b47 100644 --- a/t/001_lolor_basic.pl +++ b/t/001_lolor_basic.pl @@ -13,9 +13,46 @@ use Test::More; my $node = PostgreSQL::Test::Cluster->new('main'); -my $result; +my ($result, $stdout, $stderr); $node->init; + +# ############################################################################## +# +# Lolor is loaded dynamically, on demand +# +# ############################################################################## + +$node->start; +$node->safe_psql('postgres', "CREATE EXTENSION lolor"); + +# Check +($result, $stdout, $stderr) = $node->psql('postgres', qq( + SET lolor.node = 0; + SELECT lo_creat(-1) +)); +like($stderr, qr/value for lolor.node is not set/, "Zero value of lolor node is treated as an unset"); + +$result = $node->safe_psql('postgres', qq( + SET lolor.node = 1; + SELECT lo_creat(-1); +)); +ok($result > 0, "Lolor works and produces LO IDs"); + +$node->safe_psql('postgres', "DROP EXTENSION lolor"); +$result = $node->safe_psql('postgres', qq( + SET lolor.node = 0; + SELECT lo_creat(-1); +)); +ok($result > 0, "Lolor has been removed and standard lo_creat routine is used"); +$node->stop(); + +# ############################################################################## +# +# Tests when lolor is loaded statically +# +# ############################################################################## + $node->append_conf('postgresql.conf', qq{shared_preload_libraries = 'lolor'}); $node->start; diff --git a/t/002_pg_upgrade.pl b/t/002_pg_upgrade.pl new file mode 100644 index 0000000..b2cda08 --- /dev/null +++ b/t/002_pg_upgrade.pl @@ -0,0 +1,79 @@ +# Check binary upgrade +# +# Copyright (c) 2022-2025, pgEdge, Inc. +# Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# + +use strict; +use warnings FATAL => 'all'; + +use PostgreSQL::Test::Cluster; +use PostgreSQL::Test::Utils; +use Test::More; + +my $old = PostgreSQL::Test::Cluster->new('old_node'); +my $new = PostgreSQL::Test::Cluster->new('new_node'); +my $newbindir = $new->config_data('--bindir'); +my $oldbindir = $old->config_data('--bindir'); +my ($result, $stdout, $stderr); + +# Prepare old node to be upgraded +$old->init; +$old->append_conf('postgresql.conf', qq{lolor.node = 1}); +$old->start; +$old->safe_psql('postgres', "CREATE EXTENSION lolor"); +$old->safe_psql('postgres', + qq(SELECT lo_from_bytea(1, 'lolor LO object - 1'))); +$old->safe_psql('postgres', qq( + SET lolor.node = 1; + SELECT lo_creat(-1); +)); +$old->safe_psql('postgres', "SELECT lolor.disable()"); +$old->safe_psql('postgres', + qq(SELECT lo_from_bytea(1, 'built-in LO object - 1'))); +$old->stop(); + +$new->init; +$new->append_conf('postgresql.conf', qq{lolor.node = 1}); + +command_ok( + [ + 'pg_upgrade', + '--old-datadir' => $old->data_dir, + '--new-datadir' => $new->data_dir, + '--old-bindir' => $oldbindir, + '--new-bindir' => $newbindir, + '--link', + ], + 'run of pg_upgrade for new instance'); + +$new->start; +$new->safe_psql('postgres', "SELECT 1"); + +# Should not conflict with lolor +$new->safe_psql('postgres', "SELECT lo_from_bytea(2, 'built-in LO object - 2')"); +# Should see built-in object, created on the old node +$result = $new->safe_psql('postgres', qq( + BEGIN; -- built-in object + SELECT lo_open(1, 262144) AS fd \\gset + SELECT convert_from(loread(:fd, 1024), 'UTF8'); + END; +)); +ok($result eq 'built-in LO object - 1', "Check built-in LO works after upgrade"); + +$new->safe_psql('postgres', "SELECT lolor.enable()"); +# Should not conflict with built-in LO storage +$new->safe_psql('postgres', "SELECT lo_from_bytea(2, 'lolor LO object')"); +# Should see lolor object, created on the old node +$result = $new->safe_psql('postgres', qq( + BEGIN; -- lolor object + SELECT lo_open(1, 262144) AS fd \\gset + SELECT convert_from(loread(:fd, 1024), 'UTF8'); + END; +)); +ok($result eq 'lolor LO object - 1', "Check lolor works after upgrade"); + +$new->stop(); + +done_testing();