pg: Initial support for receiving binary results

Just the initial framework stuff and a few types to test with.
This commit is contained in:
Yorhel 2025-02-07 15:18:45 +01:00
parent 7c8473533d
commit 8f94dd0921
4 changed files with 164 additions and 34 deletions

72
c/pgtypes.c Normal file
View file

@ -0,0 +1,72 @@
/* Send function, takes a Perl value and should write the binary encoded
* format into the given fustr. */
typedef void (*fupg_send_fn)(pTHX_ SV *, fustr *, void *);
/* Receive function, takes a binary string and should return a Perl value.
* libpq guarantees that the given buffer is aligned to MAXIMUM_ALIGNOF. */
typedef SV *(*fupg_recv_fn)(pTHX_ const char *, int, void *);
typedef struct {
Oid oid;
int len;
const char *name;
fupg_send_fn send;
fupg_recv_fn recv;
} fupg_type;
#define RECVFN(name) static SV *fupg_recv_##name(pTHX_ const char *buf, int buflen __attribute__((unused)), void *data __attribute__((unused)))
RECVFN(textfmt) {
return newSVpvn_utf8(buf, buflen, 1);
}
RECVFN(bool) {
return *buf ? &PL_sv_yes : &PL_sv_no;
}
RECVFN(int2) {
return newSViv((I16)__builtin_bswap16(*((U16 *)buf)));
}
RECVFN(int4) {
return newSViv((I32)__builtin_bswap32(*((U32 *)buf)));
}
RECVFN(int8) {
return newSViv((I64)__builtin_bswap64(*((U64 *)buf)));
}
#undef RECVFN
#define R(name) fupg_recv_##name
/* Sorted by oid to support binary search.
* (XXX: hash lookup might be faster, but requires codegen) */
static const fupg_type fupg_types[] = {
{ 0, 0, NULL, NULL, R(textfmt) }, /* Invalid Oid, abused for text format */
{ 16, 1, "bool", NULL, R(bool) },
{ 20, 8, "int8", NULL, R(int8) },
{ 21, 2, "int2", NULL, R(int2) },
{ 23, 4, "int4", NULL, R(int4) },
};
/* TODO: A LOT MORE TYPES */
#undef R
#define FUPG_TYPES (sizeof(fupg_types) / sizeof(fupg_type))
static const fupg_type *fupg_type_lookup(Oid oid) {
int i, b = 0, e = FUPG_TYPES-1;
while (b <= e) {
i = b + (e - b)/2;
if (fupg_types[i].oid == oid) return fupg_types+i;
if (fupg_types[i].oid < oid) b = i+1;
else e = i-1;
}
return NULL;
}