fu/FU.xs
Yorhel 87d99e412b pg: Add support for record/composite types
This is simply magical. \o/

Vendored in khashl.h. I wouldn't have used it if this were the only
place where I'd need a custom hash table, but it should come in handy
for other tasks as well, especially when I get to implementing an LRU
for prepared statement caching.

(Can all be done with Perl HV's, but they're less efficient and more
cumbersome for these tasks)
2025-02-11 16:04:10 +01:00

264 lines
5.5 KiB
Text

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
#include <dlfcn.h>
#undef PERL_IMPLICIT_SYS
#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "c/khashl.h"
#include "c/common.c"
#include "c/jsonfmt.c"
#include "c/jsonparse.c"
#include "c/libpq.h"
#include "c/pgtypes.c"
#include "c/pgconn.c"
#include "c/pgst.c"
#define FUPG_CONN_COOKIE \
if (c->cookie) fu_confess("Invalid operation on the top-level connection while a transaction object exists")
#define FUPG_TXN_COOKIE \
if (!t->cookie) fu_confess("Invalid operation on a transaction that has already been marked as done"); \
if (t->cookie != t->conn->cookie) fu_confess("Invalid operation on transaction while a subtransaction object exists")
#define FUPG_ST_COOKIE \
if (st->cookie != st->conn->cookie) fu_confess("Invalid cross-transaction operation on statement object")
#define FUPG_STFLAGS do {\
if (!ix) ix = FUPG_CACHE;\
if (items == 1 || SvTRUE(ST(1))) x->stflags |= ix; \
else x->stflags &= ~ix; \
XSRETURN(1); \
} while(0)
MODULE = FU
PROTOTYPES: DISABLE
TYPEMAP: <<EOT
TYPEMAP
fupg_conn * FUPG_CONN
fupg_txn * FUPG_TXN
fupg_st * FUPG_ST
INPUT
FUPG_CONN
if (sv_derived_from($arg, \"FU::Pg::conn\")) $var = (fupg_conn *)SvIVX(SvRV($arg));
else fu_confess(\"invalid connection object\");
FUPG_TXN
if (sv_derived_from($arg, \"FU::Pg::txn\")) $var = (fupg_txn *)SvIVX(SvRV($arg));
else fu_confess(\"invalid transaction object\");
FUPG_ST
if (sv_derived_from($arg, \"FU::Pg::st\")) $var = (fupg_st *)SvIVX(SvRV($arg));
else fu_confess(\"invalid statement object\");
#"
EOT
MODULE = FU PACKAGE = FU::Util
void json_format(SV *val, ...)
CODE:
ST(0) = fujson_fmt_xs(aTHX_ ax, items, val);
void json_parse(SV *val, ...)
CODE:
ST(0) = fujson_parse_xs(aTHX_ ax, items, val);
MODULE = FU PACKAGE = FU::Pg
void _load_libpq()
CODE:
if (!PQconnectdb) fupg_load();
void lib_version()
CODE:
XSRETURN_IV(PQlibVersion());
void connect(const char *pkg, const char *conninfo)
CODE:
(void)pkg;
ST(0) = fupg_connect(aTHX_ conninfo);
MODULE = FU PACKAGE = FU::Pg::conn
void server_version(fupg_conn *c)
CODE:
XSRETURN_IV(PQserverVersion(c->conn));
void _debug_trace(fupg_conn *c, bool on)
CODE:
if (on) PQtrace(c->conn, stderr);
else PQuntrace(c->conn);
ST(0) = c->self;
void status(fupg_conn *c)
CODE:
ST(0) = sv_2mortal(newSVpv(fupg_conn_status(c), 0));
void cache(fupg_conn *x, ...)
ALIAS:
FU::Pg::conn::text_params = FUPG_TEXT_PARAMS
FU::Pg::conn::text_results = FUPG_TEXT_RESULTS
FU::Pg::conn::text = FUPG_TEXT
CODE:
FUPG_STFLAGS;
void disconnect(fupg_conn *c)
CODE:
fupg_conn_disconnect(c);
void DESTROY(fupg_conn *c)
CODE:
fupg_conn_destroy(c);
void txn(fupg_conn *c)
CODE:
FUPG_CONN_COOKIE;
ST(0) = fupg_conn_txn(c);
void exec(fupg_conn *c, SV *sv)
CODE:
FUPG_CONN_COOKIE;
ST(0) = fupg_exec(aTHX_ c, SvPVutf8_nolen(sv));
void q(fupg_conn *c, SV *sv, ...)
CODE:
FUPG_CONN_COOKIE;
ST(0) = fupg_q(aTHX_ c, c->stflags, SvPVutf8_nolen(sv), ax, items);
MODULE = FU PACKAGE = FU::Pg::txn
void DESTROY(fupg_txn *t)
CODE:
fupg_txn_destroy(t);
void cache(fupg_txn *x, ...)
ALIAS:
FU::Pg::txn::text_params = FUPG_TEXT_PARAMS
FU::Pg::txn::text_results = FUPG_TEXT_RESULTS
FU::Pg::txn::text = FUPG_TEXT
CODE:
FUPG_STFLAGS;
void status(fupg_txn *t)
CODE:
ST(0) = sv_2mortal(newSVpv(fupg_txn_status(t), 0));
void txn(fupg_txn *t)
CODE:
FUPG_TXN_COOKIE;
ST(0) = fupg_txn_txn(t);
void commit(fupg_txn *t)
CODE:
FUPG_TXN_COOKIE;
fupg_txn_commit(t);
void rollback(fupg_txn *t)
CODE:
FUPG_TXN_COOKIE;
fupg_txn_rollback(t);
void exec(fupg_txn *t, SV *sv)
CODE:
FUPG_TXN_COOKIE;
ST(0) = fupg_exec(aTHX_ t->conn, SvPVutf8_nolen(sv));
void q(fupg_txn *t, SV *sv, ...)
CODE:
FUPG_TXN_COOKIE;
ST(0) = fupg_q(aTHX_ t->conn, t->stflags, SvPVutf8_nolen(sv), ax, items);
MODULE = FU PACKAGE = FU::Pg::st
void cache(fupg_st *x, ...)
ALIAS:
FU::Pg::st::text_params = FUPG_TEXT_PARAMS
FU::Pg::st::text_results = FUPG_TEXT_RESULTS
FU::Pg::st::text = FUPG_TEXT
CODE:
FUPG_STFLAGS;
void param_types(fupg_st *st)
CODE:
FUPG_ST_COOKIE;
ST(0) = fupg_st_param_types(aTHX_ st);
void columns(fupg_st *st)
CODE:
FUPG_ST_COOKIE;
ST(0) = fupg_st_columns(aTHX_ st);
void exec(fupg_st *st)
CODE:
FUPG_ST_COOKIE;
ST(0) = fupg_st_exec(aTHX_ st);
void val(fupg_st *st)
CODE:
FUPG_ST_COOKIE;
ST(0) = fupg_st_val(aTHX_ st);
void rowl(fupg_st *st)
CODE:
FUPG_ST_COOKIE;
XSRETURN(fupg_st_rowl(aTHX_ st, ax));
void rowa(fupg_st *st)
CODE:
FUPG_ST_COOKIE;
ST(0) = fupg_st_rowa(aTHX_ st);
void rowh(fupg_st *st)
CODE:
FUPG_ST_COOKIE;
ST(0) = fupg_st_rowh(aTHX_ st);
void alla(fupg_st *st)
CODE:
FUPG_ST_COOKIE;
ST(0) = fupg_st_alla(aTHX_ st);
void allh(fupg_st *st)
CODE:
FUPG_ST_COOKIE;
ST(0) = fupg_st_allh(aTHX_ st);
void flat(fupg_st *st)
CODE:
FUPG_ST_COOKIE;
ST(0) = fupg_st_flat(aTHX_ st);
void kvv(fupg_st *st)
CODE:
FUPG_ST_COOKIE;
ST(0) = fupg_st_kvv(aTHX_ st);
void kva(fupg_st *st)
CODE:
FUPG_ST_COOKIE;
ST(0) = fupg_st_kva(aTHX_ st);
void kvh(fupg_st *st)
CODE:
FUPG_ST_COOKIE;
ST(0) = fupg_st_kvh(aTHX_ st);
void DESTROY(fupg_st *st)
CODE:
fupg_st_destroy(st);