diff options
Diffstat (limited to 'src/backend/utils')
-rw-r--r-- | src/backend/utils/adt/encode.c | 35 | ||||
-rw-r--r-- | src/backend/utils/adt/varchar.c | 33 | ||||
-rw-r--r-- | src/backend/utils/adt/varlena.c | 8 |
3 files changed, 46 insertions, 30 deletions
diff --git a/src/backend/utils/adt/encode.c b/src/backend/utils/adt/encode.c index feb3e830e4f..f3bb5cca43c 100644 --- a/src/backend/utils/adt/encode.c +++ b/src/backend/utils/adt/encode.c @@ -171,8 +171,8 @@ hex_encode(const char *src, size_t len, char *dst) return (uint64) len * 2; } -static inline char -get_hex(const char *cp) +static inline bool +get_hex(const char *cp, char *out) { unsigned char c = (unsigned char) *cp; int res = -1; @@ -180,18 +180,20 @@ get_hex(const char *cp) if (c < 127) res = hexlookup[c]; - if (res < 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid hexadecimal digit: \"%.*s\"", - pg_mblen(cp), cp))); + *out = (char) res; - return (char) res; + return (res >= 0); } uint64 hex_decode(const char *src, size_t len, char *dst) { + return hex_decode_safe(src, len, dst, NULL); +} + +uint64 +hex_decode_safe(const char *src, size_t len, char *dst, Node *escontext) +{ const char *s, *srcend; char v1, @@ -208,16 +210,23 @@ hex_decode(const char *src, size_t len, char *dst) s++; continue; } - v1 = get_hex(s) << 4; + if (!get_hex(s, &v1)) + ereturn(escontext, 0, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid hexadecimal digit: \"%.*s\"", + pg_mblen(s), s))); s++; if (s >= srcend) - ereport(ERROR, + ereturn(escontext, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid hexadecimal data: odd number of digits"))); - - v2 = get_hex(s); + if (!get_hex(s, &v2)) + ereturn(escontext, 0, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid hexadecimal digit: \"%.*s\"", + pg_mblen(s), s))); s++; - *p++ = v1 | v2; + *p++ = (v1 << 4) | v2; } return p - dst; diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c index a63c498181e..01a2db6b23b 100644 --- a/src/backend/utils/adt/varchar.c +++ b/src/backend/utils/adt/varchar.c @@ -122,9 +122,13 @@ anychar_typmodout(int32 typmod) * * If the input string is too long, raise an error, unless the extra * characters are spaces, in which case they're truncated. (per SQL) + * + * If escontext points to an ErrorSaveContext node, that is filled instead + * of throwing an error; the caller must check SOFT_ERROR_OCCURRED() + * to detect errors. */ static BpChar * -bpchar_input(const char *s, size_t len, int32 atttypmod) +bpchar_input(const char *s, size_t len, int32 atttypmod, Node *escontext) { BpChar *result; char *r; @@ -153,7 +157,7 @@ bpchar_input(const char *s, size_t len, int32 atttypmod) for (j = mbmaxlen; j < len; j++) { if (s[j] != ' ') - ereport(ERROR, + ereturn(escontext, NULL, (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), errmsg("value too long for type character(%d)", (int) maxlen))); @@ -195,14 +199,13 @@ Datum bpcharin(PG_FUNCTION_ARGS) { char *s = PG_GETARG_CSTRING(0); - #ifdef NOT_USED Oid typelem = PG_GETARG_OID(1); #endif int32 atttypmod = PG_GETARG_INT32(2); BpChar *result; - result = bpchar_input(s, strlen(s), atttypmod); + result = bpchar_input(s, strlen(s), atttypmod, fcinfo->context); PG_RETURN_BPCHAR_P(result); } @@ -228,7 +231,6 @@ Datum bpcharrecv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); - #ifdef NOT_USED Oid typelem = PG_GETARG_OID(1); #endif @@ -238,7 +240,7 @@ bpcharrecv(PG_FUNCTION_ARGS) int nbytes; str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes); - result = bpchar_input(str, nbytes, atttypmod); + result = bpchar_input(str, nbytes, atttypmod, NULL); pfree(str); PG_RETURN_BPCHAR_P(result); } @@ -448,11 +450,12 @@ bpchartypmodout(PG_FUNCTION_ARGS) * If the input string is too long, raise an error, unless the extra * characters are spaces, in which case they're truncated. (per SQL) * - * Uses the C string to text conversion function, which is only appropriate - * if VarChar and text are equivalent types. + * If escontext points to an ErrorSaveContext node, that is filled instead + * of throwing an error; the caller must check SOFT_ERROR_OCCURRED() + * to detect errors. */ static VarChar * -varchar_input(const char *s, size_t len, int32 atttypmod) +varchar_input(const char *s, size_t len, int32 atttypmod, Node *escontext) { VarChar *result; size_t maxlen; @@ -468,7 +471,7 @@ varchar_input(const char *s, size_t len, int32 atttypmod) for (j = mbmaxlen; j < len; j++) { if (s[j] != ' ') - ereport(ERROR, + ereturn(escontext, NULL, (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), errmsg("value too long for type character varying(%d)", (int) maxlen))); @@ -477,6 +480,10 @@ varchar_input(const char *s, size_t len, int32 atttypmod) len = mbmaxlen; } + /* + * We can use cstring_to_text_with_len because VarChar and text are + * binary-compatible types. + */ result = (VarChar *) cstring_to_text_with_len(s, len); return result; } @@ -489,14 +496,13 @@ Datum varcharin(PG_FUNCTION_ARGS) { char *s = PG_GETARG_CSTRING(0); - #ifdef NOT_USED Oid typelem = PG_GETARG_OID(1); #endif int32 atttypmod = PG_GETARG_INT32(2); VarChar *result; - result = varchar_input(s, strlen(s), atttypmod); + result = varchar_input(s, strlen(s), atttypmod, fcinfo->context); PG_RETURN_VARCHAR_P(result); } @@ -522,7 +528,6 @@ Datum varcharrecv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); - #ifdef NOT_USED Oid typelem = PG_GETARG_OID(1); #endif @@ -532,7 +537,7 @@ varcharrecv(PG_FUNCTION_ARGS) int nbytes; str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes); - result = varchar_input(str, nbytes, atttypmod); + result = varchar_input(str, nbytes, atttypmod, NULL); pfree(str); PG_RETURN_VARCHAR_P(result); } diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index c5e7ee7ca2d..1c52deec556 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -295,6 +295,7 @@ Datum byteain(PG_FUNCTION_ARGS) { char *inputText = PG_GETARG_CSTRING(0); + Node *escontext = fcinfo->context; char *tp; char *rp; int bc; @@ -307,7 +308,8 @@ byteain(PG_FUNCTION_ARGS) bc = (len - 2) / 2 + VARHDRSZ; /* maximum possible length */ result = palloc(bc); - bc = hex_decode(inputText + 2, len - 2, VARDATA(result)); + bc = hex_decode_safe(inputText + 2, len - 2, VARDATA(result), + escontext); SET_VARSIZE(result, bc + VARHDRSZ); /* actual length */ PG_RETURN_BYTEA_P(result); @@ -331,7 +333,7 @@ byteain(PG_FUNCTION_ARGS) /* * one backslash, not followed by another or ### valid octal */ - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s", "bytea"))); } @@ -372,7 +374,7 @@ byteain(PG_FUNCTION_ARGS) /* * We should never get here. The first pass should not allow it. */ - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s", "bytea"))); } |