pg: Add support for domain types

+ refactor things a bit so that send & recv functions use the same
context struct, because the way they're setup is pretty much the same
for both. This also adds recursive type resolution for bind parameters.
This commit is contained in:
Yorhel 2025-02-10 14:22:38 +01:00
parent 7515032261
commit d95ff76d43
3 changed files with 83 additions and 82 deletions

View file

@ -1,34 +1,26 @@
typedef struct fupg_send fupg_send;
typedef struct fupg_recv fupg_recv;
typedef struct fupg_tio fupg_tio;
/* Send function, takes a Perl value and should write the binary encoded
* format into the given fustr. */
typedef void (*fupg_send_fn)(pTHX_ const fupg_send *, SV *, fustr *);
typedef void (*fupg_send_fn)(pTHX_ const fupg_tio *, SV *, fustr *);
/* Receive function, takes a binary string and should return a Perl value. */
typedef SV *(*fupg_recv_fn)(pTHX_ const fupg_recv *, const char *, int);
typedef SV *(*fupg_recv_fn)(pTHX_ const fupg_tio *, const char *, int);
struct fupg_send {
/* Type I/O context */
struct fupg_tio {
Oid oid;
const char *name;
fupg_send_fn fn;
fupg_send_fn send;
fupg_recv_fn recv;
union {
fupg_send *arrayelem;
};
};
struct fupg_recv {
Oid oid;
const char *name;
fupg_recv_fn fn;
union {
fupg_recv *arrayelem;
fupg_tio *arrayelem;
};
};
typedef struct {
Oid oid;
Oid elemoid; /* For arrays */
Oid elemoid; /* For arrays & domain types */
char name[64];
fupg_send_fn send;
fupg_recv_fn recv;
@ -36,8 +28,8 @@ typedef struct {
#define RECVFN(name) static SV *fupg_recv_##name(pTHX_ const fupg_recv *ctx __attribute__((unused)), const char *buf, int len)
#define SENDFN(name) static void fupg_send_##name(pTHX_ const fupg_send *ctx __attribute__((unused)), SV *val, fustr *out)
#define RECVFN(name) static SV *fupg_recv_##name(pTHX_ const fupg_tio *ctx __attribute__((unused)), const char *buf, int len)
#define SENDFN(name) static void fupg_send_##name(pTHX_ const fupg_tio *ctx __attribute__((unused)), SV *val, fustr *out)
#define RERR(msg, ...) fu_confess("Error parsing value for type '%s' (oid %u): "msg, ctx->name, ctx->oid __VA_OPT__(,) __VA_ARGS__)
#define SERR(msg, ...) fu_confess("Error converting Perl value '%s' to type '%s' (oid %u): "msg, SvPV_nolen(val), ctx->name, ctx->oid __VA_OPT__(,) __VA_ARGS__)
#define RLEN(l) if (l != len) RERR("expected %d bytes but got %d", l, len)
@ -62,6 +54,9 @@ typedef struct {
} else SERR("expected integer");\
if (iv < min || iv > max) SERR("integer out of range")
/* These are simply marker functions, not supposed to be called directly */
RECVFN(domain) { (void)buf; (void)len; RERR("domain type should not be handled by this function"); }
SENDFN(domain) { (void)out; SERR("domain type should not be handled by this function"); }
RECVFN(bool) {
RLEN(1);
@ -216,7 +211,7 @@ SENDFN(jsonpath) {
#define ARRAY_MAXDIM 100
static SV *fupg_recv_array_elem(pTHX_ const fupg_recv *elem, const char *header, U32 dim, U32 ndim, const char **buf, const char *end) {
static SV *fupg_recv_array_elem(pTHX_ const fupg_tio *elem, const char *header, U32 dim, U32 ndim, const char **buf, const char *end) {
SV *r = &PL_sv_undef;
if (dim == ndim) {
if (end - *buf < 4) fu_confess("Invalid array format");
@ -225,7 +220,7 @@ static SV *fupg_recv_array_elem(pTHX_ const fupg_recv *elem, const char *header,
if (end - *buf < len) fu_confess("Invalid array format");
if (len >= 0) {
r = elem->fn(aTHX_ elem, *buf, len);
r = elem->recv(aTHX_ elem, *buf, len);
*buf += len;
}
@ -257,7 +252,7 @@ RECVFN(array) {
return fupg_recv_array_elem(aTHX_ ctx->arrayelem, header, 0, ndim, &data, buf+len);
}
void fupg_send_array_elem(aTHX_ const fupg_send *elem, const U32 *dims, U32 dim, U32 ndim, SV *v, fustr *out, int *hasnull) {
void fupg_send_array_elem(aTHX_ const fupg_tio *elem, const U32 *dims, U32 dim, U32 ndim, SV *v, fustr *out, int *hasnull) {
SvGETMAGIC(v);
if (dim == ndim) {
if (!SvOK(v)) {
@ -267,7 +262,7 @@ void fupg_send_array_elem(aTHX_ const fupg_send *elem, const U32 *dims, U32 dim,
}
size_t lenoff = fustr_len(out);
fustr_write(out, "\0\0\0\0", 4);
elem->fn(elem, v, out);
elem->send(elem, v, out);
fu_tobeU(32, fustr_start(out) + lenoff, fustr_len(out) - lenoff - 4);
return;
}