/* 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. * For fixed-length types, the recv function is only called after verifying * that the input buffer has the correct length. */ 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; }