Skip to content

Add pgvectorscale extension #1723

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Dockerfile-15
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ ARG pgroonga_release=2.4.0
ARG wrappers_release=0.5.0
ARG hypopg_release=1.3.1
ARG pgvector_release=0.4.0
ARG pgvectorscale_release=0.8.0
ARG pg_tle_release=1.3.2
ARG index_advisor_release=0.2.0
ARG supautils_release=2.2.0
Expand Down
1 change: 1 addition & 0 deletions Dockerfile-17
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ ARG pgroonga_release=2.4.0
ARG wrappers_release=0.5.0
ARG hypopg_release=1.3.1
ARG pgvector_release=0.4.0
ARG pgvectorscale_release=0.8.0
ARG pg_tle_release=1.3.2
ARG index_advisor_release=0.2.0
ARG supautils_release=2.2.0
Expand Down
Empty file added add-Cargo.lock.patch
Empty file.
212 changes: 133 additions & 79 deletions nix/cargo-pgrx/buildPgrxExtension.nix
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,10 @@
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
{
lib,
cargo-pgrx,
pkg-config,
rustPlatform,
stdenv,
darwin,
writeShellScriptBin,
}:

# The idea behind: Use it mostly like rustPlatform.buildRustPackage and so
# Build PostgreSQL extensions using the pgrx framework.
#
# Use it mostly like rustPlatform.buildRustPackage and so
# we hand most of the arguments down.
#
# Additional arguments are:
Expand All @@ -46,77 +39,143 @@
# If the generated rust bindings aren't needed to use the extension, its a
# unnecessary and heavy dependency. If you set this to true, you also
# have to add `rustfmt` to `nativeBuildInputs`.
{
lib,
pkg-config,
stdenv,
darwin,
writeShellScriptBin,
pgrxVersion,
rustVersion,
pkgs,
makeRustPlatform,
rust-bin,
}:

{
buildAndTestSubdir ? null,
buildType ? "release",
buildFeatures ? [ ],
cargoBuildFlags ? [ ],
postgresql,
# cargo-pgrx calls rustfmt on generated bindings, this is not strictly necessary, so we avoid the
# dependency here. Set to false and provide rustfmt in nativeBuildInputs, if you need it, e.g.
# if you include the generated code in the output via postInstall.
useFakeRustfmt ? true,
usePgTestCheckFeature ? true,
...
}@args:

let
rustPlatform = makeRustPlatform {
cargo = rust-bin.stable.${rustVersion}.default;
rustc = rust-bin.stable.${rustVersion}.default;
};

versions = builtins.fromJSON (builtins.readFile ./versions.json);
pgrx = versions.${pgrxVersion};
cargoHash = pgrx.rust."${rustVersion}".cargoHash;
cargoVersion = rustVersion;

rustfmtInNativeBuildInputs = lib.lists.any (dep: lib.getName dep == "rustfmt") (
args.nativeBuildInputs or [ ]
);
in

assert lib.asserts.assertMsg (
(args.installPhase or "") == ""
) "buildPgrxExtensions overwrites the installPhase, so providing one does nothing";
assert lib.asserts.assertMsg (
(args.buildPhase or "") == ""
) "buildPgrxExtensions overwrites the buildPhase, so providing one does nothing";
assert lib.asserts.assertMsg (useFakeRustfmt -> !rustfmtInNativeBuildInputs)
"The parameter useFakeRustfmt is set to true, but rustfmt is included in nativeBuildInputs. Either set useFakeRustfmt to false or remove rustfmt from nativeBuildInputs.";
assert lib.asserts.assertMsg (!useFakeRustfmt -> rustfmtInNativeBuildInputs)
"The parameter useFakeRustfmt is set to false, but rustfmt is not included in nativeBuildInputs. Either set useFakeRustfmt to true or add rustfmt from nativeBuildInputs.";
cargo-pgrx = pkgs.callPackage ./pgrx.nix {
inherit cargoHash;
pgrxHash = pgrx.hash;
inherit pgrxVersion;
inherit cargoVersion;
};
fakeRustfmt = writeShellScriptBin "rustfmt" "exit 0";
pgrxPostgresMajor = lib.versions.major postgresql.version;

