Hello, I'm attaching a v2 with rebase and adding Niccolo Fei as one of the reviewers.
Thank you! -- Jonathan Gonzalez V. <[email protected]> EnterpriseDB
From fef92b2baa38edc0d8c545e3fe60a5803268864a Mon Sep 17 00:00:00 2001 From: "Jonathan Gonzalez V." <[email protected]> Date: Mon, 23 Feb 2026 22:27:51 +0100 Subject: [PATCH v2 1/1] Strip `$libdir` during pg_upgrade starting on 19. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the commit 4f7f7b03758 extension_control_path GUC was included, while some test were added, is missing to handle the hardcoded `$libdir/` path during the execution of `pg_upgrade` for the the installed extensions using the extension_control_path GUC An aditional test for `pg_upgrade` is added to test the upgrade with the extension_control_path in use with a C extension using the hardcoded `$libdir/` string in the `module_pathname` Reviewed-by: Niccolò Fei <[email protected]> Signed-off-by: Jonathan Gonzalez V. <[email protected]> --- src/bin/pg_upgrade/Makefile | 6 +- src/bin/pg_upgrade/function.c | 9 ++ src/bin/pg_upgrade/meson.build | 21 ++- .../t/008_extension_control_path.pl | 126 ++++++++++++++++++ src/test/modules/test_extensions/Makefile | 3 + src/test/modules/test_extensions/meson.build | 13 ++ src/test/modules/test_extensions/test_ext.c | 22 +++ 7 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 src/bin/pg_upgrade/t/008_extension_control_path.pl create mode 100644 src/test/modules/test_extensions/test_ext.c diff --git a/src/bin/pg_upgrade/Makefile b/src/bin/pg_upgrade/Makefile index 726df4b7525..771addb675a 100644 --- a/src/bin/pg_upgrade/Makefile +++ b/src/bin/pg_upgrade/Makefile @@ -3,7 +3,7 @@ PGFILEDESC = "pg_upgrade - an in-place binary upgrade utility" PGAPPICON = win32 -EXTRA_INSTALL=contrib/test_decoding src/test/modules/dummy_seclabel +EXTRA_INSTALL=contrib/test_decoding src/test/modules/dummy_seclabel src/test/modules/test_extensions subdir = src/bin/pg_upgrade top_builddir = ../../.. @@ -38,6 +38,10 @@ LDFLAGS_INTERNAL += -L$(top_builddir)/src/fe_utils -lpgfeutils $(libpq_pgport) REGRESS_SHLIB=$(abs_top_builddir)/src/test/regress/regress$(DLSUFFIX) export REGRESS_SHLIB +# required for 008_extension_control_path.pl +TEST_EXT_LIB=$(abs_top_builddir)/src/test/modules/test_extensions/test_ext$(DLSUFFIX) +export TEST_EXT_LIB + all: pg_upgrade pg_upgrade: $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils diff --git a/src/bin/pg_upgrade/function.c b/src/bin/pg_upgrade/function.c index a3184f95665..461b7b2c20c 100644 --- a/src/bin/pg_upgrade/function.c +++ b/src/bin/pg_upgrade/function.c @@ -120,6 +120,15 @@ get_loadable_libraries(void) { char *lib = PQgetvalue(res, rowno, 0); + /* + * Starting on version 18, the extension may be loaded using + * extension_control_path, some extensions have the `$libdir/` + * hardcoded, we should remove it to allow the upgrade to version + * 19 or above. + */ + if (strncmp(lib, "$libdir/", 8) == 0) + lib += 8; + os_info.libraries[totaltups].name = pg_strdup(lib); os_info.libraries[totaltups].dbnum = dbnum; diff --git a/src/bin/pg_upgrade/meson.build b/src/bin/pg_upgrade/meson.build index 49b1b624f25..ffbf6ae8d75 100644 --- a/src/bin/pg_upgrade/meson.build +++ b/src/bin/pg_upgrade/meson.build @@ -36,13 +36,30 @@ pg_upgrade = executable('pg_upgrade', ) bin_targets += pg_upgrade +test_ext_sources = files( + '../../test/modules/test_extensions/test_ext.c' +) + +if host_system == 'windows' + test_ext_sources += rc_lib_gen.process(win32ver_rc, extra_args: [ + '--NAME', 'test_ext', + '--FILEDESC', 'test_ext - test C extension for pg_upgrade',]) +endif + +test_ext = shared_module('test_ext', + test_ext_sources, + kwargs: pg_test_mod_args, +) tests += { 'name': 'pg_upgrade', 'sd': meson.current_source_dir(), 'bd': meson.current_build_dir(), 'tap': { - 'env': {'with_icu': icu.found() ? 'yes' : 'no'}, + 'env': { + 'with_icu': icu.found() ? 'yes' : 'no', + 'TEST_EXT_LIB': test_ext.full_path(), + }, 'tests': [ 't/001_basic.pl', 't/002_pg_upgrade.pl', @@ -51,7 +68,9 @@ tests += { 't/005_char_signedness.pl', 't/006_transfer_modes.pl', 't/007_multixact_conversion.pl', + 't/008_extension_control_path.pl', ], + 'deps': [test_ext], 'test_kwargs': {'priority': 40}, # pg_upgrade tests are slow }, } diff --git a/src/bin/pg_upgrade/t/008_extension_control_path.pl b/src/bin/pg_upgrade/t/008_extension_control_path.pl new file mode 100644 index 00000000000..b50e92326ca --- /dev/null +++ b/src/bin/pg_upgrade/t/008_extension_control_path.pl @@ -0,0 +1,126 @@ +# Copyright (c) 2026, PostgreSQL Global Development Group + +# Test pg_upgrade with the extension_control_path GUC active. + +use strict; +use warnings FATAL => 'all'; + +use File::Copy; +use File::Path; +use PostgreSQL::Test::Cluster; +use PostgreSQL::Test::Utils; +use Test::More; + +# Make sure the extension file .so path is provided +my $ext_lib_so = $ENV{TEST_EXT_LIB} + or die "couldn't get the extension so path"; + +# Create the custom extension directory layout: +# $ext_dir/extension/ -- .control and .sql files +# $ext_dir/lib/ -- .so file +my $ext_dir = PostgreSQL::Test::Utils::tempdir(); +mkpath("$ext_dir/extension"); +mkpath("$ext_dir/lib"); +my $ext_lib = $ext_dir . '/lib'; + +# Copy the .so file into the lib/ subdirectory. +copy($ext_lib_so, $ext_lib) + or die "could not copy '$ext_lib_so' to '$ext_lib': $!"; + +create_extension_files('test_ext', $ext_dir); + +my $sep = $windows_os ? ";" : ":"; +my $ext_path = $windows_os ? ($ext_dir =~ s/\\/\\\\/gr) : $ext_dir; +my $ext_lib_path = $windows_os ? ($ext_lib =~ s/\\/\\\\/gr) : $ext_lib; + +my $extension_control_path_conf = qq( +extension_control_path = '\$system$sep$ext_path' +dynamic_library_path = '\$libdir$sep$ext_lib_path' +); + +my $old = + PostgreSQL::Test::Cluster->new('old', install_path => $ENV{oldinstall}); +$old->init; + +# Configure extension_control_path so the .control file is found in our +# extension/ directory, and dynamic_library_path so the .so is found in lib/. +$old->append_conf('postgresql.conf', $extension_control_path_conf); + +$old->start; + +# CREATE EXTENSION 'test_ext' +$old->safe_psql('postgres', 'CREATE EXTENSION test_ext'); + +# Verify the extension works before the upgrade. +my ($code, $stdout, $stderr) = $old->psql('postgres', 'SELECT test_ext()'); +is($code, 0, 'extension works before upgrade'); +like($stderr, qr/NOTICE: running successful/, 'extension working'); + +$old->stop; + +my $new = PostgreSQL::Test::Cluster->new('new'); +$new->init; + +# Pre-configure the new cluster with dynamic_library_path and +# extension_control_path before running pg_upgrade. +$new->append_conf('postgresql.conf', $extension_control_path_conf); + +# In a VPATH build, we'll be started in the source directory, but we want +# to run pg_upgrade in the build directory so that any files generated finish +# in it, like delete_old_cluster.{sh,bat}. +chdir ${PostgreSQL::Test::Utils::tmp_check}; + +command_ok( + [ + 'pg_upgrade', '--no-sync', + '--old-datadir' => $old->data_dir, + '--new-datadir' => $new->data_dir, + '--old-bindir' => $old->config_data('--bindir'), + '--new-bindir' => $new->config_data('--bindir'), + '--socketdir' => $new->host, + '--old-port' => $old->port, + '--new-port' => $new->port, + '--copy', + ], + 'pg_upgrade succeeds with extension installed via extension_control_path' +); + +$new->start; + +# Verify the extension still works after the upgrade. +($code, $stdout, $stderr) = $new->psql('postgres', 'SELECT test_ext()'); +is($code, 0, 'extension works after upgrade'); +like($stderr, qr/NOTICE: running successful/, 'extension working'); + +$new->stop; + +# Write .control and .sql files into $ext_dir/extension/ +# `module_pathname` contains the `$libdir/` to simulate most of the extensions +# that use it as a prefix in the `module_pathname` by default +sub create_extension_files +{ + my ($ext_name, $ext_dir) = @_; + + open my $cf, '>', "$ext_dir/extension/$ext_name.control" + or die "could not create control file: $!"; + print $cf + "comment = 'Test C extension for pg_upgrade + extension_control_path'\n"; + print $cf "default_version = '1.0'\n"; + print $cf "module_pathname = '\$libdir/$ext_name'\n"; + print $cf "relocatable = true\n"; + close $cf; + + open my $sqlf, '>', "$ext_dir/extension/$ext_name--1.0.sql" + or die "could not create SQL file: $!"; + print $sqlf "/* $ext_name--1.0.sql */\n"; + print $sqlf + "-- complain if script is sourced in psql, rather than via CREATE EXTENSION\n"; + print $sqlf + qq'\\echo Use "CREATE EXTENSION $ext_name" to load this file. \\quit\n'; + print $sqlf "CREATE FUNCTION test_ext()\n"; + print $sqlf "RETURNS void AS 'MODULE_PATHNAME'\n"; + print $sqlf "LANGUAGE C;\n"; + close $sqlf; +} + +done_testing(); diff --git a/src/test/modules/test_extensions/Makefile b/src/test/modules/test_extensions/Makefile index a3591bf3d2f..d1b0b81e5fd 100644 --- a/src/test/modules/test_extensions/Makefile +++ b/src/test/modules/test_extensions/Makefile @@ -1,6 +1,7 @@ # src/test/modules/test_extensions/Makefile MODULE = test_extensions +MODULE_big = test_ext PGFILEDESC = "test_extensions - regression testing for EXTENSION support" EXTENSION = test_ext1 test_ext2 test_ext3 test_ext4 test_ext5 test_ext6 \ @@ -11,6 +12,8 @@ EXTENSION = test_ext1 test_ext2 test_ext3 test_ext4 test_ext5 test_ext6 \ test_ext_set_schema \ test_ext_req_schema1 test_ext_req_schema2 test_ext_req_schema3 +OBJS = test_ext.o + DATA = test_ext1--1.0.sql test_ext2--1.0.sql test_ext3--1.0.sql \ test_ext4--1.0.sql test_ext5--1.0.sql test_ext6--1.0.sql \ test_ext7--1.0.sql test_ext7--1.0--2.0.sql \ diff --git a/src/test/modules/test_extensions/meson.build b/src/test/modules/test_extensions/meson.build index be9c9ae593f..2c7cea189e2 100644 --- a/src/test/modules/test_extensions/meson.build +++ b/src/test/modules/test_extensions/meson.build @@ -46,6 +46,19 @@ test_install_data += files( 'test_ext_set_schema.control', ) +test_ext_sources = files('test_ext.c') + +if host_system == 'windows' + test_ext_sources += rc_lib_gen.process(win32ver_rc, extra_args: [ + '--NAME', 'test_ext', + '--FILEDESC', 'test_ext - test C extension for pg_upgrade',]) +endif + +test_ext = shared_module('test_ext', + test_ext_sources, + kwargs: pg_test_mod_args, +) + tests += { 'name': 'test_extensions', 'sd': meson.current_source_dir(), diff --git a/src/test/modules/test_extensions/test_ext.c b/src/test/modules/test_extensions/test_ext.c new file mode 100644 index 00000000000..a23165ba67a --- /dev/null +++ b/src/test/modules/test_extensions/test_ext.c @@ -0,0 +1,22 @@ +/* + * test_ext.c + * + * Dummy C extension for testing extension_control_path with pg_upgrade + * + * Portions Copyright (c) 2026, PostgreSQL Global Development Group + */ +#include "postgres.h" + +#include "fmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(test_ext); + +Datum +test_ext(PG_FUNCTION_ARGS) +{ + ereport(NOTICE, + (errmsg("running successful"))); + PG_RETURN_VOID(); +} -- 2.51.0
signature.asc
Description: This is a digitally signed message part
