pg: Add json, jsonb, jsonpath support

NOW we're really getting to the part where this module is more awesome
than DBD::Pg.

(When I started working on this module I was expecting that the Postgres
binary protocol would send jsonb in a binary format as well and that I'd
be duplicating parts of the JSON parser/formatter to make that work, but
it turns out that Postgres just uses plain json for exchange. Saves me
some trouble, I guess)
This commit is contained in:
Yorhel 2025-02-08 15:03:17 +01:00
parent 7f1c48e0cf
commit 2aaec6a218
4 changed files with 98 additions and 49 deletions

View file

@ -57,10 +57,6 @@ typedef struct {
if (iv < min || iv > max) fu_confess("Integer %"IVdf" out of range for type '%s' (oid %u)", iv, ctx->name, ctx->oid)
RECVFN(textfmt) {
return newSVpvn_utf8(buf, len, 1);
}
RECVFN(bool) {
RLEN(1);
return *buf ? &PL_sv_yes : &PL_sv_no;
@ -182,6 +178,44 @@ SENDFN(float8) {
fustr_write(out, (const char *)&uv, 8);
}
RECVFN(json) {
fujson_parse_ctx json = {
.buf = (const unsigned char *)buf,
.end = (const unsigned char *)buf + len,
.depth = 512
};
SV *sv = fujson_parse(aTHX_ &json);
if (sv == NULL) fu_confess("Received invalid JSON for type '%s' (oid %u)", ctx->name, ctx->oid);
if (json.buf != json.end) fu_confess("Received invalid JSON for type '%s' (oid %u)", ctx->name, ctx->oid);
return sv;
}
SENDFN(json) {
fujson_fmt_ctx json = { .out = out, .depth = 512, .canon = 1, .pretty = 0 };
fujson_fmt(aTHX_ &json, val);
}
RECVFN(jsonb) {
if (len <= 1 || *buf != 1) fu_confess("Unexpected format for type '%s' (oid %u)", ctx->name, ctx->oid);
return fupg_recv_json(aTHX_ ctx, buf+1, len-1);
}
SENDFN(jsonb) {
fustr_write_ch(out, 1);
fupg_send_json(aTHX_ ctx, val, out);
}
RECVFN(jsonpath) {
if (len <= 1 || *buf != 1) fu_confess("Unexpected format for type '%s' (oid %u)", ctx->name, ctx->oid);
return fupg_recv_text(aTHX_ ctx, buf+1, len-1);
}
SENDFN(jsonpath) {
fustr_write_ch(out, 1);
fupg_send_text(aTHX_ ctx, val, out);
}
#undef SIV
#undef RLEN
#undef RECVFN
#undef SENDFN
@ -230,7 +264,7 @@ SENDFN(float8) {
B( 28, "xid", uint4 )\
B( 29, "cid", uint4 )\
/* 30 oidvector */ \
/* 114 json */ \
B( 114, "json", json )\
B( 142, "xml", text )\
B( 194, "pg_node_tree", text ) /* can't be used as a bind param */\
/* 600 point */\
@ -275,8 +309,8 @@ SENDFN(float8) {
/* 3642 gtsvector, does not support binary send/recv */\
B( 3734, "regconfig", uint4 )\
B( 3769, "regdictionary", uint4 )\
/* 3802 jsonb */\
/* 4072 jsonpath */\
B( 3802, "jsonb", jsonb )\
B( 4072, "jsonpath", jsonpath)\
B( 4089, "regnamespace", uint4 )\
B( 4096, "regrole", uint4 )\
B( 4191, "regcollation", uint4 )\