let
fakeRustfmt = writeShellScriptBin "rustfmt" ''
exit 0
setupPgrxEnvironment = ''
echo "=== Setting up PGRX environment ==="
export PGRX_HOME=$(mktemp -d)
export PGDATA="$PGRX_HOME/data-${pgrxPostgresMajor}/"
export PATH="${postgresql}/bin:$PATH"

cat > $PGRX_HOME/config.toml << EOF
[configs]
pg${pgrxPostgresMajor} = "${postgresql}/bin/pg_config"
EOF

echo "Initializing PGRX..."
${cargo-pgrx}/bin/cargo-pgrx pgrx init "--pg${pgrxPostgresMajor}" ${lib.getDev postgresql}/bin/pg_config
'';
maybeDebugFlag = lib.optionalString (buildType != "release") "--debug";
maybeEnterBuildAndTestSubdir = lib.optionalString (buildAndTestSubdir != null) ''
export CARGO_TARGET_DIR="$(pwd)/target"
pushd "${buildAndTestSubdir}"

setupPostgreSQLForTesting = ''
echo "=== Setting up PostgreSQL for extension testing ==="
export PGHOST="$(mktemp -d)"
export USER="$(whoami)"

echo "Starting PostgreSQL..."
pg_ctl start -w -l "$PGDATA/postgresql.log" || {
echo "PostgreSQL failed to start, continuing without database (package-only build)..."
}

if pg_ctl status >/dev/null 2>&1; then
createuser -h localhost --superuser --createdb "$USER" 2>/dev/null || true
fi
'';
maybeLeaveBuildAndTestSubdir = lib.optionalString (buildAndTestSubdir != null) "popd";

pgrxPostgresMajor = lib.versions.major postgresql.version;
preBuildAndTest = ''
export PGRX_HOME=$(mktemp -d)
export PGDATA="$PGRX_HOME/data-${pgrxPostgresMajor}/"
cargo-pgrx pgrx init "--pg${pgrxPostgresMajor}" ${lib.getDev postgresql}/bin/pg_config
buildExtensionPhase = ''
echo "=== Building extension with cargo-pgrx ==="

