diff --git a/flake.nix b/flake.nix index 18cd9ba13..b650890d0 100644 --- a/flake.nix +++ b/flake.nix @@ -159,7 +159,7 @@ ./nix/ext/pg_tle.nix ./nix/ext/wrappers/default.nix ./nix/ext/supautils.nix - ./nix/ext/plv8.nix + ./nix/ext/plv8 ]; #Where we import and build the orioledb extension, we add on our custom extensions @@ -170,7 +170,7 @@ x: x != ./nix/ext/timescaledb.nix && x != ./nix/ext/timescaledb-2.9.1.nix && - x != ./nix/ext/plv8.nix + x != ./nix/ext/plv8/default.nix ) ourExtensions; orioledbExtensions = orioleFilteredExtensions ++ [ ./nix/ext/orioledb.nix ]; @@ -1384,6 +1384,8 @@ devShell = devShells.default; } // pkgs.lib.optionalAttrs (system == "aarch64-linux") { inherit (basePackages) postgresql_15_debug postgresql_15_src postgresql_orioledb-17_debug postgresql_orioledb-17_src postgresql_17_debug postgresql_17_src; + } // pkgs.lib.optionalAttrs (system == "x86_64-linux") { + plv8 = import ./nix/ext/tests/plv8.nix { inherit self; inherit pkgs; }; }; # Apps is a list of names of things that can be executed with 'nix run'; diff --git a/nix/ext/plv8.nix b/nix/ext/plv8.nix deleted file mode 100644 index b3fd03e07..000000000 --- a/nix/ext/plv8.nix +++ /dev/null @@ -1,145 +0,0 @@ -{ stdenv -, lib -, fetchFromGitHub -, v8 -, perl -, postgresql -# For passthru test on various systems, and local development on macos -# not we are not currently using passthru tests but retaining for possible contrib -# to nixpkgs -, runCommand -, coreutils -, gnugrep -, clang -, xcbuild -, darwin -, patchelf -}: - -stdenv.mkDerivation (finalAttrs: { - pname = "plv8"; - version = "3.1.10"; - - src = fetchFromGitHub { - owner = "plv8"; - repo = "plv8"; - rev = "v${finalAttrs.version}"; - hash = "sha256-g1A/XPC0dX2360Gzvmo9/FSQnM6Wt2K4eR0pH0p9fz4="; - }; - - patches = [ - # Allow building with system v8. - # https://github.com/plv8/plv8/pull/505 (rejected) - ./0001-build-Allow-using-V8-from-system.patch - ]; - - nativeBuildInputs = [ - perl - ] ++ lib.optionals stdenv.isDarwin [ - clang - xcbuild - ]; - - buildInputs = [ - v8 - postgresql - ] ++ lib.optionals stdenv.isDarwin [ - darwin.apple_sdk.frameworks.CoreFoundation - darwin.apple_sdk.frameworks.Kerberos - ]; - - buildFlags = [ "all" ]; - - makeFlags = [ - # Nixpkgs build a v8 monolith instead of separate v8_libplatform. - "USE_SYSTEM_V8=1" - "V8_OUTDIR=${v8}/lib" - "PG_CONFIG=${postgresql}/bin/pg_config" - ] ++ lib.optionals stdenv.isDarwin [ - "CC=${clang}/bin/clang" - "CXX=${clang}/bin/clang++" - "SHLIB_LINK=-L${v8}/lib -lv8_monolith -Wl,-rpath,${v8}/lib" - ] ++ lib.optionals (!stdenv.isDarwin) [ - "SHLIB_LINK=-lv8" - ]; - - NIX_LDFLAGS = (lib.optionals stdenv.isDarwin [ - "-L${postgresql}/lib" - "-L${v8}/lib" - "-lv8_monolith" - "-lpq" - "-lpgcommon" - "-lpgport" - "-F${darwin.apple_sdk.frameworks.CoreFoundation}/Library/Frameworks" - "-framework" "CoreFoundation" - "-F${darwin.apple_sdk.frameworks.Kerberos}/Library/Frameworks" - "-framework" "Kerberos" - "-undefined" "dynamic_lookup" - "-flat_namespace" - ]); - - installFlags = [ - # PGXS only supports installing to postgresql prefix so we need to redirect this - "DESTDIR=${placeholder "out"}" - ]; - - # No configure script. - dontConfigure = true; - - postPatch = '' - patchShebangs ./generate_upgrade.sh - substituteInPlace generate_upgrade.sh \ - --replace " 2.3.10 " " 2.3.10 2.3.11 2.3.12 2.3.13 2.3.14 2.3.15 " - - ${lib.optionalString stdenv.isDarwin '' - # Replace g++ with clang++ in Makefile - sed -i 's/g++/clang++/g' Makefile - ''} - ''; - - postInstall = '' - # Move the redirected to proper directory. - # There appear to be no references to the install directories - # so changing them does not cause issues. - mv "$out/nix/store"/*/* "$out" - rmdir "$out/nix/store"/* "$out/nix/store" "$out/nix" - - # Handle different PostgreSQL versions - if [ "${lib.versions.major postgresql.version}" = "15" ]; then - mv "$out/lib/plv8-${finalAttrs.version}.so" "$out/lib/plv8.so" - ln -s "$out/lib/plv8.so" "$out/lib/plv8-${finalAttrs.version}.so" - sed -i 's|module_pathname = '"'"'$libdir/plv8-[0-9.]*'"'"'|module_pathname = '"'"'$libdir/plv8'"'"'|' "$out/share/postgresql/extension/plv8.control" - sed -i 's|module_pathname = '"'"'$libdir/plv8-[0-9.]*'"'"'|module_pathname = '"'"'$libdir/plv8'"'"'|' "$out/share/postgresql/extension/plcoffee.control" - sed -i 's|module_pathname = '"'"'$libdir/plv8-[0-9.]*'"'"'|module_pathname = '"'"'$libdir/plv8'"'"'|' "$out/share/postgresql/extension/plls.control" - - ${lib.optionalString stdenv.isDarwin '' - install_name_tool -add_rpath "${v8}/lib" $out/lib/plv8.so - install_name_tool -add_rpath "${postgresql}/lib" $out/lib/plv8.so - install_name_tool -add_rpath "${stdenv.cc.cc.lib}/lib" $out/lib/plv8.so - install_name_tool -change @rpath/libv8_monolith.dylib ${v8}/lib/libv8_monolith.dylib $out/lib/plv8.so - ''} - - ${lib.optionalString (!stdenv.isDarwin) '' - ${patchelf}/bin/patchelf --set-rpath "${v8}/lib:${postgresql}/lib:${stdenv.cc.cc.lib}/lib" $out/lib/plv8.so - ''} - else - ${lib.optionalString stdenv.isDarwin '' - install_name_tool -add_rpath "${v8}/lib" $out/lib/plv8-${finalAttrs.version}${postgresql.dlSuffix} - install_name_tool -add_rpath "${postgresql}/lib" $out/lib/plv8-${finalAttrs.version}${postgresql.dlSuffix} - install_name_tool -add_rpath "${stdenv.cc.cc.lib}/lib" $out/lib/plv8-${finalAttrs.version}${postgresql.dlSuffix} - install_name_tool -change @rpath/libv8_monolith.dylib ${v8}/lib/libv8_monolith.dylib $out/lib/plv8-${finalAttrs.version}${postgresql.dlSuffix} - ''} - - ${lib.optionalString (!stdenv.isDarwin) '' - ${patchelf}/bin/patchelf --set-rpath "${v8}/lib:${postgresql}/lib:${stdenv.cc.cc.lib}/lib" $out/lib/plv8-${finalAttrs.version}${postgresql.dlSuffix} - ''} - fi - ''; - - meta = with lib; { - description = "V8 Engine Javascript Procedural Language add-on for PostgreSQL"; - homepage = "https://plv8.github.io/"; - platforms = [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-darwin" ]; - license = licenses.postgresql; - }; -}) diff --git a/nix/ext/0001-build-Allow-using-V8-from-system.patch b/nix/ext/plv8/0001-build-Allow-using-V8-from-system-3.1.10.patch similarity index 100% rename from nix/ext/0001-build-Allow-using-V8-from-system.patch rename to nix/ext/plv8/0001-build-Allow-using-V8-from-system-3.1.10.patch diff --git a/nix/ext/plv8/0001-build-Allow-using-V8-from-system-3.1.4.patch b/nix/ext/plv8/0001-build-Allow-using-V8-from-system-3.1.4.patch new file mode 100644 index 000000000..77c8e25c3 --- /dev/null +++ b/nix/ext/plv8/0001-build-Allow-using-V8-from-system-3.1.4.patch @@ -0,0 +1,83 @@ +From e473bab9483d937d8cab4313b9b45de0571c20fa Mon Sep 17 00:00:00 2001 +From: Jan Tojnar +Date: Thu, 13 Oct 2022 10:16:32 +0200 +Subject: [PATCH] build: Allow using V8 from system + +Building V8 is slow and pointless on systems that already provide a recent version like some Linux distros. +With this change, you can build against system V8 with the following: + + make USE_SYSTEM_V8=1 SHLIB_LINK=-lv8 V8_OUTDIR=/usr/lib +--- + Makefile | 35 +++++++++++++++++++---------------- + 1 file changed, 19 insertions(+), 16 deletions(-) + +diff --git a/Makefile b/Makefile +index 2f1f9f1..cfa50bc 100644 +--- a/Makefile ++++ b/Makefile +@@ -20,7 +20,7 @@ OBJS = $(SRCS:.cc=.o) + MODULE_big = plv8-$(PLV8_VERSION) + EXTENSION = plv8 + PLV8_DATA = plv8.control plv8--$(PLV8_VERSION).sql $(wildcard upgrade/*.sql) +- ++USE_SYSTEM_V8 = 0 + + # Platform detection + ifeq ($(OS),Windows_NT) +@@ -41,6 +41,7 @@ PGXS := $(shell $(PG_CONFIG) --pgxs) + PG_VERSION_NUM := $(shell cat `$(PG_CONFIG) --includedir-server`/pg_config*.h \ + | perl -ne 'print $$1 and exit if /PG_VERSION_NUM\s+(\d+)/') + ++ifeq ($(USE_SYSTEM_V8),0) + AUTOV8_DIR = build/v8 + AUTOV8_OUT = build/v8/out.gn/obj + AUTOV8_STATIC_LIBS = -lv8_libplatform -lv8_libbase +@@ -63,21 +64,6 @@ v8: + endif + + +-# enable direct jsonb conversion by default +-CCFLAGS += -DJSONB_DIRECT_CONVERSION +- +-CCFLAGS += -DV8_COMPRESS_POINTERS=1 -DV8_31BIT_SMIS_ON_64BIT_ARCH=1 +- +-CCFLAGS += -I$(AUTOV8_DIR)/include -I$(AUTOV8_DIR) +- +-ifdef EXECUTION_TIMEOUT +- CCFLAGS += -DEXECUTION_TIMEOUT +-endif +- +-ifdef BIGINT_GRACEFUL +- CCFLAGS += -DBIGINT_GRACEFUL +-endif +- + + # We're gonna build static link. Rip it out after include Makefile + SHLIB_LINK := $(filter-out -lv8, $(SHLIB_LINK)) +@@ -97,6 +83,23 @@ else + SHLIB_LINK += -lrt -std=c++14 + endif + endif ++endif ++ ++# enable direct jsonb conversion by default ++CCFLAGS += -DJSONB_DIRECT_CONVERSION ++ ++CCFLAGS += -DV8_COMPRESS_POINTERS=1 -DV8_31BIT_SMIS_ON_64BIT_ARCH=1 ++ ++CCFLAGS += -I$(AUTOV8_DIR)/include -I$(AUTOV8_DIR) ++ ++ifdef EXECUTION_TIMEOUT ++ CCFLAGS += -DEXECUTION_TIMEOUT ++endif ++ ++ifdef BIGINT_GRACEFUL ++ CCFLAGS += -DBIGINT_GRACEFUL ++endif ++ + + DATA = $(PLV8_DATA) + ifndef DISABLE_DIALECT +-- +2.49.0 + diff --git a/nix/ext/plv8/0001-build-Allow-using-V8-from-system-3.1.5.patch b/nix/ext/plv8/0001-build-Allow-using-V8-from-system-3.1.5.patch new file mode 100644 index 000000000..4be4abc5b --- /dev/null +++ b/nix/ext/plv8/0001-build-Allow-using-V8-from-system-3.1.5.patch @@ -0,0 +1,84 @@ +From 7523ea5bced10511688e73f6261857c04726a8a9 Mon Sep 17 00:00:00 2001 +From: Jan Tojnar +Date: Thu, 13 Oct 2022 10:16:32 +0200 +Subject: [PATCH] build: Allow using V8 from system + +Building V8 is slow and pointless on systems that already provide a recent version like some Linux distros. +With this change, you can build against system V8 with the following: + + make USE_SYSTEM_V8=1 SHLIB_LINK=-lv8 V8_OUTDIR=/usr/lib +--- + Makefile | 36 ++++++++++++++++++++---------------- + 1 file changed, 20 insertions(+), 16 deletions(-) + +diff --git a/Makefile b/Makefile +index 38879cc..a6abae5 100644 +--- a/Makefile ++++ b/Makefile +@@ -20,6 +20,7 @@ OBJS = $(SRCS:.cc=.o) + MODULE_big = plv8-$(PLV8_VERSION) + EXTENSION = plv8 + PLV8_DATA = plv8.control plv8--$(PLV8_VERSION).sql $(wildcard upgrade/*.sql) ++USE_SYSTEM_V8 = 0 + + + # Platform detection +@@ -41,6 +42,7 @@ PGXS := $(shell $(PG_CONFIG) --pgxs) + PG_VERSION_NUM := $(shell cat `$(PG_CONFIG) --includedir-server`/pg_config*.h \ + | perl -ne 'print $$1 and exit if /PG_VERSION_NUM\s+(\d+)/') + ++ifeq ($(USE_SYSTEM_V8),0) + AUTOV8_DIR = build/v8 + AUTOV8_OUT = build/v8/out.gn/obj + AUTOV8_STATIC_LIBS = -lv8_libplatform -lv8_libbase +@@ -67,22 +69,6 @@ v8: + endif + endif + +-# enable direct jsonb conversion by default +-CCFLAGS += -DJSONB_DIRECT_CONVERSION +- +-CCFLAGS += -DV8_COMPRESS_POINTERS=1 -DV8_31BIT_SMIS_ON_64BIT_ARCH=1 +- +-CCFLAGS += -I$(AUTOV8_DIR)/include -I$(AUTOV8_DIR) +- +-ifdef EXECUTION_TIMEOUT +- CCFLAGS += -DEXECUTION_TIMEOUT +-endif +- +-ifdef BIGINT_GRACEFUL +- CCFLAGS += -DBIGINT_GRACEFUL +-endif +- +- + # We're gonna build static link. Rip it out after include Makefile + SHLIB_LINK := $(filter-out -lv8, $(SHLIB_LINK)) + +@@ -101,6 +87,24 @@ else + SHLIB_LINK += -lrt -std=c++14 + endif + endif ++endif ++ ++ ++# enable direct jsonb conversion by default ++CCFLAGS += -DJSONB_DIRECT_CONVERSION ++ ++CCFLAGS += -DV8_COMPRESS_POINTERS=1 -DV8_31BIT_SMIS_ON_64BIT_ARCH=1 ++ ++CCFLAGS += -I$(AUTOV8_DIR)/include -I$(AUTOV8_DIR) ++ ++ifdef EXECUTION_TIMEOUT ++ CCFLAGS += -DEXECUTION_TIMEOUT ++endif ++ ++ifdef BIGINT_GRACEFUL ++ CCFLAGS += -DBIGINT_GRACEFUL ++endif ++ + + DATA = $(PLV8_DATA) + ifndef DISABLE_DIALECT +-- +2.49.0 + diff --git a/nix/ext/plv8/0001-build-Allow-using-V8-from-system-3.2.3.patch b/nix/ext/plv8/0001-build-Allow-using-V8-from-system-3.2.3.patch new file mode 100644 index 000000000..91417a16d --- /dev/null +++ b/nix/ext/plv8/0001-build-Allow-using-V8-from-system-3.2.3.patch @@ -0,0 +1,44 @@ +From bfe98c83bdcc0f3c33d836e03e6d4cf7199c8d37 Mon Sep 17 00:00:00 2001 +From: Jan Tojnar +Date: Thu, 13 Oct 2022 10:16:32 +0200 +Subject: [PATCH] build: Allow using V8 from system + +Building V8 is slow and pointless on systems that already provide a recent version like some Linux distros. +With this change, you can build against system V8 with the following: + + make USE_SYSTEM_V8=1 SHLIB_LINK=-lv8 V8_OUTDIR=/usr/lib +--- + Makefile | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/Makefile b/Makefile +index 1180fae..c74b23d 100644 +--- a/Makefile ++++ b/Makefile +@@ -13,6 +13,7 @@ OBJS = $(SRCS:.cc=.o) + MODULE_big = plv8-$(PLV8_VERSION) + EXTENSION = plv8 + PLV8_DATA = plv8.control plv8--$(PLV8_VERSION).sql ++USE_SYSTEM_V8 = 0 + + ifeq ($(OS),Windows_NT) + # noop for now +@@ -34,6 +35,7 @@ ifeq ($(NUMPROC),0) + NUMPROC = 1 + endif + ++ifeq ($(USE_SYSTEM_V8),0) + SHLIB_LINK += -Ldeps/v8-cmake/build + + all: v8 $(OBJS) +@@ -48,6 +50,7 @@ deps/v8-cmake/build/libv8_libbase.a: deps/v8-cmake/README.md + @cd deps/v8-cmake && mkdir -p build && cd build && cmake -Denable-fPIC=ON -DCMAKE_BUILD_TYPE=Release ../ && make -j $(NUMPROC) + + v8: deps/v8-cmake/build/libv8_libbase.a ++endif + + # enable direct jsonb conversion by default + CCFLAGS += -DJSONB_DIRECT_CONVERSION +-- +2.49.0 + diff --git a/nix/ext/plv8/0001-fix-upgrade-related-woes-with-GUC-redefinitions-3.1.10.patch b/nix/ext/plv8/0001-fix-upgrade-related-woes-with-GUC-redefinitions-3.1.10.patch new file mode 100644 index 000000000..2de022d23 --- /dev/null +++ b/nix/ext/plv8/0001-fix-upgrade-related-woes-with-GUC-redefinitions-3.1.10.patch @@ -0,0 +1,411 @@ +From 70242190410ed060aecd63e03ac341cc67f0c18e Mon Sep 17 00:00:00 2001 +From: Constantine Peresypkin +Date: Mon, 31 Jul 2023 19:36:01 -0400 +Subject: [PATCH] fix upgrade-related woes with GUC redefinitions + +Forward-port of #409 +--- + .gitignore | 1 + + Makefile | 2 +- + platforms/windows/CMakeLists.txt | 1 + + plv8.cc | 164 ++++++++++++++++++++----------- + plv8.h | 4 + + plv8_guc.cc | 138 ++++++++++++++++++++++++++ + 6 files changed, 249 insertions(+), 61 deletions(-) + create mode 100644 plv8_guc.cc + +diff --git a/.gitignore b/.gitignore +index 798df71..2b3e1a9 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -14,6 +14,7 @@ + # Generic build files + *.o + *.so ++*.bc + + # For static build + /build +diff --git a/Makefile b/Makefile +index c685051..dec0d90 100644 +--- a/Makefile ++++ b/Makefile +@@ -15,7 +15,7 @@ CUSTOM_CC = g++ + JSS = coffee-script.js livescript.js + # .cc created from .js + JSCS = $(JSS:.js=.cc) +-SRCS = plv8.cc plv8_type.cc plv8_func.cc plv8_param.cc plv8_allocator.cc $(JSCS) ++SRCS = plv8.cc plv8_type.cc plv8_func.cc plv8_param.cc plv8_allocator.cc plv8_guc.cc $(JSCS) + OBJS = $(SRCS:.cc=.o) + MODULE_big = plv8-$(PLV8_VERSION) + EXTENSION = plv8 +diff --git a/platforms/windows/CMakeLists.txt b/platforms/windows/CMakeLists.txt +index 1b787b8..070463e 100644 +--- a/platforms/windows/CMakeLists.txt ++++ b/platforms/windows/CMakeLists.txt +@@ -29,6 +29,7 @@ set(SOURCES + "livescript.cc" + "../plv8.cc" + "../plv8_func.cc" ++ "../plv8_guc.cc" + "../plv8_param.cc" + "../plv8_type.cc") + +diff --git a/plv8.cc b/plv8.cc +index c1ce883..80fecc7 100644 +--- a/plv8.cc ++++ b/plv8.cc +@@ -29,6 +29,7 @@ extern "C" { + #include "miscadmin.h" + #include "utils/builtins.h" + #include "utils/guc.h" ++#include "utils/guc_tables.h" + #include "utils/memutils.h" + #include "utils/lsyscache.h" + #include "utils/rel.h" +@@ -349,82 +350,125 @@ _PG_init(void) + hash_ctl.hash = oid_hash; + plv8_proc_cache_hash = hash_create("PLv8 Procedures", 32, + &hash_ctl, HASH_ELEM | HASH_FUNCTION); +- +- DefineCustomStringVariable("plv8.start_proc", +- gettext_noop("PLV8 function to run once when PLV8 is first used."), +- NULL, +- &plv8_start_proc, +- NULL, +- PGC_USERSET, 0, ++ config_generic *guc_value; ++ ++#define START_PROC_VAR "plv8.start_proc" ++ guc_value = plv8_find_option(START_PROC_VAR); ++ if (guc_value != NULL) { ++ plv8_start_proc = plv8_string_option(guc_value); ++ } else { ++ DefineCustomStringVariable(START_PROC_VAR, ++ gettext_noop("PLV8 function to run once when PLV8 is first used."), ++ NULL, ++ &plv8_start_proc, ++ NULL, ++ PGC_USERSET, 0, + #if PG_VERSION_NUM >= 90100 +- NULL, ++ NULL, + #endif +- NULL, +- NULL); +- +- DefineCustomStringVariable("plv8.icu_data", +- gettext_noop("ICU data file directory."), +- NULL, +- &plv8_icu_data, +- NULL, +- PGC_USERSET, 0, ++ NULL, ++ NULL); ++ } ++#undef START_PROC_VAR ++ ++#define ICU_DATA_VAR "plv8.icu_data" ++ guc_value = plv8_find_option(ICU_DATA_VAR); ++ if (guc_value != NULL) { ++ plv8_start_proc = plv8_string_option(guc_value); ++ } else { ++ DefineCustomStringVariable(ICU_DATA_VAR, ++ gettext_noop("ICU data file directory."), ++ NULL, ++ &plv8_icu_data, ++ NULL, ++ PGC_USERSET, 0, + #if PG_VERSION_NUM >= 90100 +- NULL, ++ NULL, + #endif +- NULL, +- NULL); +- +- DefineCustomStringVariable("plv8.v8_flags", +- gettext_noop("V8 engine initialization flags (e.g. --harmony for all current harmony features)."), +- NULL, +- &plv8_v8_flags, +- NULL, +- PGC_USERSET, 0, ++ NULL, ++ NULL); ++ } ++#undef ICU_DATA_VAR ++ ++#define V8_FLAGS_VAR "plv8.v8_flags" ++ guc_value = plv8_find_option(V8_FLAGS_VAR); ++ if (guc_value != NULL) { ++ plv8_start_proc = plv8_string_option(guc_value); ++ } else { ++ DefineCustomStringVariable(V8_FLAGS_VAR, ++ gettext_noop("V8 engine initialization flags (e.g. --harmony for all current harmony features)."), ++ NULL, ++ &plv8_v8_flags, ++ NULL, ++ PGC_USERSET, 0, + #if PG_VERSION_NUM >= 90100 +- NULL, ++ NULL, + #endif +- NULL, +- NULL); +- +- DefineCustomIntVariable("plv8.debugger_port", +- gettext_noop("V8 remote debug port."), +- gettext_noop("The default value is 35432. " +- "This is effective only if PLV8 is built with ENABLE_DEBUGGER_SUPPORT."), +- &plv8_debugger_port, +- 35432, 0, 65536, +- PGC_USERSET, 0, ++ NULL, ++ NULL); ++ } ++#undef V8_FLAGS_VAR ++ ++#define DEBUGGER_PORT_VAR "plv8.debugger_port" ++ guc_value = plv8_find_option(DEBUGGER_PORT_VAR); ++ if (guc_value != NULL) { ++ plv8_debugger_port = plv8_int_option(guc_value); ++ } else { ++ DefineCustomIntVariable(DEBUGGER_PORT_VAR, ++ gettext_noop("V8 remote debug port."), ++ gettext_noop("The default value is 35432. " ++ "This is effective only if PLV8 is built with ENABLE_DEBUGGER_SUPPORT."), ++ &plv8_debugger_port, ++ 35432, 0, 65536, ++ PGC_USERSET, 0, + #if PG_VERSION_NUM >= 90100 +- NULL, ++ NULL, + #endif +- NULL, +- NULL); ++ NULL, ++ NULL); ++ } ++#undef DEBUGGER_PORT_VAR + + #ifdef EXECUTION_TIMEOUT +- DefineCustomIntVariable("plv8.execution_timeout", +- gettext_noop("V8 execution timeout."), +- gettext_noop("The default value is 300 seconds. " +- "This allows you to override the default execution timeout."), +- &plv8_execution_timeout, +- 300, 1, 65536, +- PGC_USERSET, 0, ++#define EXECUTION_TIMEOUT_VAR "plv8.execution_timeout" ++ guc_value = plv8_find_option(EXECUTION_TIMEOUT_VAR); ++ if (guc_value != NULL) { ++ plv8_execution_timeout = plv8_int_option(guc_value); ++ } else { ++ DefineCustomIntVariable(EXECUTION_TIMEOUT_VAR, ++ gettext_noop("V8 execution timeout."), ++ gettext_noop("The default value is 300 seconds. " ++ "This allows you to override the default execution timeout."), ++ &plv8_execution_timeout, ++ 300, 1, 65536, ++ PGC_USERSET, 0, + #if PG_VERSION_NUM >= 90100 +- NULL, ++ NULL, + #endif +- NULL, +- NULL); ++ NULL, ++ NULL); ++ } ++#undef EXECUTION_TIMEOUT_VAR + #endif + +- DefineCustomIntVariable("plv8.memory_limit", +- gettext_noop("Per-isolate memory limit in MBytes"), +- gettext_noop("The default value is 256 MB"), +- (int*)&plv8_memory_limit, +- 256, 256, 3096, // hardcoded v8 limits for isolates +- PGC_SUSET, 0, ++#define MEMORY_LIMIT_VAR "plv8.memory_limit" ++ guc_value = plv8_find_option(MEMORY_LIMIT_VAR); ++ if (guc_value != NULL) { ++ plv8_memory_limit = plv8_int_option(guc_value); ++ } else { ++ DefineCustomIntVariable(MEMORY_LIMIT_VAR, ++ gettext_noop("Per-isolate memory limit in MBytes"), ++ gettext_noop("The default value is 256 MB"), ++ (int *) &plv8_memory_limit, ++ 256, 256, 3096, // hardcoded v8 limits for isolates ++ PGC_SUSET, 0, + #if PG_VERSION_NUM >= 90100 +- NULL, ++ NULL, + #endif +- NULL, +- NULL); ++ NULL, ++ NULL); ++ } ++#undef MEMORY_LIMIT_VAR + + RegisterXactCallback(plv8_xact_cb, NULL); + +diff --git a/plv8.h b/plv8.h +index 8fd1d66..ab12642 100644 +--- a/plv8.h ++++ b/plv8.h +@@ -306,4 +306,8 @@ extern void HandleUnhandledPromiseRejections(); + + extern void GetMemoryInfo(v8::Local obj); + ++extern struct config_generic *plv8_find_option(const char *name); ++char *plv8_string_option(struct config_generic * record); ++int plv8_int_option(struct config_generic * record); ++ + #endif // _PLV8_ +diff --git a/plv8_guc.cc b/plv8_guc.cc +new file mode 100644 +index 0000000..93b4daa +--- /dev/null ++++ b/plv8_guc.cc +@@ -0,0 +1,138 @@ ++/* ++ * This code was copied from postgres:src/backend/utils/misc/guc.c (with some changes) ++ * because public postgresql headers do not expose it for some reason ++ * there is GetConfigOptionName(), GetConfigOption(), GetConfigOptionFlags() ++ * unfortunately none of these answer a simple question: does GUC variable exist? ++ * and all of them fail hard if not provided with "missing_ok = true" ++ */ ++ ++#include "plv8.h" ++ ++extern "C" { ++#include "utils/guc.h" ++#include "utils/guc_tables.h" ++} ++ ++/* ++ * To allow continued support of obsolete names for GUC variables, we apply ++ * the following mappings to any unrecognized name. Note that an old name ++ * should be mapped to a new one only if the new variable has very similar ++ * semantics to the old. ++ */ ++static const char *const map_old_guc_names[] = { ++ /* The format is ++ * "old_name", "new_name", ++ */ ++ NULL ++}; ++ ++static int plv8_guc_name_compare(const char *, const char *); ++static int plv8_guc_var_compare(const void *, const void *); ++ ++char * ++plv8_string_option(struct config_generic *record) { ++ if (record->vartype != PGC_STRING) ++ elog(ERROR, "'%s' is not a string", record->name); ++ ++ auto *conf = (struct config_string *) record; ++ if (*conf->variable && **conf->variable) ++ return *conf->variable; ++ return pstrdup(""); ++} ++ ++int ++plv8_int_option(struct config_generic *record) { ++ if (record->vartype != PGC_INT) ++ elog(ERROR, "'%s' is not an int", record->name); ++ ++ auto *conf = (struct config_int *) record; ++ return *conf->variable; ++} ++ ++/* ++ * Look up option NAME. If it exists, return a pointer to its record, ++ * else return NULL. ++ */ ++struct config_generic * ++plv8_find_option(const char *name) ++{ ++ const char **key = &name; ++ struct config_generic **res; ++ int i; ++ ++ /* ++ * By equating const char ** with struct config_generic *, we are assuming ++ * the name field is first in config_generic. ++ */ ++ res = (struct config_generic **) bsearch((void *) &key, ++ (void *) get_guc_variables(), ++ GetNumConfigOptions(), ++ sizeof(struct config_generic *), ++ plv8_guc_var_compare); ++ /* ++ * Return NULL for placeholders, ++ * these can be safely overwritten by DefineCustomTYPEVariable() functions ++ */ ++ if (res) { ++ if ((*res)->flags & GUC_CUSTOM_PLACEHOLDER) ++ return NULL; ++ return *res; ++ } ++ ++ /* ++ * See if the name is an obsolete name for a variable. We assume that the ++ * set of supported old names is short enough that a brute-force search is ++ * the best way. ++ */ ++ for (i = 0; map_old_guc_names[i] != NULL; i += 2) ++ { ++ if (plv8_guc_name_compare(name, map_old_guc_names[i]) == 0) ++ return plv8_find_option(map_old_guc_names[i + 1]); ++ } ++ ++ /* Unknown name */ ++ return NULL; ++} ++ ++ ++/* ++ * comparator for qsorting and bsearching guc_variables array ++ */ ++static int ++plv8_guc_var_compare(const void *a, const void *b) ++{ ++ const struct config_generic *confa = *(struct config_generic *const *) a; ++ const struct config_generic *confb = *(struct config_generic *const *) b; ++ ++ return plv8_guc_name_compare(confa->name, confb->name); ++} ++ ++/* ++ * the bare comparison function for GUC names ++ */ ++static int ++plv8_guc_name_compare(const char *namea, const char *nameb) ++{ ++ /* ++ * The temptation to use strcasecmp() here must be resisted, because the ++ * array ordering has to remain stable across setlocale() calls. So, build ++ * our own with a simple ASCII-only downcasing. ++ */ ++ while (*namea && *nameb) ++ { ++ char cha = *namea++; ++ char chb = *nameb++; ++ ++ if (cha >= 'A' && cha <= 'Z') ++ cha += 'a' - 'A'; ++ if (chb >= 'A' && chb <= 'Z') ++ chb += 'a' - 'A'; ++ if (cha != chb) ++ return cha - chb; ++ } ++ if (*namea) ++ return 1; /* a is longer */ ++ if (*nameb) ++ return -1; /* b is longer */ ++ return 0; ++} +-- +2.49.0 + diff --git a/nix/ext/plv8/0001-fix-upgrade-related-woes-with-GUC-redefinitions-3.1.4.patch b/nix/ext/plv8/0001-fix-upgrade-related-woes-with-GUC-redefinitions-3.1.4.patch new file mode 100644 index 000000000..a5f17bc81 --- /dev/null +++ b/nix/ext/plv8/0001-fix-upgrade-related-woes-with-GUC-redefinitions-3.1.4.patch @@ -0,0 +1,411 @@ +From 9c280302b5b8628e5b8635be63c8cbef55f5d98c Mon Sep 17 00:00:00 2001 +From: Constantine Peresypkin +Date: Mon, 31 Jul 2023 19:36:01 -0400 +Subject: [PATCH] fix upgrade-related woes with GUC redefinitions + +Forward-port of #409 +--- + .gitignore | 1 + + Makefile | 2 +- + platforms/windows/CMakeLists.txt | 1 + + plv8.cc | 164 ++++++++++++++++++++----------- + plv8.h | 4 + + plv8_guc.cc | 138 ++++++++++++++++++++++++++ + 6 files changed, 249 insertions(+), 61 deletions(-) + create mode 100644 plv8_guc.cc + +diff --git a/.gitignore b/.gitignore +index 798df71..2b3e1a9 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -14,6 +14,7 @@ + # Generic build files + *.o + *.so ++*.bc + + # For static build + /build +diff --git a/Makefile b/Makefile +index cfa50bc..6d5e202 100644 +--- a/Makefile ++++ b/Makefile +@@ -15,7 +15,7 @@ CUSTOM_CC = g++ + JSS = coffee-script.js livescript.js + # .cc created from .js + JSCS = $(JSS:.js=.cc) +-SRCS = plv8.cc plv8_type.cc plv8_func.cc plv8_param.cc plv8_allocator.cc $(JSCS) ++SRCS = plv8.cc plv8_type.cc plv8_func.cc plv8_param.cc plv8_allocator.cc plv8_guc.cc $(JSCS) + OBJS = $(SRCS:.cc=.o) + MODULE_big = plv8-$(PLV8_VERSION) + EXTENSION = plv8 +diff --git a/platforms/windows/CMakeLists.txt b/platforms/windows/CMakeLists.txt +index 1b787b8..070463e 100644 +--- a/platforms/windows/CMakeLists.txt ++++ b/platforms/windows/CMakeLists.txt +@@ -29,6 +29,7 @@ set(SOURCES + "livescript.cc" + "../plv8.cc" + "../plv8_func.cc" ++ "../plv8_guc.cc" + "../plv8_param.cc" + "../plv8_type.cc") + +diff --git a/plv8.cc b/plv8.cc +index 843da9c..986f23c 100644 +--- a/plv8.cc ++++ b/plv8.cc +@@ -29,6 +29,7 @@ extern "C" { + #include "miscadmin.h" + #include "utils/builtins.h" + #include "utils/guc.h" ++#include "utils/guc_tables.h" + #include "utils/memutils.h" + #include "utils/lsyscache.h" + #include "utils/rel.h" +@@ -349,82 +350,125 @@ _PG_init(void) + hash_ctl.hash = oid_hash; + plv8_proc_cache_hash = hash_create("PLv8 Procedures", 32, + &hash_ctl, HASH_ELEM | HASH_FUNCTION); +- +- DefineCustomStringVariable("plv8.start_proc", +- gettext_noop("PLV8 function to run once when PLV8 is first used."), +- NULL, +- &plv8_start_proc, +- NULL, +- PGC_USERSET, 0, ++ config_generic *guc_value; ++ ++#define START_PROC_VAR "plv8.start_proc" ++ guc_value = plv8_find_option(START_PROC_VAR); ++ if (guc_value != NULL) { ++ plv8_start_proc = plv8_string_option(guc_value); ++ } else { ++ DefineCustomStringVariable(START_PROC_VAR, ++ gettext_noop("PLV8 function to run once when PLV8 is first used."), ++ NULL, ++ &plv8_start_proc, ++ NULL, ++ PGC_USERSET, 0, + #if PG_VERSION_NUM >= 90100 +- NULL, ++ NULL, + #endif +- NULL, +- NULL); +- +- DefineCustomStringVariable("plv8.icu_data", +- gettext_noop("ICU data file directory."), +- NULL, +- &plv8_icu_data, +- NULL, +- PGC_USERSET, 0, ++ NULL, ++ NULL); ++ } ++#undef START_PROC_VAR ++ ++#define ICU_DATA_VAR "plv8.icu_data" ++ guc_value = plv8_find_option(ICU_DATA_VAR); ++ if (guc_value != NULL) { ++ plv8_start_proc = plv8_string_option(guc_value); ++ } else { ++ DefineCustomStringVariable(ICU_DATA_VAR, ++ gettext_noop("ICU data file directory."), ++ NULL, ++ &plv8_icu_data, ++ NULL, ++ PGC_USERSET, 0, + #if PG_VERSION_NUM >= 90100 +- NULL, ++ NULL, + #endif +- NULL, +- NULL); +- +- DefineCustomStringVariable("plv8.v8_flags", +- gettext_noop("V8 engine initialization flags (e.g. --harmony for all current harmony features)."), +- NULL, +- &plv8_v8_flags, +- NULL, +- PGC_USERSET, 0, ++ NULL, ++ NULL); ++ } ++#undef ICU_DATA_VAR ++ ++#define V8_FLAGS_VAR "plv8.v8_flags" ++ guc_value = plv8_find_option(V8_FLAGS_VAR); ++ if (guc_value != NULL) { ++ plv8_start_proc = plv8_string_option(guc_value); ++ } else { ++ DefineCustomStringVariable(V8_FLAGS_VAR, ++ gettext_noop("V8 engine initialization flags (e.g. --harmony for all current harmony features)."), ++ NULL, ++ &plv8_v8_flags, ++ NULL, ++ PGC_USERSET, 0, + #if PG_VERSION_NUM >= 90100 +- NULL, ++ NULL, + #endif +- NULL, +- NULL); +- +- DefineCustomIntVariable("plv8.debugger_port", +- gettext_noop("V8 remote debug port."), +- gettext_noop("The default value is 35432. " +- "This is effective only if PLV8 is built with ENABLE_DEBUGGER_SUPPORT."), +- &plv8_debugger_port, +- 35432, 0, 65536, +- PGC_USERSET, 0, ++ NULL, ++ NULL); ++ } ++#undef V8_FLAGS_VAR ++ ++#define DEBUGGER_PORT_VAR "plv8.debugger_port" ++ guc_value = plv8_find_option(DEBUGGER_PORT_VAR); ++ if (guc_value != NULL) { ++ plv8_debugger_port = plv8_int_option(guc_value); ++ } else { ++ DefineCustomIntVariable(DEBUGGER_PORT_VAR, ++ gettext_noop("V8 remote debug port."), ++ gettext_noop("The default value is 35432. " ++ "This is effective only if PLV8 is built with ENABLE_DEBUGGER_SUPPORT."), ++ &plv8_debugger_port, ++ 35432, 0, 65536, ++ PGC_USERSET, 0, + #if PG_VERSION_NUM >= 90100 +- NULL, ++ NULL, + #endif +- NULL, +- NULL); ++ NULL, ++ NULL); ++ } ++#undef DEBUGGER_PORT_VAR + + #ifdef EXECUTION_TIMEOUT +- DefineCustomIntVariable("plv8.execution_timeout", +- gettext_noop("V8 execution timeout."), +- gettext_noop("The default value is 300 seconds. " +- "This allows you to override the default execution timeout."), +- &plv8_execution_timeout, +- 300, 1, 65536, +- PGC_USERSET, 0, ++#define EXECUTION_TIMEOUT_VAR "plv8.execution_timeout" ++ guc_value = plv8_find_option(EXECUTION_TIMEOUT_VAR); ++ if (guc_value != NULL) { ++ plv8_execution_timeout = plv8_int_option(guc_value); ++ } else { ++ DefineCustomIntVariable(EXECUTION_TIMEOUT_VAR, ++ gettext_noop("V8 execution timeout."), ++ gettext_noop("The default value is 300 seconds. " ++ "This allows you to override the default execution timeout."), ++ &plv8_execution_timeout, ++ 300, 1, 65536, ++ PGC_USERSET, 0, + #if PG_VERSION_NUM >= 90100 +- NULL, ++ NULL, + #endif +- NULL, +- NULL); ++ NULL, ++ NULL); ++ } ++#undef EXECUTION_TIMEOUT_VAR + #endif + +- DefineCustomIntVariable("plv8.memory_limit", +- gettext_noop("Per-isolate memory limit in MBytes"), +- gettext_noop("The default value is 256 MB"), +- (int*)&plv8_memory_limit, +- 256, 256, 3096, // hardcoded v8 limits for isolates +- PGC_SUSET, 0, ++#define MEMORY_LIMIT_VAR "plv8.memory_limit" ++ guc_value = plv8_find_option(MEMORY_LIMIT_VAR); ++ if (guc_value != NULL) { ++ plv8_memory_limit = plv8_int_option(guc_value); ++ } else { ++ DefineCustomIntVariable(MEMORY_LIMIT_VAR, ++ gettext_noop("Per-isolate memory limit in MBytes"), ++ gettext_noop("The default value is 256 MB"), ++ (int *) &plv8_memory_limit, ++ 256, 256, 3096, // hardcoded v8 limits for isolates ++ PGC_SUSET, 0, + #if PG_VERSION_NUM >= 90100 +- NULL, ++ NULL, + #endif +- NULL, +- NULL); ++ NULL, ++ NULL); ++ } ++#undef MEMORY_LIMIT_VAR + + RegisterXactCallback(plv8_xact_cb, NULL); + +diff --git a/plv8.h b/plv8.h +index 8fd1d66..ab12642 100644 +--- a/plv8.h ++++ b/plv8.h +@@ -306,4 +306,8 @@ extern void HandleUnhandledPromiseRejections(); + + extern void GetMemoryInfo(v8::Local obj); + ++extern struct config_generic *plv8_find_option(const char *name); ++char *plv8_string_option(struct config_generic * record); ++int plv8_int_option(struct config_generic * record); ++ + #endif // _PLV8_ +diff --git a/plv8_guc.cc b/plv8_guc.cc +new file mode 100644 +index 0000000..93b4daa +--- /dev/null ++++ b/plv8_guc.cc +@@ -0,0 +1,138 @@ ++/* ++ * This code was copied from postgres:src/backend/utils/misc/guc.c (with some changes) ++ * because public postgresql headers do not expose it for some reason ++ * there is GetConfigOptionName(), GetConfigOption(), GetConfigOptionFlags() ++ * unfortunately none of these answer a simple question: does GUC variable exist? ++ * and all of them fail hard if not provided with "missing_ok = true" ++ */ ++ ++#include "plv8.h" ++ ++extern "C" { ++#include "utils/guc.h" ++#include "utils/guc_tables.h" ++} ++ ++/* ++ * To allow continued support of obsolete names for GUC variables, we apply ++ * the following mappings to any unrecognized name. Note that an old name ++ * should be mapped to a new one only if the new variable has very similar ++ * semantics to the old. ++ */ ++static const char *const map_old_guc_names[] = { ++ /* The format is ++ * "old_name", "new_name", ++ */ ++ NULL ++}; ++ ++static int plv8_guc_name_compare(const char *, const char *); ++static int plv8_guc_var_compare(const void *, const void *); ++ ++char * ++plv8_string_option(struct config_generic *record) { ++ if (record->vartype != PGC_STRING) ++ elog(ERROR, "'%s' is not a string", record->name); ++ ++ auto *conf = (struct config_string *) record; ++ if (*conf->variable && **conf->variable) ++ return *conf->variable; ++ return pstrdup(""); ++} ++ ++int ++plv8_int_option(struct config_generic *record) { ++ if (record->vartype != PGC_INT) ++ elog(ERROR, "'%s' is not an int", record->name); ++ ++ auto *conf = (struct config_int *) record; ++ return *conf->variable; ++} ++ ++/* ++ * Look up option NAME. If it exists, return a pointer to its record, ++ * else return NULL. ++ */ ++struct config_generic * ++plv8_find_option(const char *name) ++{ ++ const char **key = &name; ++ struct config_generic **res; ++ int i; ++ ++ /* ++ * By equating const char ** with struct config_generic *, we are assuming ++ * the name field is first in config_generic. ++ */ ++ res = (struct config_generic **) bsearch((void *) &key, ++ (void *) get_guc_variables(), ++ GetNumConfigOptions(), ++ sizeof(struct config_generic *), ++ plv8_guc_var_compare); ++ /* ++ * Return NULL for placeholders, ++ * these can be safely overwritten by DefineCustomTYPEVariable() functions ++ */ ++ if (res) { ++ if ((*res)->flags & GUC_CUSTOM_PLACEHOLDER) ++ return NULL; ++ return *res; ++ } ++ ++ /* ++ * See if the name is an obsolete name for a variable. We assume that the ++ * set of supported old names is short enough that a brute-force search is ++ * the best way. ++ */ ++ for (i = 0; map_old_guc_names[i] != NULL; i += 2) ++ { ++ if (plv8_guc_name_compare(name, map_old_guc_names[i]) == 0) ++ return plv8_find_option(map_old_guc_names[i + 1]); ++ } ++ ++ /* Unknown name */ ++ return NULL; ++} ++ ++ ++/* ++ * comparator for qsorting and bsearching guc_variables array ++ */ ++static int ++plv8_guc_var_compare(const void *a, const void *b) ++{ ++ const struct config_generic *confa = *(struct config_generic *const *) a; ++ const struct config_generic *confb = *(struct config_generic *const *) b; ++ ++ return plv8_guc_name_compare(confa->name, confb->name); ++} ++ ++/* ++ * the bare comparison function for GUC names ++ */ ++static int ++plv8_guc_name_compare(const char *namea, const char *nameb) ++{ ++ /* ++ * The temptation to use strcasecmp() here must be resisted, because the ++ * array ordering has to remain stable across setlocale() calls. So, build ++ * our own with a simple ASCII-only downcasing. ++ */ ++ while (*namea && *nameb) ++ { ++ char cha = *namea++; ++ char chb = *nameb++; ++ ++ if (cha >= 'A' && cha <= 'Z') ++ cha += 'a' - 'A'; ++ if (chb >= 'A' && chb <= 'Z') ++ chb += 'a' - 'A'; ++ if (cha != chb) ++ return cha - chb; ++ } ++ if (*namea) ++ return 1; /* a is longer */ ++ if (*nameb) ++ return -1; /* b is longer */ ++ return 0; ++} +-- +2.49.0 + diff --git a/nix/ext/plv8/0001-fix-upgrade-related-woes-with-GUC-redefinitions-3.1.5.patch b/nix/ext/plv8/0001-fix-upgrade-related-woes-with-GUC-redefinitions-3.1.5.patch new file mode 100644 index 000000000..045d30daa --- /dev/null +++ b/nix/ext/plv8/0001-fix-upgrade-related-woes-with-GUC-redefinitions-3.1.5.patch @@ -0,0 +1,411 @@ +From 7657cb9744cfd92b2f7239ab3271d3f004751c3a Mon Sep 17 00:00:00 2001 +From: Constantine Peresypkin +Date: Mon, 31 Jul 2023 19:36:01 -0400 +Subject: [PATCH] fix upgrade-related woes with GUC redefinitions + +Forward-port of #409 +--- + .gitignore | 1 + + Makefile | 2 +- + platforms/windows/CMakeLists.txt | 1 + + plv8.cc | 164 ++++++++++++++++++++----------- + plv8.h | 4 + + plv8_guc.cc | 138 ++++++++++++++++++++++++++ + 6 files changed, 249 insertions(+), 61 deletions(-) + create mode 100644 plv8_guc.cc + +diff --git a/.gitignore b/.gitignore +index 798df71..2b3e1a9 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -14,6 +14,7 @@ + # Generic build files + *.o + *.so ++*.bc + + # For static build + /build +diff --git a/Makefile b/Makefile +index b8ccb7f..48172d9 100644 +--- a/Makefile ++++ b/Makefile +@@ -15,7 +15,7 @@ CUSTOM_CC = g++ + JSS = coffee-script.js livescript.js + # .cc created from .js + JSCS = $(JSS:.js=.cc) +-SRCS = plv8.cc plv8_type.cc plv8_func.cc plv8_param.cc plv8_allocator.cc $(JSCS) ++SRCS = plv8.cc plv8_type.cc plv8_func.cc plv8_param.cc plv8_allocator.cc plv8_guc.cc $(JSCS) + OBJS = $(SRCS:.cc=.o) + MODULE_big = plv8-$(PLV8_VERSION) + EXTENSION = plv8 +diff --git a/platforms/windows/CMakeLists.txt b/platforms/windows/CMakeLists.txt +index 1b787b8..070463e 100644 +--- a/platforms/windows/CMakeLists.txt ++++ b/platforms/windows/CMakeLists.txt +@@ -29,6 +29,7 @@ set(SOURCES + "livescript.cc" + "../plv8.cc" + "../plv8_func.cc" ++ "../plv8_guc.cc" + "../plv8_param.cc" + "../plv8_type.cc") + +diff --git a/plv8.cc b/plv8.cc +index abbd828..4404a1c 100644 +--- a/plv8.cc ++++ b/plv8.cc +@@ -29,6 +29,7 @@ extern "C" { + #include "miscadmin.h" + #include "utils/builtins.h" + #include "utils/guc.h" ++#include "utils/guc_tables.h" + #include "utils/memutils.h" + #include "utils/lsyscache.h" + #include "utils/rel.h" +@@ -349,82 +350,125 @@ _PG_init(void) + hash_ctl.hash = oid_hash; + plv8_proc_cache_hash = hash_create("PLv8 Procedures", 32, + &hash_ctl, HASH_ELEM | HASH_FUNCTION); +- +- DefineCustomStringVariable("plv8.start_proc", +- gettext_noop("PLV8 function to run once when PLV8 is first used."), +- NULL, +- &plv8_start_proc, +- NULL, +- PGC_USERSET, 0, ++ config_generic *guc_value; ++ ++#define START_PROC_VAR "plv8.start_proc" ++ guc_value = plv8_find_option(START_PROC_VAR); ++ if (guc_value != NULL) { ++ plv8_start_proc = plv8_string_option(guc_value); ++ } else { ++ DefineCustomStringVariable(START_PROC_VAR, ++ gettext_noop("PLV8 function to run once when PLV8 is first used."), ++ NULL, ++ &plv8_start_proc, ++ NULL, ++ PGC_USERSET, 0, + #if PG_VERSION_NUM >= 90100 +- NULL, ++ NULL, + #endif +- NULL, +- NULL); +- +- DefineCustomStringVariable("plv8.icu_data", +- gettext_noop("ICU data file directory."), +- NULL, +- &plv8_icu_data, +- NULL, +- PGC_USERSET, 0, ++ NULL, ++ NULL); ++ } ++#undef START_PROC_VAR ++ ++#define ICU_DATA_VAR "plv8.icu_data" ++ guc_value = plv8_find_option(ICU_DATA_VAR); ++ if (guc_value != NULL) { ++ plv8_start_proc = plv8_string_option(guc_value); ++ } else { ++ DefineCustomStringVariable(ICU_DATA_VAR, ++ gettext_noop("ICU data file directory."), ++ NULL, ++ &plv8_icu_data, ++ NULL, ++ PGC_USERSET, 0, + #if PG_VERSION_NUM >= 90100 +- NULL, ++ NULL, + #endif +- NULL, +- NULL); +- +- DefineCustomStringVariable("plv8.v8_flags", +- gettext_noop("V8 engine initialization flags (e.g. --harmony for all current harmony features)."), +- NULL, +- &plv8_v8_flags, +- NULL, +- PGC_USERSET, 0, ++ NULL, ++ NULL); ++ } ++#undef ICU_DATA_VAR ++ ++#define V8_FLAGS_VAR "plv8.v8_flags" ++ guc_value = plv8_find_option(V8_FLAGS_VAR); ++ if (guc_value != NULL) { ++ plv8_start_proc = plv8_string_option(guc_value); ++ } else { ++ DefineCustomStringVariable(V8_FLAGS_VAR, ++ gettext_noop("V8 engine initialization flags (e.g. --harmony for all current harmony features)."), ++ NULL, ++ &plv8_v8_flags, ++ NULL, ++ PGC_USERSET, 0, + #if PG_VERSION_NUM >= 90100 +- NULL, ++ NULL, + #endif +- NULL, +- NULL); +- +- DefineCustomIntVariable("plv8.debugger_port", +- gettext_noop("V8 remote debug port."), +- gettext_noop("The default value is 35432. " +- "This is effective only if PLV8 is built with ENABLE_DEBUGGER_SUPPORT."), +- &plv8_debugger_port, +- 35432, 0, 65536, +- PGC_USERSET, 0, ++ NULL, ++ NULL); ++ } ++#undef V8_FLAGS_VAR ++ ++#define DEBUGGER_PORT_VAR "plv8.debugger_port" ++ guc_value = plv8_find_option(DEBUGGER_PORT_VAR); ++ if (guc_value != NULL) { ++ plv8_debugger_port = plv8_int_option(guc_value); ++ } else { ++ DefineCustomIntVariable(DEBUGGER_PORT_VAR, ++ gettext_noop("V8 remote debug port."), ++ gettext_noop("The default value is 35432. " ++ "This is effective only if PLV8 is built with ENABLE_DEBUGGER_SUPPORT."), ++ &plv8_debugger_port, ++ 35432, 0, 65536, ++ PGC_USERSET, 0, + #if PG_VERSION_NUM >= 90100 +- NULL, ++ NULL, + #endif +- NULL, +- NULL); ++ NULL, ++ NULL); ++ } ++#undef DEBUGGER_PORT_VAR + + #ifdef EXECUTION_TIMEOUT +- DefineCustomIntVariable("plv8.execution_timeout", +- gettext_noop("V8 execution timeout."), +- gettext_noop("The default value is 300 seconds. " +- "This allows you to override the default execution timeout."), +- &plv8_execution_timeout, +- 300, 1, 65536, +- PGC_USERSET, 0, ++#define EXECUTION_TIMEOUT_VAR "plv8.execution_timeout" ++ guc_value = plv8_find_option(EXECUTION_TIMEOUT_VAR); ++ if (guc_value != NULL) { ++ plv8_execution_timeout = plv8_int_option(guc_value); ++ } else { ++ DefineCustomIntVariable(EXECUTION_TIMEOUT_VAR, ++ gettext_noop("V8 execution timeout."), ++ gettext_noop("The default value is 300 seconds. " ++ "This allows you to override the default execution timeout."), ++ &plv8_execution_timeout, ++ 300, 1, 65536, ++ PGC_USERSET, 0, + #if PG_VERSION_NUM >= 90100 +- NULL, ++ NULL, + #endif +- NULL, +- NULL); ++ NULL, ++ NULL); ++ } ++#undef EXECUTION_TIMEOUT_VAR + #endif + +- DefineCustomIntVariable("plv8.memory_limit", +- gettext_noop("Per-isolate memory limit in MBytes"), +- gettext_noop("The default value is 256 MB"), +- (int*)&plv8_memory_limit, +- 256, 256, 3096, // hardcoded v8 limits for isolates +- PGC_SUSET, 0, ++#define MEMORY_LIMIT_VAR "plv8.memory_limit" ++ guc_value = plv8_find_option(MEMORY_LIMIT_VAR); ++ if (guc_value != NULL) { ++ plv8_memory_limit = plv8_int_option(guc_value); ++ } else { ++ DefineCustomIntVariable(MEMORY_LIMIT_VAR, ++ gettext_noop("Per-isolate memory limit in MBytes"), ++ gettext_noop("The default value is 256 MB"), ++ (int *) &plv8_memory_limit, ++ 256, 256, 3096, // hardcoded v8 limits for isolates ++ PGC_SUSET, 0, + #if PG_VERSION_NUM >= 90100 +- NULL, ++ NULL, + #endif +- NULL, +- NULL); ++ NULL, ++ NULL); ++ } ++#undef MEMORY_LIMIT_VAR + + RegisterXactCallback(plv8_xact_cb, NULL); + +diff --git a/plv8.h b/plv8.h +index 8fd1d66..ab12642 100644 +--- a/plv8.h ++++ b/plv8.h +@@ -306,4 +306,8 @@ extern void HandleUnhandledPromiseRejections(); + + extern void GetMemoryInfo(v8::Local obj); + ++extern struct config_generic *plv8_find_option(const char *name); ++char *plv8_string_option(struct config_generic * record); ++int plv8_int_option(struct config_generic * record); ++ + #endif // _PLV8_ +diff --git a/plv8_guc.cc b/plv8_guc.cc +new file mode 100644 +index 0000000..93b4daa +--- /dev/null ++++ b/plv8_guc.cc +@@ -0,0 +1,138 @@ ++/* ++ * This code was copied from postgres:src/backend/utils/misc/guc.c (with some changes) ++ * because public postgresql headers do not expose it for some reason ++ * there is GetConfigOptionName(), GetConfigOption(), GetConfigOptionFlags() ++ * unfortunately none of these answer a simple question: does GUC variable exist? ++ * and all of them fail hard if not provided with "missing_ok = true" ++ */ ++ ++#include "plv8.h" ++ ++extern "C" { ++#include "utils/guc.h" ++#include "utils/guc_tables.h" ++} ++ ++/* ++ * To allow continued support of obsolete names for GUC variables, we apply ++ * the following mappings to any unrecognized name. Note that an old name ++ * should be mapped to a new one only if the new variable has very similar ++ * semantics to the old. ++ */ ++static const char *const map_old_guc_names[] = { ++ /* The format is ++ * "old_name", "new_name", ++ */ ++ NULL ++}; ++ ++static int plv8_guc_name_compare(const char *, const char *); ++static int plv8_guc_var_compare(const void *, const void *); ++ ++char * ++plv8_string_option(struct config_generic *record) { ++ if (record->vartype != PGC_STRING) ++ elog(ERROR, "'%s' is not a string", record->name); ++ ++ auto *conf = (struct config_string *) record; ++ if (*conf->variable && **conf->variable) ++ return *conf->variable; ++ return pstrdup(""); ++} ++ ++int ++plv8_int_option(struct config_generic *record) { ++ if (record->vartype != PGC_INT) ++ elog(ERROR, "'%s' is not an int", record->name); ++ ++ auto *conf = (struct config_int *) record; ++ return *conf->variable; ++} ++ ++/* ++ * Look up option NAME. If it exists, return a pointer to its record, ++ * else return NULL. ++ */ ++struct config_generic * ++plv8_find_option(const char *name) ++{ ++ const char **key = &name; ++ struct config_generic **res; ++ int i; ++ ++ /* ++ * By equating const char ** with struct config_generic *, we are assuming ++ * the name field is first in config_generic. ++ */ ++ res = (struct config_generic **) bsearch((void *) &key, ++ (void *) get_guc_variables(), ++ GetNumConfigOptions(), ++ sizeof(struct config_generic *), ++ plv8_guc_var_compare); ++ /* ++ * Return NULL for placeholders, ++ * these can be safely overwritten by DefineCustomTYPEVariable() functions ++ */ ++ if (res) { ++ if ((*res)->flags & GUC_CUSTOM_PLACEHOLDER) ++ return NULL; ++ return *res; ++ } ++ ++ /* ++ * See if the name is an obsolete name for a variable. We assume that the ++ * set of supported old names is short enough that a brute-force search is ++ * the best way. ++ */ ++ for (i = 0; map_old_guc_names[i] != NULL; i += 2) ++ { ++ if (plv8_guc_name_compare(name, map_old_guc_names[i]) == 0) ++ return plv8_find_option(map_old_guc_names[i + 1]); ++ } ++ ++ /* Unknown name */ ++ return NULL; ++} ++ ++ ++/* ++ * comparator for qsorting and bsearching guc_variables array ++ */ ++static int ++plv8_guc_var_compare(const void *a, const void *b) ++{ ++ const struct config_generic *confa = *(struct config_generic *const *) a; ++ const struct config_generic *confb = *(struct config_generic *const *) b; ++ ++ return plv8_guc_name_compare(confa->name, confb->name); ++} ++ ++/* ++ * the bare comparison function for GUC names ++ */ ++static int ++plv8_guc_name_compare(const char *namea, const char *nameb) ++{ ++ /* ++ * The temptation to use strcasecmp() here must be resisted, because the ++ * array ordering has to remain stable across setlocale() calls. So, build ++ * our own with a simple ASCII-only downcasing. ++ */ ++ while (*namea && *nameb) ++ { ++ char cha = *namea++; ++ char chb = *nameb++; ++ ++ if (cha >= 'A' && cha <= 'Z') ++ cha += 'a' - 'A'; ++ if (chb >= 'A' && chb <= 'Z') ++ chb += 'a' - 'A'; ++ if (cha != chb) ++ return cha - chb; ++ } ++ if (*namea) ++ return 1; /* a is longer */ ++ if (*nameb) ++ return -1; /* b is longer */ ++ return 0; ++} +-- +2.49.0 + diff --git a/nix/ext/plv8/default.nix b/nix/ext/plv8/default.nix new file mode 100644 index 000000000..1482f57a5 --- /dev/null +++ b/nix/ext/plv8/default.nix @@ -0,0 +1,243 @@ +{ + stdenv, + lib, + fetchFromGitHub, + v8, + perl, + postgresql, + # For passthru test on various systems, and local development on macos + # not we are not currently using passthru tests but retaining for possible contrib + # to nixpkgs + clang, + xcbuild, + darwin, + patchelf, + buildEnv, + nodejs_20 +}: + +let + pname = "plv8"; + + # Load version configuration from external file + allVersions = (builtins.fromJSON (builtins.readFile ../versions.json)).${pname}; + + # Filter versions compatible with current PostgreSQL version + supportedVersions = lib.filterAttrs ( + _: value: builtins.elem (lib.versions.major postgresql.version) value.postgresql + ) allVersions; + + # Derived version information + versions = lib.naturalSort (lib.attrNames supportedVersions); + latestVersion = lib.last versions; + numberOfVersions = builtins.length versions; + packages = builtins.attrValues ( + lib.mapAttrs (name: value: build name value.hash) supportedVersions + ); + + # Build function for individual versions + build = + version: hash: + stdenv.mkDerivation (finalAttrs: { + inherit pname version; + #version = "3.1.10"; + + src = fetchFromGitHub { + owner = "plv8"; + repo = "plv8"; + rev = "v${finalAttrs.version}"; + inherit hash; + }; + + patches = [ + # Allow building with system v8. + # https://github.com/plv8/plv8/pull/505 (rejected) + ./0001-build-Allow-using-V8-from-system-${version}.patch + ] ++ lib.optionals (builtins.compareVersions "3.1.10" version >= 0) [ + # Apply https://github.com/plv8/plv8/pull/552/ patch to fix extension upgrade problems + ./0001-fix-upgrade-related-woes-with-GUC-redefinitions-${version}.patch + ]; + + nativeBuildInputs = + [ + perl + ] + ++ lib.optionals stdenv.isDarwin [ + clang + xcbuild + ]; + + buildInputs = + [ + (if (builtins.compareVersions "3.1.10" version >= 0) then v8 else nodejs_20.libv8) + postgresql + ] + ++ lib.optionals stdenv.isDarwin [ + darwin.apple_sdk.frameworks.CoreFoundation + darwin.apple_sdk.frameworks.Kerberos + ]; + + buildFlags = [ "all" ]; + + makeFlags = + [ + # Nixpkgs build a v8 monolith instead of separate v8_libplatform. + "USE_SYSTEM_V8=1" + "V8_OUTDIR=${v8}/lib" + "PG_CONFIG=${postgresql}/bin/pg_config" + ] + ++ lib.optionals stdenv.isDarwin [ + "CC=${clang}/bin/clang" + "CXX=${clang}/bin/clang++" + "SHLIB_LINK=-L${v8}/lib -lv8_monolith -Wl,-rpath,${v8}/lib" + ] + ++ lib.optionals (!stdenv.isDarwin) [ + "SHLIB_LINK=-lv8" + ]; + + NIX_LDFLAGS = lib.optionals stdenv.isDarwin [ + "-L${postgresql}/lib" + "-L${v8}/lib" + "-lv8_monolith" + "-lpq" + "-lpgcommon" + "-lpgport" + "-F${darwin.apple_sdk.frameworks.CoreFoundation}/Library/Frameworks" + "-framework" + "CoreFoundation" + "-F${darwin.apple_sdk.frameworks.Kerberos}/Library/Frameworks" + "-framework" + "Kerberos" + "-undefined" + "dynamic_lookup" + "-flat_namespace" + ]; + + # No configure script. + dontConfigure = true; + + postPatch = '' + patchShebangs ./generate_upgrade.sh + substituteInPlace generate_upgrade.sh \ + --replace " 3.1.8 " " 3.1.8 3.1.10 " + + ${lib.optionalString stdenv.isDarwin '' + # Replace g++ with clang++ in Makefile + sed -i 's/g++/clang++/g' Makefile + ''} + ''; + + installPhase = '' + runHook preInstall + set -eo pipefail + + mkdir -p $out/{lib,share/postgresql/extension} + + # Install versioned library + LIB_NAME="${pname}-${finalAttrs.version}${postgresql.dlSuffix}" + install -Dm755 $LIB_NAME $out/lib + + if [ "${lib.versions.major postgresql.version}" = "15" ]; then + ${lib.optionalString stdenv.isDarwin '' + install_name_tool -add_rpath "${v8}/lib" $out/lib/$LIB_NAME + install_name_tool -add_rpath "${postgresql}/lib" $out/lib/$LIB_NAME + install_name_tool -add_rpath "${stdenv.cc.cc.lib}/lib" $out/lib/$LIB_NAME + install_name_tool -change @rpath/libv8_monolith.dylib ${v8}/lib/libv8_monolith.dylib $out/lib/$LIB_NAME + ''} + + ${lib.optionalString (!stdenv.isDarwin) '' + ${patchelf}/bin/patchelf --set-rpath "${v8}/lib:${postgresql}/lib:${stdenv.cc.cc.lib}/lib" $out/lib/$LIB_NAME + ''} + else + ${lib.optionalString stdenv.isDarwin '' + install_name_tool -add_rpath "${v8}/lib" $out/lib/$LIB_NAME + install_name_tool -add_rpath "${postgresql}/lib" $out/lib/$LIB_NAME + install_name_tool -add_rpath "${stdenv.cc.cc.lib}/lib" $out/lib/$LIB_NAME + install_name_tool -change @rpath/libv8_monolith.dylib ${v8}/lib/libv8_monolith.dylib $out/lib/$LIB_NAME + ''} + + ${lib.optionalString (!stdenv.isDarwin) '' + ${patchelf}/bin/patchelf --set-rpath "${v8}/lib:${postgresql}/lib:${stdenv.cc.cc.lib}/lib" $out/lib/$LIB_NAME + ''} + fi + + # plv8 3.2.x removed support for coffeejs and livescript + EXTENSIONS=(${if (builtins.compareVersions "3.1.10" version >= 0) then "plv8 plcoffee plls" else "plv8"}) + for ext in "''${EXTENSIONS[@]}" ; do + cp $ext--${version}.sql $out/share/postgresql/extension + install -Dm644 $ext.control $out/share/postgresql/extension/$ext--${version}.control + # Create versioned control file with modified module path + sed -e "/^default_version =/d" \ + -e "s|^module_pathname = .*|module_pathname = '\$libdir/${pname}-${version}'|" \ + $ext.control > $out/share/postgresql/extension/$ext--${version}.control + done + + # For the latest 3.1.x version, also create the default control file + # for coffeejs and livescript extensions + if [[ ${version} == "3.1.10" ]]; then + for ext in "''${EXTENSIONS[@]}" ; do + if [[ "$ext" != "plv8" ]]; then + { + echo "default_version = '${version}'" + cat $out/share/postgresql/extension/$ext--${version}.control + } > $out/share/postgresql/extension/$ext.control + fi + done + fi + + # For the latest version, create default control file and symlink + if [[ "${version}" == "${latestVersion}" ]]; then + { + echo "default_version = '${version}'" + cat $out/share/postgresql/extension/${pname}--${version}.control + } > $out/share/postgresql/extension/${pname}.control + ln -sfn ${pname}-${latestVersion}${postgresql.dlSuffix} $out/lib/${pname}${postgresql.dlSuffix} + fi + + # copy upgrade scripts + cp upgrade/*.sql $out/share/postgresql/extension + + runHook postInstall + ''; + + meta = with lib; { + description = "V8 Engine Javascript Procedural Language add-on for PostgreSQL"; + homepage = "https://plv8.github.io/"; + platforms = [ + "x86_64-linux" + "aarch64-linux" + "aarch64-darwin" + "x86_64-darwin" + ]; + license = licenses.postgresql; + }; + }); +in +buildEnv { + name = pname; + paths = packages; + + pathsToLink = [ + "/lib" + "/share/postgresql/extension" + ]; + postBuild = '' + # Verify all expected library files are present + expectedFiles=${toString (numberOfVersions + 1)} + actualFiles=$(ls -A $out/lib/${pname}*${postgresql.dlSuffix} | wc -l) + + if [[ "$actualFiles" != "$expectedFiles" ]]; then + echo "Error: Expected $expectedFiles library files, found $actualFiles" + echo "Files found:" + ls -la $out/lib/${pname}*${postgresql.dlSuffix} || true + exit 1 + fi + ''; + + passthru = { + inherit versions numberOfVersions; + pname = "${pname}-all"; + version = + "multi-" + lib.concatStringsSep "-" (map (v: lib.replaceStrings [ "." ] [ "-" ] v) versions); + }; +} diff --git a/nix/ext/tests/plv8.nix b/nix/ext/tests/plv8.nix new file mode 100644 index 000000000..107254059 --- /dev/null +++ b/nix/ext/tests/plv8.nix @@ -0,0 +1,156 @@ +{ self, pkgs }: +let + pname = "plv8"; + inherit (pkgs) lib; + installedExtension = + postgresMajorVersion: self.packages.${pkgs.system}."psql_${postgresMajorVersion}/exts/${pname}-all"; + versions = postgresqlMajorVersion: (installedExtension postgresqlMajorVersion).versions; + postgresqlWithExtension = + postgresql: + let + majorVersion = lib.versions.major postgresql.version; + pkg = pkgs.buildEnv { + name = "postgresql-${majorVersion}-${pname}"; + paths = [ + postgresql + postgresql.lib + (installedExtension majorVersion) + ]; + passthru = { + inherit (postgresql) version psqlSchema; + lib = pkg; + withPackages = _: pkg; + }; + nativeBuildInputs = [ pkgs.makeWrapper ]; + pathsToLink = [ + "/" + "/bin" + "/lib" + ]; + postBuild = '' + wrapProgram $out/bin/postgres --set NIX_PGLIBDIR $out/lib + wrapProgram $out/bin/pg_ctl --set NIX_PGLIBDIR $out/lib + wrapProgram $out/bin/pg_upgrade --set NIX_PGLIBDIR $out/lib + ''; + }; + in + pkg; +in +self.inputs.nixpkgs.lib.nixos.runTest { + name = pname; + hostPkgs = pkgs; + nodes.server = + { config, ... }: + { + virtualisation = { + forwardPorts = [ + { + from = "host"; + host.port = 13022; + guest.port = 22; + } + ]; + }; + services.openssh = { + enable = true; + }; + + services.postgresql = { + enable = true; + package = postgresqlWithExtension self.packages.${pkgs.system}.postgresql_15; + }; + + specialisation.postgresql17.configuration = { + services.postgresql = { + package = lib.mkForce (postgresqlWithExtension self.packages.${pkgs.system}.postgresql_17); + }; + + systemd.services.postgresql-migrate = { + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + User = "postgres"; + Group = "postgres"; + StateDirectory = "postgresql"; + WorkingDirectory = "${builtins.dirOf config.services.postgresql.dataDir}"; + }; + script = + let + oldPostgresql = postgresqlWithExtension self.packages.${pkgs.system}.postgresql_15; + newPostgresql = postgresqlWithExtension self.packages.${pkgs.system}.postgresql_17; + oldDataDir = "${builtins.dirOf config.services.postgresql.dataDir}/${oldPostgresql.psqlSchema}"; + newDataDir = "${builtins.dirOf config.services.postgresql.dataDir}/${newPostgresql.psqlSchema}"; + in + '' + if [[ ! -d ${newDataDir} ]]; then + install -d -m 0700 -o postgres -g postgres "${newDataDir}" + ${newPostgresql}/bin/initdb -D "${newDataDir}" + ${newPostgresql}/bin/pg_upgrade --old-datadir "${oldDataDir}" --new-datadir "${newDataDir}" \ + --old-bindir "${oldPostgresql}/bin" --new-bindir "${newPostgresql}/bin" + else + echo "${newDataDir} already exists" + fi + ''; + }; + + systemd.services.postgresql = { + after = [ "postgresql-migrate.service" ]; + requires = [ "postgresql-migrate.service" ]; + }; + }; + + }; + testScript = + { nodes, ... }: + let + pg17-configuration = "${nodes.server.system.build.toplevel}/specialisation/postgresql17"; + in + '' + versions = { + "15": [${lib.concatStringsSep ", " (map (s: ''"${s}"'') (versions "15"))}], + "17": [${lib.concatStringsSep ", " (map (s: ''"${s}"'') (versions "17"))}], + } + + def run_sql(query): + return server.succeed(f"""sudo -u postgres psql -t -A -F\",\" -c \"{query}\" """).strip() + + def check_upgrade_path(pg_version): + with subtest("Check ${pname} upgrade path"): + firstVersion = versions[pg_version][0] + server.succeed("sudo -u postgres psql -c 'DROP EXTENSION IF EXISTS ${pname};'") + run_sql(f"""CREATE EXTENSION ${pname} WITH VERSION '{firstVersion}' CASCADE;""") + installed_version = run_sql(r"""SELECT extversion FROM pg_extension WHERE extname = '${pname}';""") + assert installed_version == firstVersion, f"Expected ${pname} version {firstVersion}, but found {installed_version}" + for version in versions[pg_version][1:]: + server.succeed("sudo -u postgres psql -c 'DROP EXTENSION IF EXISTS ${pname};'") + run_sql(f"""CREATE EXTENSION ${pname} WITH VERSION '{version}' CASCADE;""") + installed_version = run_sql(r"""SELECT extversion FROM pg_extension WHERE extname = '${pname}';""") + assert installed_version == version, f"Expected ${pname} version {version}, but found {installed_version}" + + start_all() + + server.wait_for_unit("multi-user.target") + server.wait_for_unit("postgresql.service") + + check_upgrade_path("15") + + with subtest("Check ${pname} latest extension version"): + server.succeed("sudo -u postgres psql -c 'DROP EXTENSION ${pname};'") + server.succeed("sudo -u postgres psql -c 'CREATE EXTENSION ${pname} CASCADE;'") + installed_extensions=run_sql(r"""SELECT extname, extversion FROM pg_extension;""") + latestVersion = versions["15"][-1] + assert f"${pname},{latestVersion}" in installed_extensions + + with subtest("switch to postgresql 17"): + server.succeed( + "${pg17-configuration}/bin/switch-to-configuration test >&2" + ) + + with subtest("Check ${pname} latest extension version after upgrade"): + installed_extensions=run_sql(r"""SELECT extname, extversion FROM pg_extension;""") + latestVersion = versions["17"][-1] + assert f"${pname},{latestVersion}" in installed_extensions + + check_upgrade_path("17") + ''; +} diff --git a/nix/ext/versions.json b/nix/ext/versions.json new file mode 100644 index 000000000..8985b1063 --- /dev/null +++ b/nix/ext/versions.json @@ -0,0 +1,29 @@ +{ + "plv8": { + "3.1.4": { + "postgresql": [ + "15" + ], + "hash": "sha256-GoPP2nAeDItBt3Lug49s+brD0gIy3iDlJpbyHRuMcZ4=" + }, + "3.1.5": { + "postgresql": [ + "15" + ], + "hash": "sha256-LodC2eQJSm5fLckrjm2RuejZhmOyQMJTv9b0iPCnzKQ=" + }, + "3.1.10": { + "postgresql": [ + "15" + ], + "hash": "sha256-g1A/XPC0dX2360Gzvmo9/FSQnM6Wt2K4eR0pH0p9fz4=" + }, + "3.2.3": { + "postgresql": [ + "15", + "17" + ], + "hash": "sha256-ivQZJSNn5giWF351fqZ7mBZoJkGtby5T7beK45g3Zqs=" + } + } +} diff --git a/nix/tests/expected/z_15_ext_interface.out b/nix/tests/expected/z_15_ext_interface.out index 540bee2e8..8ecb9eb00 100644 --- a/nix/tests/expected/z_15_ext_interface.out +++ b/nix/tests/expected/z_15_ext_interface.out @@ -13,7 +13,7 @@ added and you should `create extension ...` to enable it in ./nix/tests/prime */ create extension if not exists adminpack; -create extension if not exists plv8; +create extension if not exists plv8 with version '3.1.10'; create extension if not exists plcoffee; create extension if not exists plls; create extension if not exists old_snapshot; diff --git a/nix/tests/expected/z_17_ext_interface.out b/nix/tests/expected/z_17_ext_interface.out index f7750f849..00acd169d 100644 --- a/nix/tests/expected/z_17_ext_interface.out +++ b/nix/tests/expected/z_17_ext_interface.out @@ -24,9 +24,10 @@ order by ------------------------ pg_cron pgjwt + plv8 postgis_tiger_geocoder tsm_system_time -(4 rows) +(5 rows) /* diff --git a/nix/tests/expected/z_orioledb-17_ext_interface.out b/nix/tests/expected/z_orioledb-17_ext_interface.out index f7750f849..00acd169d 100644 --- a/nix/tests/expected/z_orioledb-17_ext_interface.out +++ b/nix/tests/expected/z_orioledb-17_ext_interface.out @@ -24,9 +24,10 @@ order by ------------------------ pg_cron pgjwt + plv8 postgis_tiger_geocoder tsm_system_time -(4 rows) +(5 rows) /* diff --git a/nix/tests/sql/z_15_ext_interface.sql b/nix/tests/sql/z_15_ext_interface.sql index 24ee03ea2..187d3e374 100644 --- a/nix/tests/sql/z_15_ext_interface.sql +++ b/nix/tests/sql/z_15_ext_interface.sql @@ -15,7 +15,7 @@ added and you should `create extension ...` to enable it in ./nix/tests/prime */ create extension if not exists adminpack; -create extension if not exists plv8; +create extension if not exists plv8 with version '3.1.10'; create extension if not exists plcoffee; create extension if not exists plls; create extension if not exists old_snapshot;