Skip to content

Commit

Permalink
Example sqlfns (#79)
Browse files Browse the repository at this point in the history
Requires #75 

Adding an example extension showing how different ways on how to export
Zig functions to Postgres and read arguments and return values.

See examples/sqlfns/src/main.zig
  • Loading branch information
urso authored Jul 15, 2024
1 parent 589fe7b commit e00803b
Show file tree
Hide file tree
Showing 10 changed files with 451 additions and 0 deletions.
2 changes: 2 additions & 0 deletions examples/sqlfns/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# sqlfns - Sample extension showing how to create function that can be called from Postgres

53 changes: 53 additions & 0 deletions examples/sqlfns/build.zig
Original file line number Diff line number Diff line change
@@ -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);
}
}
13 changes: 13 additions & 0 deletions examples/sqlfns/build.zig.zon
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.{
.name = "sqlfns",
.version = "0.1.0",
.paths = .{
"extension",
"src",
},
.dependencies = .{
.pgzx = .{
.path = "./../..",
},
},
}
57 changes: 57 additions & 0 deletions examples/sqlfns/ci/run.sh
Original file line number Diff line number Diff line change
@@ -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= <<EOF
Usage: $0 [command]
commands (default 'all'):
all - build nand run tests
build - build and install extension
create_extension - create extension
extension_drop - drop extension
regression_tests - run regression tests
help - show this help message
EOF

case $command in
all) all ;;
build) build ;;
create_extension) create_extension ;;
extension_drop) extension_drop ;;
regression_tests) regression_tests ;;
unit_tests) unit_tests ;;
help) echo "$HELP" ;;
*) echo "$HELP" ;;
esac
99 changes: 99 additions & 0 deletions examples/sqlfns/expected/sqlfns_test.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
CREATE EXTENSION sqlfns;
SET search_path TO sqlfns;
SELECT hello_world_c(NULL);
hello_world_c
---------------
Hello World
(1 row)

SELECT hello_world_c('pgzx');
hello_world_c
---------------
Hello, pgzx!
(1 row)

SELECT hello_world_zig(NULL);
hello_world_zig
-----------------
Hello World
(1 row)

SELECT hello_world_zig('pgzx');
hello_world_zig
-----------------
Hello, pgzx!
(1 row)

SELECT hello_world_zig(NULL);
hello_world_zig
-----------------
Hello World
(1 row)

SELECT hello_world_zig('pgzx');
hello_world_zig
-----------------
Hello, pgzx!
(1 row)

SELECT hello_world_zig_null(NULL);
hello_world_zig_null
----------------------

(1 row)

SELECT hello_world_zig_null('pgzx');
hello_world_zig_null
----------------------
Hello, pgzx!
(1 row)

SELECT hello_world_zig_datum(NULL);
hello_world_zig_datum
-----------------------

(1 row)

SELECT hello_world_zig_datum('pgzx');
hello_world_zig_datum
-----------------------
Hello, pgzx!
(1 row)

SELECT hello_world_anon(NULL);
hello_world_anon
------------------
Hello World
(1 row)

SELECT hello_world_anon('pgzx');
hello_world_anon
------------------
Hello, pgzx!
(1 row)

SELECT hello_world_mod(NULL);
hello_world_mod
-----------------
Hello World
(1 row)

SELECT hello_world_mod('pgzx');
hello_world_mod
-----------------
Hello, pgzx!
(1 row)

SELECT hello_world_file(NULL);
hello_world_file
------------------
Hello World
(1 row)

SELECT hello_world_file('pgzx');
hello_world_file
------------------
Hello, pgzx!
(1 row)

DROP EXTENSION sqlfns;
27 changes: 27 additions & 0 deletions examples/sqlfns/extension/sqlfns--0.1.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
CREATE FUNCTION hello_world_c(name text) RETURNS text
AS 'MODULE_PATHNAME'
LANGUAGE C;

CREATE FUNCTION hello_world_zig(name text) RETURNS text
AS 'MODULE_PATHNAME'
LANGUAGE C;

CREATE FUNCTION hello_world_zig_null(name text) RETURNS text
AS 'MODULE_PATHNAME'
LANGUAGE C;

CREATE FUNCTION hello_world_zig_datum(name text) RETURNS text
AS 'MODULE_PATHNAME'
LANGUAGE C;

CREATE FUNCTION hello_world_anon(name text) RETURNS text
AS 'MODULE_PATHNAME'
LANGUAGE C;

CREATE FUNCTION hello_world_mod(name text) RETURNS text
AS 'MODULE_PATHNAME'
LANGUAGE C;

CREATE FUNCTION hello_world_file(name text) RETURNS text
AS 'MODULE_PATHNAME'
LANGUAGE C;
6 changes: 6 additions & 0 deletions examples/sqlfns/extension/sqlfns.control
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
comment = 'pgzx: SQL Functions test extension'
default_version = '0.1'
module_pathname = '$libdir/sqlfns'
relocatable = false
superuser = false
schema = 'sqlfns'
29 changes: 29 additions & 0 deletions examples/sqlfns/sql/sqlfns_test.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
CREATE EXTENSION sqlfns;

SET search_path TO sqlfns;

SELECT hello_world_c(NULL);
SELECT hello_world_c('pgzx');

SELECT hello_world_zig(NULL);
SELECT hello_world_zig('pgzx');

SELECT hello_world_zig(NULL);
SELECT hello_world_zig('pgzx');

SELECT hello_world_zig_null(NULL);
SELECT hello_world_zig_null('pgzx');

SELECT hello_world_zig_datum(NULL);
SELECT hello_world_zig_datum('pgzx');

SELECT hello_world_anon(NULL);
SELECT hello_world_anon('pgzx');

SELECT hello_world_mod(NULL);
SELECT hello_world_mod('pgzx');

SELECT hello_world_file(NULL);
SELECT hello_world_file('pgzx');

DROP EXTENSION sqlfns;
9 changes: 9 additions & 0 deletions examples/sqlfns/src/hello_world.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const std = @import("std");
const pgzx = @import("pgzx");

pub fn hello_world_file(name: ?[:0]const u8) ![:0]const u8 {
return if (name) |n|
try std.fmt.allocPrintZ(pgzx.mem.PGCurrentContextAllocator, "Hello, {s}!", .{n})
else
"Hello World";
}
Loading

0 comments on commit e00803b

Please sign in to comment.