# unix sockets work in sandbox, too.
export PGHOST="$(mktemp -d)"
cat > "$PGDATA/postgresql.conf" <<EOF
listen_addresses = '''
unix_socket_directories = '$PGHOST'
EOF
${lib.optionalString (buildAndTestSubdir != null) ''
export CARGO_TARGET_DIR="$(pwd)/target"
pushd "${buildAndTestSubdir}"
''}

# This is primarily for Mac or other Nix systems that don't use the nixbld user.
export USER="$(whoami)"
pg_ctl start
createuser -h localhost --superuser --createdb "$USER" || true
pg_ctl stop
PGRX_BUILD_FLAGS="--frozen -j $NIX_BUILD_CORES ${builtins.concatStringsSep " " cargoBuildFlags}"

${lib.optionalString stdenv.hostPlatform.isDarwin ''
export RUSTFLAGS="''${RUSTFLAGS:+''${RUSTFLAGS} }-Clink-args=-Wl,-undefined,dynamic_lookup"
''}

${cargo-pgrx}/bin/cargo-pgrx pgrx package \
--pg-config ${lib.getDev postgresql}/bin/pg_config \
${lib.optionalString (buildType != "release") "--debug"} \
${
lib.optionalString (
buildFeatures != [ ]
) "--features \"${builtins.concatStringsSep " " buildFeatures}\""
} \
--out-dir "$out"

${lib.optionalString (buildAndTestSubdir != null) "popd"}
'';

cleanupPhase = ''
echo "=== Cleaning up PostgreSQL ==="
if [ -n "''${PGDATA:-}" ] && [ -f "$PGDATA/postmaster.pid" ]; then
echo "Stopping PostgreSQL..."
pg_ctl stop -w || true
fi
'';
in

argsForBuildRustPackage = builtins.removeAttrs args [
assert lib.asserts.assertMsg (
(args.installPhase or "") == ""
) "buildPgrxExtensions overwrites the installPhase";

assert lib.asserts.assertMsg (
(args.buildPhase or "") == ""
) "buildPgrxExtensions overwrites the buildPhase";

assert lib.asserts.assertMsg (
useFakeRustfmt -> !rustfmtInNativeBuildInputs
) "useFakeRustfmt conflicts with rustfmt in nativeBuildInputs";

assert lib.asserts.assertMsg (
!useFakeRustfmt -> rustfmtInNativeBuildInputs
) "useFakeRustfmt false but no rustfmt in nativeBuildInputs";

rustPlatform.buildRustPackage (
builtins.removeAttrs args [
"postgresql"
"useFakeRustfmt"
"usePgTestCheckFeature"
];

# so we don't accidentally `(rustPlatform.buildRustPackage argsForBuildRustPackage) // { ... }` because
# we forgot parentheses
finalArgs = argsForBuildRustPackage // {
]
// {
buildInputs =
(args.buildInputs or [ ])
++ lib.optionals stdenv.hostPlatform.isDarwin [ darwin.apple_sdk.frameworks.Security ];
Expand All @@ -134,52 +193,47 @@ let
buildPhase = ''
runHook preBuild

echo "Executing cargo-pgrx buildPhase"
${preBuildAndTest}
${maybeEnterBuildAndTestSubdir}

PGRX_BUILD_FLAGS="--frozen -j $NIX_BUILD_CORES ${builtins.concatStringsSep " " cargoBuildFlags}" \
${lib.optionalString stdenv.hostPlatform.isDarwin ''RUSTFLAGS="''${RUSTFLAGS:+''${RUSTFLAGS} }-Clink-args=-Wl,-undefined,dynamic_lookup"''} \
cargo pgrx package \
--pg-config ${lib.getDev postgresql}/bin/pg_config \
${maybeDebugFlag} \
--features "${builtins.concatStringsSep " " buildFeatures}" \
--out-dir "$out"

${maybeLeaveBuildAndTestSubdir}
${setupPgrxEnvironment}
${setupPostgreSQLForTesting}
${buildExtensionPhase}

runHook postBuild
'';

preCheck = preBuildAndTest + args.preCheck or "";

installPhase = ''
runHook preInstall

echo "Executing buildPgrxExtension install"
${lib.optionalString (buildAndTestSubdir != null) ''
pushd "${buildAndTestSubdir}"
''}

${maybeEnterBuildAndTestSubdir}

cargo-pgrx pgrx stop all
echo "=== Installing extension files ==="

mv $out/${postgresql}/* $out
mv $out/${postgresql.lib}/* $out
mv $out/${postgresql.lib}/* $out
rm -rf $out/nix

${maybeLeaveBuildAndTestSubdir}
${lib.optionalString (buildAndTestSubdir != null) "popd"}

runHook postInstall
'';

postBuild = cleanupPhase;
postInstall = cleanupPhase;

PGRX_PG_SYS_SKIP_BINDING_REWRITE = "1";
CARGO_BUILD_INCREMENTAL = "false";
RUST_BACKTRACE = "full";

checkNoDefaultFeatures = true;
checkFeatures =
(args.checkFeatures or [ ])
++ (lib.optionals usePgTestCheckFeature [ "pg_test" ])
++ lib.optionals usePgTestCheckFeature [ "pg_test" ]
++ [ "pg${pgrxPostgresMajor}" ];
};
in
rustPlatform.buildRustPackage finalArgs

meta = (args.meta or { }) // {
description = args.meta.description or "PostgreSQL extension built with pgrx";
platforms = lib.platforms.unix;
};
}
)
Loading