From 2aea32dc3ccfb5afb0129bf72e07c4bde9dba2c3 Mon Sep 17 00:00:00 2001 From: urso Date: Wed, 10 Jul 2024 14:57:06 +0200 Subject: [PATCH 1/4] ci: run scripts per example --- ci/run.sh | 154 +++++++++++------------------- examples/char_count_zig/ci/run.sh | 63 ++++++++++++ examples/pgaudit_zig/ci/run.sh | 56 +++++++++++ examples/spi_sql/ci/run.sh | 57 +++++++++++ 4 files changed, 233 insertions(+), 97 deletions(-) create mode 100755 examples/char_count_zig/ci/run.sh create mode 100755 examples/pgaudit_zig/ci/run.sh create mode 100755 examples/spi_sql/ci/run.sh diff --git a/ci/run.sh b/ci/run.sh index 9c86a51..7d1136d 100755 --- a/ci/run.sh +++ b/ci/run.sh @@ -3,115 +3,75 @@ #set -x set -o pipefail -test_pgzx() { - rc=0 - run_unit_tests ./ || rc=1 - extension_drop pgzx_unit - return $rc -} - -test_char_count_zig() { - extension_create char_count_zig - trap "extension_drop char_count_zig" INT TERM - - rc=0 - run_regression_tests ./examples/char_count_zig || rc=1 - run_unit_tests ./examples/char_count_zig || rc=1 - - extension_drop char_count_zig - return $rc -} - -test_pgaudit_zig() { - run_unit_tests ./examples/pgaudit_zig -} - -test_spi_sql() { - local rc=0 - run_regression_tests ./examples/spi_sql || rc=1 - return $rc -} - -extension_build() { - cwd=$(pwd) - cd "$1" || return 1 - zig build -freference-trace -p "$PG_HOME" || return 1 - cd "$cwd" || return 1 -} - -extension_create() { - echo "Create extension $1" - psql -U postgres -c "CREATE EXTENSION IF NOT EXISTS $1" -} +examples=(./examples/*) -extension_drop() { - echo "Drop extension $1" - psql -U postgres -c "DROP EXTENSION IF EXISTS $1" +fail() { + echo "$1" >&2 + exit 1 } -run_regression_tests() { - echo "Run regression tests" - +build_example() { cwd=$(pwd) cd "$1" || return 1 - zig build pg_regress --verbose || return 1 + ./ci/run.sh build || return 1 cd "$cwd" || return 1 } -run_unit_tests() { - echo "Run unit tests" - +run_example() { cwd=$(pwd) cd "$1" || return 1 - zig build -freference-trace -p "$PG_HOME" unit || return 1 + ./ci/run.sh || return 1 cd "$cwd" || return 1 } -run_test_suites() { - for t in "$@"; do - echo "" - echo "# Run $t" - if ! $t; then - return 1 - fi - done -} - -fail() { - echo "$1" >&2 - exit 1 -} - -main() { - echo "Build and install extension" - eval "$(pgenv)" - - log_init_size=0 - if [ -f "$PG_CLUSTER_LOG_FILE" ]; then - log_init_size=$(stat -c %s "$PG_CLUSTER_LOG_FILE") - fi - echo "Server log size: $log_init_size" - - extension_build ./examples/char_count_zig || fail "Failed to build char_count_zig" - extension_build ./examples/pgaudit_zig || fail "Failed to build pgaudit_zig" - extension_build ./examples/spi_sql || fail "Failed to build spi_sql" - - echo "Start PostgreSQL" - pgstart || fail "Failed to start PostgreSQL" - trap pgstop TERM INT EXIT - - ok=true - run_test_suites test_pgzx test_char_count_zig test_pgaudit_zig test_spi_sql || ok=false - - if ! $ok; then - printf "\n\nServer log:" - - log_size=$(stat -c %s "$PG_CLUSTER_LOG_FILE") - tail -c $((log_size - log_init_size)) "$PG_CLUSTER_LOG_FILE" - fail "Regression tests failed" - fi - - echo "Success!" +test_pgzx() { + rc=0 + zig build -freference-trace -p "$PG_HOME" unit || rc=1 + psql -U postgres -c "DROP EXTENSION IF EXISTS pgzx_unit" + return $rc } -main +echo "Build and install extension" +eval "$(pgenv)" + +log_init_size=0 +if [ -f "$PG_CLUSTER_LOG_FILE" ]; then + log_init_size=$(stat -c %s "$PG_CLUSTER_LOG_FILE") +fi +echo "Server log size: $log_init_size" + +# build examples +echo "${examples[@]}" +build_jobs=() +for example in "${examples[@]}"; do + echo -e "\n\nBuild example $example" + build_example "$example" & + build_jobs+=($!) +done +for job in "${build_jobs[@]}"; do + wait "$job" || fail "Failed to build example" +done + +echo -e "\n\nStart PostgreSQL" +pgstart || fail "Failed to start PostgreSQL" +trap pgstop TERM INT EXIT + +echo -e "\n\nRun pgzx unit tests:" +test_pgzx || fail "Failed to run pgzx unit tests" + +for example in "${examples[@]}"; do + echo -e "\n\nRun example CI script $example" + run_example "$example" || fail "Failed to run CI script for $example" +done + +ok=true + +if ! $ok; then + printf "\n\nServer log:" + + log_size=$(stat -c %s "$PG_CLUSTER_LOG_FILE") + tail -c $((log_size - log_init_size)) "$PG_CLUSTER_LOG_FILE" + fail "Regression tests failed" +fi + +echo "Success!" diff --git a/examples/char_count_zig/ci/run.sh b/examples/char_count_zig/ci/run.sh new file mode 100755 index 0000000..4c7e340 --- /dev/null +++ b/examples/char_count_zig/ci/run.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash + +#set -x +set -o pipefail + +EXTENSION_NAME=char_count_zig + +build() { + echo "Build extension $EXTENSION_NAME" + zig build -freference-trace -p "$PG_HOME" || return 1 +} + +create_extension() { + echo "Create extension $EXTENSION_NAME" + psql -U postgres -c "CREATE EXTENSION IF NOT EXISTS $EXTENSION_NAME" +} + +extension_drop() { + echo "Drop extension $EXTENSION_NAME" + psql -U postgres -c "DROP EXTENSION IF EXISTS $EXTENSION_NAME" +} + +regression_tests() { + echo "Run regression tests: $EXTENSION_NAME" + zig build pg_regress --verbose || return 1 +} + +unit_tests() { + echo "Run unit tests: $EXTENSION_NAME" + zig build -freference-trace -p "$PG_HOME" unit || return 1 +} + +all() { + build && create_extension && unit_tests && regression_tests && extension_drop +} + +# optional command. Use all if not specified +command=${1:-all} + +#shellcheck disable=SC1007 +HELP= < Date: Wed, 10 Jul 2024 20:24:58 +0200 Subject: [PATCH 2/4] typo --- examples/spi_sql/ci/run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spi_sql/ci/run.sh b/examples/spi_sql/ci/run.sh index 036451a..4095885 100755 --- a/examples/spi_sql/ci/run.sh +++ b/examples/spi_sql/ci/run.sh @@ -3,7 +3,7 @@ #set -x set -o pipefail -EXTENSION_NAME=char_count_zig +EXTENSION_NAME=spi_sql build() { echo "Build extension $EXTENSION_NAME" From 7156da4d4732c1a9eaefeb04cb6644ea0fe85d15 Mon Sep 17 00:00:00 2001 From: urso Date: Wed, 10 Jul 2024 21:46:10 +0200 Subject: [PATCH 3/4] examples: sqlfns --- examples/sqlfns/README.md | 2 + examples/sqlfns/build.zig | 53 ++++++++ examples/sqlfns/build.zig.zon | 13 ++ examples/sqlfns/ci/run.sh | 57 ++++++++ examples/sqlfns/expected/sqlfns_test.out | 99 ++++++++++++++ examples/sqlfns/extension/sqlfns--0.1.sql | 27 ++++ examples/sqlfns/extension/sqlfns.control | 6 + examples/sqlfns/sql/sqlfns_test.sql | 29 +++++ examples/sqlfns/src/hello_world.zig | 9 ++ examples/sqlfns/src/main.zig | 151 ++++++++++++++++++++++ 10 files changed, 446 insertions(+) create mode 100644 examples/sqlfns/README.md create mode 100644 examples/sqlfns/build.zig create mode 100644 examples/sqlfns/build.zig.zon create mode 100755 examples/sqlfns/ci/run.sh create mode 100644 examples/sqlfns/expected/sqlfns_test.out create mode 100644 examples/sqlfns/extension/sqlfns--0.1.sql create mode 100644 examples/sqlfns/extension/sqlfns.control create mode 100644 examples/sqlfns/sql/sqlfns_test.sql create mode 100644 examples/sqlfns/src/hello_world.zig create mode 100644 examples/sqlfns/src/main.zig diff --git a/examples/sqlfns/README.md b/examples/sqlfns/README.md new file mode 100644 index 0000000..2461523 --- /dev/null +++ b/examples/sqlfns/README.md @@ -0,0 +1,2 @@ +# sqlfns - Sample extension showing how to create function that can be called from Postgres + diff --git a/examples/sqlfns/build.zig b/examples/sqlfns/build.zig new file mode 100644 index 0000000..f8ac2b0 --- /dev/null +++ b/examples/sqlfns/build.zig @@ -0,0 +1,53 @@ +const std = @import("std"); + +// Load pgzx build support. The build utilities use pg_config to find all dependencies +// and provide functions go create and test extensions. +const PGBuild = @import("pgzx").Build; + +pub fn build(b: *std.Build) void { + // Project meta data + const name = "sqlfns"; + const version = .{ .major = 0, .minor = 1 }; + + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + // Load the pgzx module and initialize the build utilities + const dep_pgzx = b.dependency("pgzx", .{ .target = target, .optimize = optimize }); + const pgzx = dep_pgzx.module("pgzx"); + var pgbuild = PGBuild.create(b, .{ .target = target, .optimize = optimize }); + + const build_options = b.addOptions(); + build_options.addOption(bool, "testfn", b.option(bool, "testfn", "Register test function") orelse false); + + // Register the dependency with the build system + // and add pgzx as module dependency. + { + const ext = pgbuild.addInstallExtension(.{ + .name = name, + .version = version, + .root_source_file = b.path("src/main.zig"), + .root_dir = ".", + }); + ext.lib.root_module.addImport("pgzx", pgzx); + ext.lib.root_module.addOptions("build_options", build_options); + + b.getInstallStep().dependOn(&ext.step); + } + + // Configure pg_regress based testing for the current extension. + { + const extest = pgbuild.addRegress(.{ + .db_user = "postgres", + .db_port = 5432, + .root_dir = ".", + .scripts = &[_][]const u8{ + "sqlfns_test", + }, + }); + + // Make regression tests available to `zig build` + var regress = b.step("pg_regress", "Run regression tests"); + regress.dependOn(&extest.step); + } +} diff --git a/examples/sqlfns/build.zig.zon b/examples/sqlfns/build.zig.zon new file mode 100644 index 0000000..2fd4f93 --- /dev/null +++ b/examples/sqlfns/build.zig.zon @@ -0,0 +1,13 @@ +.{ + .name = "sqlfns", + .version = "0.1.0", + .paths = .{ + "extension", + "src", + }, + .dependencies = .{ + .pgzx = .{ + .path = "./../..", + }, + }, +} diff --git a/examples/sqlfns/ci/run.sh b/examples/sqlfns/ci/run.sh new file mode 100755 index 0000000..8be58ce --- /dev/null +++ b/examples/sqlfns/ci/run.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +#set -x +set -o pipefail + +EXTENSION_NAME=sqlfns + +build() { + echo "Build extension $EXTENSION_NAME" + zig build -freference-trace -p "$PG_HOME" || return 1 +} + +create_extension() { + echo "Create extension $EXTENSION_NAME" + psql -U postgres -c "CREATE EXTENSION IF NOT EXISTS $EXTENSION_NAME" +} + +extension_drop() { + echo "Drop extension $EXTENSION_NAME" + psql -U postgres -c "DROP EXTENSION IF EXISTS $EXTENSION_NAME" +} + +regression_tests() { + echo "Run regression tests: $EXTENSION_NAME" + zig build pg_regress --verbose || return 1 +} + +all() { + build && create_extension && regression_tests && extension_drop +} + +# optional command. Use all if not specified +command=${1:-all} + +#shellcheck disable=SC1007 +HELP= < Date: Thu, 11 Jul 2024 12:46:17 +0200 Subject: [PATCH 4/4] typo --- examples/sqlfns/src/main.zig | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/examples/sqlfns/src/main.zig b/examples/sqlfns/src/main.zig index c2c22a0..d1d7d9b 100644 --- a/examples/sqlfns/src/main.zig +++ b/examples/sqlfns/src/main.zig @@ -90,11 +90,14 @@ fn hello_world_zig_null(name: ?[:0]const u8) !?[:0]const u8 { } // It is also possible to capture the FunctionCallInfo as an argument to your function. You want to do this if -// you want to use the configured collation, check the context node, or -// manually parse arguments manually. +// you want to use the string collation, check the context node, or +// parse arguments manually. // -// In this example we will accept and return a Datum. This requires to mark a +// In this example we will also accept and return a Datum. This requires us to mark a // NULL return in the FunctionCallInfo. +// +// Note: alternatively we could returns a `?pg.Datum` and just return `null`. +// We use the FunctionCallInfo to demonstrate access how to access them. comptime { pgzx.PG_FUNCTION_V1("hello_world_zig_datum", hello_world_zig_datum); @@ -115,9 +118,11 @@ fn hello_world_zig_datum(fcinfo: pg.FunctionCallInfo, arg: ?pg.Datum) !pg.Datum // ==================================================== // Exporting a number of functions can become a bit tedious over time. -// The `PG_EXPORT` function can be used to automatically export all public functions from a struct. +// The `PG_EXPORT` function can be used to automatically export all public +// functions from a struct. // Here we export a function from an anonymous struct. + comptime { pgzx.PG_EXPORT(struct { pub fn hello_world_anon(name: ?[:0]const u8) ![:0]const u8 { @@ -129,7 +134,7 @@ comptime { }); } -// Or a names struct: +// We can also export functions from a named struct: comptime { pgzx.PG_EXPORT(mod_hello_world); @@ -144,7 +149,7 @@ const mod_hello_world = struct { } }; -// In Zig when importing a file, the file is treated as a struct. Let's try this: +// In Zig when importing a file, the file is also treated as a struct. Let's try this: comptime { pgzx.PG_EXPORT(@import("hello_world.zig"));