Skip to content
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

add FunctionCallInfo, SortSupport, StringInfo #35

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions src/pgzx/c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const includes = @cImport({
@cInclude("postgres.h");
@cInclude("postgres_ext.h");

@cInclude("access/hash.h");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't tell how this file is sorted, so I just put the new import at the top.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might have put it after varatt.h :). But feel free to keep it here.

@cInclude("fmgr.h");
@cInclude("miscadmin.h");
@cInclude("varatt.h");
Expand Down Expand Up @@ -40,6 +41,7 @@ const includes = @cImport({
// libpq support
@cInclude("libpq-fe.h");
@cInclude("libpq/libpq-be.h");
@cInclude("libpq/pqformat.h");
@cInclude("libpqsrv.h");
});

Expand Down
41 changes: 37 additions & 4 deletions src/pgzx/datum.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ const varatt = @import("varatt.zig");
pub fn Conv(comptime T: type, comptime from: anytype, comptime to: anytype) type {
return struct {
pub const Type = T;

pub fn fromNullableDatum(d: c.NullableDatum) !Type {
if (d.isnull) {
return err.PGError.UnexpectedNullValue;
}
return try from(d.value);
}

pub fn toNullableDatum(v: Type) !c.NullableDatum {
return .{
.value = try to(v),
Expand All @@ -27,12 +29,14 @@ pub fn Conv(comptime T: type, comptime from: anytype, comptime to: anytype) type
pub fn ConvNoFail(comptime T: type, comptime from: anytype, comptime to: anytype) type {
return struct {
pub const Type = T;

pub fn fromNullableDatum(d: c.NullableDatum) !T {
if (d.isnull) {
return err.PGError.UnexpectedNullValue;
}
return from(d.value);
}

pub fn toNullableDatum(v: T) !c.NullableDatum {
return .{
.value = to(v),
Expand All @@ -46,12 +50,14 @@ pub fn ConvNoFail(comptime T: type, comptime from: anytype, comptime to: anytype
pub fn OptConv(comptime C: anytype) type {
return struct {
pub const Type = ?C.Type;

pub fn fromNullableDatum(d: c.NullableDatum) !Type {
if (d.isnull) {
return null;
}
return try C.fromNullableDatum(d);
}

pub fn toNullableDatum(v: Type) !c.NullableDatum {
if (v) |value| {
return try C.toNullableDatum(value);
Expand All @@ -70,7 +76,10 @@ pub fn OptConv(comptime C: anytype) type {
/// reflection only.
var directMappings = .{
.{ c.Datum, PGDatum },
.{ c.FunctionCallInfo, PGFunctionCallInfo },
.{ c.NullableDatum, PGNullableDatum },
.{ c.SortSupport, PGSortSupport },
.{ c.StringInfo, PGStringInfo },
};

pub fn fromNullableDatum(comptime T: type, d: c.NullableDatum) !T {
Expand Down Expand Up @@ -154,7 +163,7 @@ inline fn isConv(comptime T: type) bool {
return @hasDecl(T, "Type") and @hasDecl(T, "fromNullableDatum") and @hasDecl(T, "toNullableDatum");
}

pub const Void = ConvNoFail(void, idDatum, toVoid);
pub const Void = ConvNoFail(void, makeID(c.Datum), toVoid);
pub const Bool = ConvNoFail(bool, c.DatumGetBool, c.BoolGetDatum);
pub const Int8 = ConvNoFail(i8, datumGetInt8, c.Int8GetDatum);
pub const Int16 = ConvNoFail(i16, c.DatumGetInt16, c.Int16GetDatum);
Expand All @@ -170,12 +179,18 @@ pub const Float64 = ConvNoFail(f64, c.DatumGetFloat8, c.Float8GetDatum);
pub const SliceU8 = Conv([]const u8, getDatumTextSlice, sliceToDatumText);
pub const SliceU8Z = Conv([:0]const u8, getDatumTextSliceZ, sliceToDatumText);

pub const PGDatum = ConvNoFail(c.Datum, idDatum, idDatum);
pub const PGFunctionCallInfo = ConvID(c.FunctionCallInfo);
pub const PGSortSupport = ConvID(c.SortSupport);
pub const PGStringInfo = Conv(c.StringInfo, datumGetStringInfo, c.PointerGetDatum);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see why we want these types. But I don't think we should add them to datum conversions 🤔

We already have support to capture FunctionCallInfo via pgzx.fmgr.args module. Maybe that would be a better place for these argument types?

This and the other PRs also make me wonder if we rather want to introduce different function types. Right now we have PG_FUNCTION_V1, which can be any function. But maybe it would make sense to also introduce PG_OUT_FUNCTION or PG_SORT_FUNCTION exporters. These function types would ensure the correct number of argument and pass SortSupport or StringInfo right away.

For SortSupport one needs to functions like:

static int
btfloat8fastcmp(Datum x, Datum y, SortSupport ssup)
{
	float8		arg1 = DatumGetFloat8(x);
	float8		arg2 = DatumGetFloat8(y);

	return float8_cmp_internal(arg1, arg2);
}

Datum
btfloat8sortsupport(PG_FUNCTION_ARGS)
{
	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);

	ssup->comparator = btfloat8fastcmp;
	PG_RETURN_VOID();
}

Using an "abstraction" in Zig this might become:

comptime {
  pgzx.PG_SORT_SUPPORT("btfloat8sortsupport", .{
    .comparator = btfloat8fastcmp,
  })
}

Maybe it is worth to open an issue to discuss functionality that you are missing for the kind of work you are planning. Then we can discuss what needs to be adapted where, or if it makes sense to introduce abstractions. WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. I didn't know about the fmgr.args module. I'll have to check it out. I like the idea of different types of functions. It would simplify the definition boilerplate.


pub const PGDatum = ConvID(c.Datum);
const PGNullableDatum = struct {
pub const Type = c.NullableDatum;

pub fn fromNullableDatum(d: c.NullableDatum) !Type {
return d;
}

pub fn toNullableDatum(v: Type) !c.NullableDatum {
return v;
}
Expand All @@ -185,8 +200,26 @@ const PGNullableDatum = struct {

// TODO: conversion decorator for jsonb decoding/encoding types

fn idDatum(d: c.Datum) c.Datum {
return d;
fn ConvID(comptime T: type) type {
const idFn = makeID(T);

return ConvNoFail(T, idFn, idFn);
}

fn makeID(comptime T: type) fn (T) T {
return struct {
fn id(t: T) T {
return t;
}
}.id;
}

fn datumGetStringInfo(datum: c.Datum) !c.StringInfo {
return datumGetPointer(c.StringInfo, datum);
}

inline fn datumGetPointer(comptime T: type, datum: c.Datum) T {
return @ptrCast(@alignCast(c.DatumGetPointer(datum)));
}

fn toVoid(d: void) c.Datum {
Expand Down