Pg: Support dynamic-oid types + vndbtag/vndbid
This commit is contained in:
parent
70c5199df4
commit
dc752e2a23
3 changed files with 124 additions and 6 deletions
14
c/pgconn.c
14
c/pgconn.c
|
|
@ -471,6 +471,7 @@ static void fupg_refresh_types(pTHX_ fupg_conn *c) {
|
||||||
snprintf(t->name.n, sizeof(t->name.n), "%s", PQgetvalue(r, i, 1));
|
snprintf(t->name.n, sizeof(t->name.n), "%s", PQgetvalue(r, i, 1));
|
||||||
char typ = *PQgetvalue(r, i, 2);
|
char typ = *PQgetvalue(r, i, 2);
|
||||||
t->elemoid = fu_frombeU(32, PQgetvalue(r, i, 3));
|
t->elemoid = fu_frombeU(32, PQgetvalue(r, i, 3));
|
||||||
|
const fupg_type *builtin;
|
||||||
|
|
||||||
if (t->elemoid) {
|
if (t->elemoid) {
|
||||||
if (typ == 'd') { /* domain */
|
if (typ == 'd') { /* domain */
|
||||||
|
|
@ -487,13 +488,14 @@ static void fupg_refresh_types(pTHX_ fupg_conn *c) {
|
||||||
/* enum, can use text send/recv */
|
/* enum, can use text send/recv */
|
||||||
t->send = fupg_send_text;
|
t->send = fupg_send_text;
|
||||||
t->recv = fupg_recv_text;
|
t->recv = fupg_recv_text;
|
||||||
|
} else if ((builtin = fupg_builtin_byoid(t->oid))) {
|
||||||
|
t->send = builtin->send;
|
||||||
|
t->recv = builtin->recv;
|
||||||
|
} else if ((builtin = fupg_dynoid_byname(t->name.n))) {
|
||||||
|
t->send = builtin->send;
|
||||||
|
t->recv = builtin->recv;
|
||||||
} else {
|
} else {
|
||||||
/* TODO: (multi)ranges, by-name lookup for dynamic-oid types */
|
/* TODO: (multi)ranges */
|
||||||
const fupg_type *builtin = fupg_builtin_byoid(t->oid);
|
|
||||||
if (builtin) {
|
|
||||||
t->send = builtin->send;
|
|
||||||
t->recv = builtin->recv;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PQclear(r);
|
PQclear(r);
|
||||||
|
|
|
||||||
94
c/pgtypes.c
94
c/pgtypes.c
|
|
@ -638,6 +638,72 @@ SENDFN(time) {
|
||||||
fustr_writebeI(64, out, SvNV(val) * 1000000);
|
fustr_writebeI(64, out, SvNV(val) * 1000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* VNDB types */
|
||||||
|
|
||||||
|
const char vndbtag_alpha[] = "\0""abcdefghijklmnopqrstuvwxyz?????";
|
||||||
|
|
||||||
|
static I16 vndbtag_parse(char **str) {
|
||||||
|
I16 tag = 0;
|
||||||
|
if (**str >= 'a' && **str <= 'z') {
|
||||||
|
tag = (**str - 'a' + 1) << 10;
|
||||||
|
(*str)++;
|
||||||
|
if (**str >= 'a' && **str <= 'z') {
|
||||||
|
tag |= (**str - 'a' + 1) << 5;
|
||||||
|
(*str)++;
|
||||||
|
if (**str >= 'a' && **str <= 'z') {
|
||||||
|
tag |= **str - 'a' + 1;
|
||||||
|
(*str)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vndbtag_fmt(I16 tag, char *out) {
|
||||||
|
out[0] = vndbtag_alpha[(tag >> 10) & 31];
|
||||||
|
out[1] = vndbtag_alpha[(tag >> 5) & 31];
|
||||||
|
out[2] = vndbtag_alpha[(tag >> 0) & 31];
|
||||||
|
out[3] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
RECVFN(vndbtag) {
|
||||||
|
RLEN(2);
|
||||||
|
SV *r = newSV(4);
|
||||||
|
SvPOK_only(r);
|
||||||
|
vndbtag_fmt(fu_frombeI(16, buf), SvPVX(r));
|
||||||
|
SvCUR_set(r, strlen(SvPVX(r)));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
SENDFN(vndbtag) {
|
||||||
|
char *t = SvPV_nolen(val);
|
||||||
|
I16 v = vndbtag_parse(&t);
|
||||||
|
if (*t) SERR("Invalid vndbtag: '%s'", SvPV_nolen(val));
|
||||||
|
fustr_writebeI(16, out, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define VNDBID2_MAXNUM (((I64)1<<48)-1)
|
||||||
|
|
||||||
|
RECVFN(vndbid) {
|
||||||
|
RLEN(8);
|
||||||
|
I64 v = fu_frombeI(64, buf);
|
||||||
|
char tbuf[4];
|
||||||
|
vndbtag_fmt(v >> 48, tbuf);
|
||||||
|
return newSVpvf("%s%"UVuf, tbuf, (UV)(v & VNDBID2_MAXNUM));
|
||||||
|
}
|
||||||
|
|
||||||
|
SENDFN(vndbid) {
|
||||||
|
char *ostr = SvPV_nolen(val), *str = ostr;
|
||||||
|
UV num;
|
||||||
|
I16 tag = vndbtag_parse(&str);
|
||||||
|
if (!grok_atoUV(str, &num, NULL) || num > VNDBID2_MAXNUM) SERR("invalid vndbid '%s'", ostr);
|
||||||
|
fustr_writebeI(64, out, ((I64)tag)<<48 | num);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#undef SIV
|
#undef SIV
|
||||||
#undef RLEN
|
#undef RLEN
|
||||||
#undef RECVFN
|
#undef RECVFN
|
||||||
|
|
@ -818,7 +884,24 @@ static const fupg_type fupg_builtin[] = {
|
||||||
#define FUPG_BUILTIN (sizeof(fupg_builtin) / sizeof(fupg_type))
|
#define FUPG_BUILTIN (sizeof(fupg_builtin) / sizeof(fupg_type))
|
||||||
|
|
||||||
|
|
||||||
|
/* List of types identified by name */
|
||||||
|
|
||||||
|
#define DYNOID\
|
||||||
|
T("vndbtag", vndbtag)\
|
||||||
|
T("vndbid", vndbid)
|
||||||
|
|
||||||
|
static const fupg_type fupg_dynoid[] = {
|
||||||
|
#define T(name, fun) { 0, 0, {name"\0"}, fupg_send_##fun, fupg_recv_##fun },
|
||||||
|
DYNOID
|
||||||
|
#undef T
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef DYNOID
|
||||||
|
#define FUPG_DYNOID (sizeof(fupg_dynoid) / sizeof(fupg_type))
|
||||||
|
|
||||||
|
|
||||||
/* List of special types for use with set_type() */
|
/* List of special types for use with set_type() */
|
||||||
|
|
||||||
#define SPECIALS\
|
#define SPECIALS\
|
||||||
T("$date_str", date_str)\
|
T("$date_str", date_str)\
|
||||||
T("$hex", hex )
|
T("$hex", hex )
|
||||||
|
|
@ -851,8 +934,19 @@ static const fupg_type *fupg_builtin_byoid(Oid oid) {
|
||||||
return fupg_type_byoid(fupg_builtin, FUPG_BUILTIN, oid);
|
return fupg_type_byoid(fupg_builtin, FUPG_BUILTIN, oid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const fupg_type *fupg_dynoid_byname(const char *name) {
|
||||||
|
size_t i;
|
||||||
|
for (i=0; i<FUPG_DYNOID; i++)
|
||||||
|
if (strcmp(fupg_dynoid[i].name.n, name) == 0)
|
||||||
|
return fupg_dynoid+i;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static const fupg_type *fupg_builtin_byname(const char *name) {
|
static const fupg_type *fupg_builtin_byname(const char *name) {
|
||||||
size_t i;
|
size_t i;
|
||||||
|
const fupg_type *r = fupg_dynoid_byname(name);
|
||||||
|
if (r) return r;
|
||||||
|
|
||||||
/* XXX: Can use binary search here if the list of specials grows.
|
/* XXX: Can use binary search here if the list of specials grows.
|
||||||
* That list does not have to be ordered by oid. */
|
* That list does not have to be ordered by oid. */
|
||||||
for (i=0; i<FUPG_SPECIALS; i++)
|
for (i=0; i<FUPG_SPECIALS; i++)
|
||||||
|
|
|
||||||
|
|
@ -121,4 +121,26 @@ subtest 'custom types', sub {
|
||||||
is $txn->q("SELECT dom FROM fupg_test_table")->val, 0x6262;
|
is $txn->q("SELECT dom FROM fupg_test_table")->val, 0x6262;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
subtest 'vndbid', sub {
|
||||||
|
plan skip_all => 'type not loaded in the database' if !$conn->q("SELECT 1 FROM pg_type WHERE typname = 'vndbtag'")->val;
|
||||||
|
|
||||||
|
for my $t (qw/a zz xxx/) {
|
||||||
|
is $conn->q('SELECT $1::vndbtag', $t)->val, $t;
|
||||||
|
is $conn->q('SELECT $1::vndbtag', $t)->text_params->val, $t;
|
||||||
|
is $conn->q('SELECT $1::vndbtag', $t)->text_results->val, $t;
|
||||||
|
}
|
||||||
|
ok !eval { $conn->q('SELECT $1::vndbtag', '')->val };
|
||||||
|
ok !eval { $conn->q('SELECT $1::vndbtag', 'abcd')->val };
|
||||||
|
|
||||||
|
for my $t (qw/a123 zz992883231 xxx18388123/) {
|
||||||
|
is $conn->q('SELECT $1::vndbid', $t)->val, $t;
|
||||||
|
is $conn->q('SELECT $1::vndbid', $t)->text_params->val, $t;
|
||||||
|
is $conn->q('SELECT $1::vndbid', $t)->text_results->val, $t;
|
||||||
|
}
|
||||||
|
ok !eval { $conn->q('SELECT $1::vndbid', '')->val };
|
||||||
|
ok !eval { $conn->q('SELECT $1::vndbid', 'ab')->val };
|
||||||
|
ok !eval { $conn->q('SELECT $1::vndbid', 'ab1219229999999999')->val };
|
||||||
|
};
|
||||||
|
|
||||||
done_testing;
|
done_testing;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue