pgtypes: Cleaner error reporting
This commit is contained in:
parent
d5f593387a
commit
b66610e25a
1 changed files with 22 additions and 23 deletions
45
c/pgtypes.c
45
c/pgtypes.c
|
|
@ -38,7 +38,9 @@ typedef struct {
|
|||
|
||||
#define RECVFN(name) static SV *fupg_recv_##name(pTHX_ const fupg_recv *ctx __attribute__((unused)), const char *buf, int len)
|
||||
#define SENDFN(name) static void fupg_send_##name(pTHX_ const fupg_send *ctx __attribute__((unused)), SV *val, fustr *out)
|
||||
#define RLEN(l) if (l != len) fu_confess("Invalid length for type '%s' (oid %u), expected %d but got %d", ctx->name, ctx->oid, l, len)
|
||||
#define RERR(msg, ...) fu_confess("Error parsing value for type '%s' (oid %u): "msg, ctx->name, ctx->oid __VA_OPT__(,) __VA_ARGS__)
|
||||
#define SERR(msg, ...) fu_confess("Error converting Perl value '%s' to type '%s' (oid %u): "msg, SvPV_nolen(val), ctx->name, ctx->oid __VA_OPT__(,) __VA_ARGS__)
|
||||
#define RLEN(l) if (l != len) RERR("expected %d bytes but got %d", l, len)
|
||||
|
||||
/* Perl likes to play loose with SV-to-integer conversions, but that's not
|
||||
* very fun when trying to store values in a database. Text-based bind
|
||||
|
|
@ -48,8 +50,7 @@ typedef struct {
|
|||
if (SvIOK(val)) iv = SvIV(val); \
|
||||
else if (SvNOK(val)) { \
|
||||
NV nv = SvNV(val); \
|
||||
if (nv < IV_MIN || nv > IV_MAX || fabs(nv - floor(nv)) > 0.0000000001) \
|
||||
fu_confess("Type '%s' (oid %u) expects an integer but got a floating point", ctx->name, ctx->oid); \
|
||||
if (nv < IV_MIN || nv > IV_MAX || fabs(nv - floor(nv)) > 0.0000000001) SERR("expected integer");\
|
||||
iv = SvIV(val); \
|
||||
} else if (SvPOK(val)) {\
|
||||
STRLEN sl; \
|
||||
|
|
@ -57,9 +58,9 @@ typedef struct {
|
|||
char *s = SvPV(val, sl); \
|
||||
if (*s == '-' && grok_atoUV(s+1, &uv, NULL) && uv <= ((UV)IV_MAX)+1) iv = SvIV(val);\
|
||||
else if (grok_atoUV(s, &uv, NULL) && uv <= IV_MAX) iv = SvIV(val);\
|
||||
else fu_confess("Type '%s' (oid %u) expects an integer", ctx->name, ctx->oid); \
|
||||
} else fu_confess("Type '%s' (oid %u) expects an integer", ctx->name, ctx->oid);\
|
||||
if (iv < min || iv > max) fu_confess("Integer %"IVdf" out of range for type '%s' (oid %u)", iv, ctx->name, ctx->oid)
|
||||
else SERR("expected integer");\
|
||||
} else SERR("expected integer");\
|
||||
if (iv < min || iv > max) SERR("integer out of range")
|
||||
|
||||
|
||||
RECVFN(bool) {
|
||||
|
|
@ -129,14 +130,13 @@ RECVFN(char) {
|
|||
SENDFN(char) {
|
||||
STRLEN len;
|
||||
const char *buf = SvPVbyte(val, len);
|
||||
if (len != 1) fu_confess("Type '%s' (oid %u) expects a 1-byte string", ctx->name, ctx->oid);
|
||||
if (len != 1) SERR("expected 1-byte string");
|
||||
fustr_write(out, buf, len);
|
||||
}
|
||||
|
||||
/* Works for many text-based column types, including receiving any value in the text format */
|
||||
RECVFN(text) {
|
||||
if (!is_c9strict_utf8_string((const U8*)buf, len))
|
||||
fu_confess("Received invalid UTF-8 for type '%s' (oid %u)", ctx->name, ctx->oid);
|
||||
if (!is_c9strict_utf8_string((const U8*)buf, len)) RERR("invalid UTF-8");
|
||||
return newSVpvn_utf8(buf, len, 1);
|
||||
}
|
||||
|
||||
|
|
@ -152,7 +152,7 @@ RECVFN(float4) {
|
|||
}
|
||||
|
||||
SENDFN(float4) {
|
||||
if (!looks_like_number(val)) fu_confess("Type '%s' (oid %u) expects a number", ctx->name, ctx->oid);
|
||||
if (!looks_like_number(val)) SERR("expected a number");
|
||||
fustr_writebeT(float, 32, out, SvNV(val));
|
||||
}
|
||||
|
||||
|
|
@ -162,7 +162,7 @@ RECVFN(float8) {
|
|||
}
|
||||
|
||||
SENDFN(float8) {
|
||||
if (!looks_like_number(val)) fu_confess("Type '%s' (oid %u) expects a number", ctx->name, ctx->oid);
|
||||
if (!looks_like_number(val)) SERR("expected a number");
|
||||
fustr_writebeT(double, 64, out, SvNV(val));
|
||||
}
|
||||
|
||||
|
|
@ -173,8 +173,8 @@ RECVFN(json) {
|
|||
.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);
|
||||
if (sv == NULL) RERR("invalid JSON");
|
||||
if (json.buf != json.end) RERR("trailing garbage");
|
||||
return sv;
|
||||
}
|
||||
|
||||
|
|
@ -184,7 +184,7 @@ SENDFN(json) {
|
|||
}
|
||||
|
||||
RECVFN(jsonb) {
|
||||
if (len <= 1 || *buf != 1) fu_confess("Unexpected format for type '%s' (oid %u)", ctx->name, ctx->oid);
|
||||
if (len <= 1 || *buf != 1) RERR("invalid JSONB");
|
||||
return fupg_recv_json(aTHX_ ctx, buf+1, len-1);
|
||||
}
|
||||
|
||||
|
|
@ -194,7 +194,7 @@ SENDFN(jsonb) {
|
|||
}
|
||||
|
||||
RECVFN(jsonpath) {
|
||||
if (len <= 1 || *buf != 1) fu_confess("Unexpected format for type '%s' (oid %u)", ctx->name, ctx->oid);
|
||||
if (len <= 1 || *buf != 1) RERR("invalid jsonpath");
|
||||
return fupg_recv_text(aTHX_ ctx, buf+1, len-1);
|
||||
}
|
||||
|
||||
|
|
@ -232,16 +232,15 @@ static SV *fupg_recv_array_elem(pTHX_ const fupg_recv *elem, const char *header,
|
|||
}
|
||||
|
||||
RECVFN(array) {
|
||||
if (len < 12) fu_confess("Invalid array format for type '%s' (oid %u)", ctx->name, ctx->oid);
|
||||
if (len < 12) RERR("input data too short");
|
||||
U32 ndim = fu_frombeU(32, buf);
|
||||
// buf+4 is hasnull, can safely ignore
|
||||
Oid elemtype = fu_frombeU(32, buf+8);
|
||||
if (elemtype != ctx->arrayelem->oid)
|
||||
fu_confess("Array type '%s' (oid %u) expected elements of type %u but got %u", ctx->name, ctx->oid, ctx->arrayelem->oid, elemtype);
|
||||
if (elemtype != ctx->arrayelem->oid) RERR("invalid element type, expected %u but got %u", ctx->arrayelem->oid, elemtype);
|
||||
|
||||
if (ndim == 0) return newRV_noinc((SV *)newAV());
|
||||
if (ndim > ARRAY_MAXDIM) fu_confess("Array value of type '%s' (oid %u) has too many dimensions (%d)", ctx->name, ctx->oid, ndim);
|
||||
if ((U32)len < 12 + ndim*8) fu_confess("Invalid array format for type '%s' (oid %u)", ctx->name, ctx->oid);
|
||||
if (ndim > ARRAY_MAXDIM) RERR("too many dimensions");
|
||||
if ((U32)len < 12 + ndim*8) RERR("input data too short");
|
||||
|
||||
const char *header = buf + 12;
|
||||
const char *data = header + ndim * 8;
|
||||
|
|
@ -293,15 +292,15 @@ SENDFN(array) {
|
|||
v = SvRV(v);
|
||||
SvGETMAGIC(v);
|
||||
if (SvTYPE(v) != SVt_PVAV) break;
|
||||
if (ndim >= ARRAY_MAXDIM) fu_confess("Maximum depth exceeded while attempting to send array of type '%s' (oid %u)", ctx->name, ctx->oid);
|
||||
if (ndim >= ARRAY_MAXDIM) SERR("too many dimensions");
|
||||
dims[ndim] = av_count((AV*)v);
|
||||
if (ndim > 0 && dims[ndim] == 0) fu_confess("Empty dimension while attempting to send array of type '%s' (oid %u)", ctx->name, ctx->oid);
|
||||
if (ndim > 0 && dims[ndim] == 0) SERR("nested arrays may not be empty");
|
||||
ndim++;
|
||||
SV **sv = av_fetch((AV*)v, 0, 0);
|
||||
if (!sv || !*sv) break;
|
||||
v = *sv;
|
||||
}
|
||||
if (ndim == 0) fu_confess("Type '%s' (oid %u) expects an array", ctx->name, ctx->oid);
|
||||
if (ndim == 0) SERR("expected an array");
|
||||
if (dims[0] == 0) ndim = 0;
|
||||
|
||||
/* Write header */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue