72 lines
1.8 KiB
C
72 lines
1.8 KiB
C
/* 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;
|
|
}
|