From 17407a8eaa2afa8ac0de4b0a494f33d8eb7a98bd Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 14 Dec 2022 13:22:08 -0500 Subject: [PATCH] Convert a few more datatype input functions to report errors softly. Convert bit_in, varbit_in, inet_in, cidr_in, macaddr_in, and macaddr8_in to the new style. Amul Sul, minor mods by me Discussion: https://postgr.es/m/CAAJ_b97KeDWUdpTKGOaFYPv0OicjOu6EW+QYWj-Ywrgj_aEy1g@mail.gmail.com --- src/backend/utils/adt/mac.c | 5 +- src/backend/utils/adt/mac8.c | 65 +++++++++++--------------- src/backend/utils/adt/network.c | 14 +++--- src/backend/utils/adt/varbit.c | 20 ++++---- src/test/regress/expected/bit.out | 61 ++++++++++++++++++++++++ src/test/regress/expected/inet.out | 37 +++++++++++++++ src/test/regress/expected/macaddr.out | 25 ++++++++++ src/test/regress/expected/macaddr8.out | 25 ++++++++++ src/test/regress/sql/bit.sql | 13 ++++++ src/test/regress/sql/inet.sql | 9 ++++ src/test/regress/sql/macaddr.sql | 6 +++ src/test/regress/sql/macaddr8.sql | 6 +++ 12 files changed, 230 insertions(+), 56 deletions(-) diff --git a/src/backend/utils/adt/mac.c b/src/backend/utils/adt/mac.c index ac7342cfca..089450dac3 100644 --- a/src/backend/utils/adt/mac.c +++ b/src/backend/utils/adt/mac.c @@ -55,6 +55,7 @@ Datum macaddr_in(PG_FUNCTION_ARGS) { char *str = PG_GETARG_CSTRING(0); + Node *escontext = fcinfo->context; macaddr *result; int a, b, @@ -88,7 +89,7 @@ macaddr_in(PG_FUNCTION_ARGS) count = sscanf(str, "%2x%2x%2x%2x%2x%2x%1s", &a, &b, &c, &d, &e, &f, junk); if (count != 6) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", "macaddr", str))); @@ -96,7 +97,7 @@ macaddr_in(PG_FUNCTION_ARGS) if ((a < 0) || (a > 255) || (b < 0) || (b > 255) || (c < 0) || (c > 255) || (d < 0) || (d > 255) || (e < 0) || (e > 255) || (f < 0) || (f > 255)) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("invalid octet value in \"macaddr\" value: \"%s\"", str))); diff --git a/src/backend/utils/adt/mac8.c b/src/backend/utils/adt/mac8.c index 24d219f638..87c8cebf6e 100644 --- a/src/backend/utils/adt/mac8.c +++ b/src/backend/utils/adt/mac8.c @@ -35,7 +35,7 @@ #define lobits(addr) \ ((unsigned long)(((addr)->e<<24) | ((addr)->f<<16) | ((addr)->g<<8) | ((addr)->h))) -static unsigned char hex2_to_uchar(const unsigned char *ptr, const unsigned char *str); +static unsigned char hex2_to_uchar(const unsigned char *ptr, bool *badhex); static const signed char hexlookup[128] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -51,16 +51,13 @@ static const signed char hexlookup[128] = { /* * hex2_to_uchar - convert 2 hex digits to a byte (unsigned char) * - * This will ereport() if the end of the string is reached ('\0' found), or if + * Sets *badhex to true if the end of the string is reached ('\0' found), or if * either character is not a valid hex digit. - * - * ptr is the pointer to where the digits to convert are in the string, str is - * the entire string, which is used only for error reporting. */ static inline unsigned char -hex2_to_uchar(const unsigned char *ptr, const unsigned char *str) +hex2_to_uchar(const unsigned char *ptr, bool *badhex) { - unsigned char ret = 0; + unsigned char ret; signed char lookup; /* Handle the first character */ @@ -88,12 +85,7 @@ hex2_to_uchar(const unsigned char *ptr, const unsigned char *str) return ret; invalid_input: - ereport(ERROR, - (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8", - str))); - - /* We do not actually reach here */ + *badhex = true; return 0; } @@ -104,7 +96,9 @@ Datum macaddr8_in(PG_FUNCTION_ARGS) { const unsigned char *str = (unsigned char *) PG_GETARG_CSTRING(0); + Node *escontext = fcinfo->context; const unsigned char *ptr = str; + bool badhex = false; macaddr8 *result; unsigned char a = 0, b = 0, @@ -136,37 +130,37 @@ macaddr8_in(PG_FUNCTION_ARGS) switch (count) { case 1: - a = hex2_to_uchar(ptr, str); + a = hex2_to_uchar(ptr, &badhex); break; case 2: - b = hex2_to_uchar(ptr, str); + b = hex2_to_uchar(ptr, &badhex); break; case 3: - c = hex2_to_uchar(ptr, str); + c = hex2_to_uchar(ptr, &badhex); break; case 4: - d = hex2_to_uchar(ptr, str); + d = hex2_to_uchar(ptr, &badhex); break; case 5: - e = hex2_to_uchar(ptr, str); + e = hex2_to_uchar(ptr, &badhex); break; case 6: - f = hex2_to_uchar(ptr, str); + f = hex2_to_uchar(ptr, &badhex); break; case 7: - g = hex2_to_uchar(ptr, str); + g = hex2_to_uchar(ptr, &badhex); break; case 8: - h = hex2_to_uchar(ptr, str); + h = hex2_to_uchar(ptr, &badhex); break; default: /* must be trailing garbage... */ - ereport(ERROR, - (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8", - str))); + goto fail; } + if (badhex) + goto fail; + /* Move forward to where the next byte should be */ ptr += 2; @@ -179,10 +173,7 @@ macaddr8_in(PG_FUNCTION_ARGS) /* Have to use the same spacer throughout */ else if (spacer != *ptr) - ereport(ERROR, - (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8", - str))); + goto fail; /* move past the spacer */ ptr++; @@ -197,10 +188,7 @@ macaddr8_in(PG_FUNCTION_ARGS) /* If we found a space and then non-space, it's invalid */ if (*ptr) - ereport(ERROR, - (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8", - str))); + goto fail; } } } @@ -216,10 +204,7 @@ macaddr8_in(PG_FUNCTION_ARGS) e = 0xFE; } else if (count != 8) - ereport(ERROR, - (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8", - str))); + goto fail; result = (macaddr8 *) palloc0(sizeof(macaddr8)); @@ -233,6 +218,12 @@ macaddr8_in(PG_FUNCTION_ARGS) result->h = h; PG_RETURN_MACADDR8_P(result); + +fail: + ereturn(escontext, (Datum) 0, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8", + str))); } /* diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c index 6d580ea78f..42a4d9d44e 100644 --- a/src/backend/utils/adt/network.c +++ b/src/backend/utils/adt/network.c @@ -72,7 +72,7 @@ static inet *internal_inetpl(inet *ip, int64 addend); * Common INET/CIDR input routine */ static inet * -network_in(char *src, bool is_cidr) +network_in(char *src, bool is_cidr, Node *escontext) { int bits; inet *dst; @@ -93,7 +93,7 @@ network_in(char *src, bool is_cidr) bits = pg_inet_net_pton(ip_family(dst), src, ip_addr(dst), is_cidr ? ip_addrsize(dst) : -1); if ((bits < 0) || (bits > ip_maxbits(dst))) - ereport(ERROR, + ereturn(escontext, NULL, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), /* translator: first %s is inet or cidr */ errmsg("invalid input syntax for type %s: \"%s\"", @@ -105,7 +105,7 @@ network_in(char *src, bool is_cidr) if (is_cidr) { if (!addressOK(ip_addr(dst), bits, ip_family(dst))) - ereport(ERROR, + ereturn(escontext, NULL, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid cidr value: \"%s\"", src), errdetail("Value has bits set to right of mask."))); @@ -122,7 +122,7 @@ inet_in(PG_FUNCTION_ARGS) { char *src = PG_GETARG_CSTRING(0); - PG_RETURN_INET_P(network_in(src, false)); + PG_RETURN_INET_P(network_in(src, false, fcinfo->context)); } Datum @@ -130,7 +130,7 @@ cidr_in(PG_FUNCTION_ARGS) { char *src = PG_GETARG_CSTRING(0); - PG_RETURN_INET_P(network_in(src, true)); + PG_RETURN_INET_P(network_in(src, true, fcinfo->context)); } @@ -1742,7 +1742,7 @@ inet_client_addr(PG_FUNCTION_ARGS) clean_ipv6_addr(port->raddr.addr.ss_family, remote_host); - PG_RETURN_INET_P(network_in(remote_host, false)); + PG_RETURN_INET_P(network_in(remote_host, false, NULL)); } @@ -1814,7 +1814,7 @@ inet_server_addr(PG_FUNCTION_ARGS) clean_ipv6_addr(port->laddr.addr.ss_family, local_host); - PG_RETURN_INET_P(network_in(local_host, false)); + PG_RETURN_INET_P(network_in(local_host, false, NULL)); } diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c index 73e41e0808..30248cf3cc 100644 --- a/src/backend/utils/adt/varbit.c +++ b/src/backend/utils/adt/varbit.c @@ -147,11 +147,11 @@ Datum bit_in(PG_FUNCTION_ARGS) { char *input_string = PG_GETARG_CSTRING(0); - #ifdef NOT_USED Oid typelem = PG_GETARG_OID(1); #endif int32 atttypmod = PG_GETARG_INT32(2); + Node *escontext = fcinfo->context; VarBit *result; /* The resulting bit string */ char *sp; /* pointer into the character string */ bits8 *r; /* pointer into the result */ @@ -193,7 +193,7 @@ bit_in(PG_FUNCTION_ARGS) else { if (slen > VARBITMAXLEN / 4) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("bit string length exceeds the maximum allowed (%d)", VARBITMAXLEN))); @@ -207,7 +207,7 @@ bit_in(PG_FUNCTION_ARGS) if (atttypmod <= 0) atttypmod = bitlen; else if (bitlen != atttypmod) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH), errmsg("bit string length %d does not match type bit(%d)", bitlen, atttypmod))); @@ -229,7 +229,7 @@ bit_in(PG_FUNCTION_ARGS) if (*sp == '1') *r |= x; else if (*sp != '0') - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("\"%.*s\" is not a valid binary digit", pg_mblen(sp), sp))); @@ -254,7 +254,7 @@ bit_in(PG_FUNCTION_ARGS) else if (*sp >= 'a' && *sp <= 'f') x = (bits8) (*sp - 'a') + 10; else - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("\"%.*s\" is not a valid hexadecimal digit", pg_mblen(sp), sp))); @@ -452,11 +452,11 @@ Datum varbit_in(PG_FUNCTION_ARGS) { char *input_string = PG_GETARG_CSTRING(0); - #ifdef NOT_USED Oid typelem = PG_GETARG_OID(1); #endif int32 atttypmod = PG_GETARG_INT32(2); + Node *escontext = fcinfo->context; VarBit *result; /* The resulting bit string */ char *sp; /* pointer into the character string */ bits8 *r; /* pointer into the result */ @@ -494,7 +494,7 @@ varbit_in(PG_FUNCTION_ARGS) else { if (slen > VARBITMAXLEN / 4) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("bit string length exceeds the maximum allowed (%d)", VARBITMAXLEN))); @@ -508,7 +508,7 @@ varbit_in(PG_FUNCTION_ARGS) if (atttypmod <= 0) atttypmod = bitlen; else if (bitlen > atttypmod) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), errmsg("bit string too long for type bit varying(%d)", atttypmod))); @@ -530,7 +530,7 @@ varbit_in(PG_FUNCTION_ARGS) if (*sp == '1') *r |= x; else if (*sp != '0') - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("\"%.*s\" is not a valid binary digit", pg_mblen(sp), sp))); @@ -555,7 +555,7 @@ varbit_in(PG_FUNCTION_ARGS) else if (*sp >= 'a' && *sp <= 'f') x = (bits8) (*sp - 'a') + 10; else - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("\"%.*s\" is not a valid hexadecimal digit", pg_mblen(sp), sp))); diff --git a/src/test/regress/expected/bit.out b/src/test/regress/expected/bit.out index a5aab9c0e3..209044713c 100644 --- a/src/test/regress/expected/bit.out +++ b/src/test/regress/expected/bit.out @@ -746,3 +746,64 @@ TABLE bit_defaults; 1001 | 0101 | 1001 | 0101 (1 row) +-- test non-error-throwing API for some core types +SELECT pg_input_is_valid('01010001', 'bit(10)'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('01010001', 'bit(10)'); + pg_input_error_message +------------------------------------------------- + bit string length 8 does not match type bit(10) +(1 row) + +SELECT pg_input_is_valid('01010Z01', 'bit(8)'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('01010Z01', 'bit(8)'); + pg_input_error_message +--------------------------------- + "Z" is not a valid binary digit +(1 row) + +SELECT pg_input_is_valid('x01010Z01', 'bit(32)'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('x01010Z01', 'bit(32)'); + pg_input_error_message +-------------------------------------- + "Z" is not a valid hexadecimal digit +(1 row) + +SELECT pg_input_is_valid('01010Z01', 'varbit'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('01010Z01', 'varbit'); + pg_input_error_message +--------------------------------- + "Z" is not a valid binary digit +(1 row) + +SELECT pg_input_is_valid('x01010Z01', 'varbit'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('x01010Z01', 'varbit'); + pg_input_error_message +-------------------------------------- + "Z" is not a valid hexadecimal digit +(1 row) + diff --git a/src/test/regress/expected/inet.out b/src/test/regress/expected/inet.out index d5bf9e2aaa..c9f466ac1d 100644 --- a/src/test/regress/expected/inet.out +++ b/src/test/regress/expected/inet.out @@ -1056,3 +1056,40 @@ SELECT a FROM (VALUES ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff (91 rows) +-- test non-error-throwing API for some core types +SELECT pg_input_is_valid('1234', 'cidr'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('1234', 'cidr'); + pg_input_error_message +-------------------------------------------- + invalid input syntax for type cidr: "1234" +(1 row) + +SELECT pg_input_is_valid('192.168.198.200/24', 'cidr'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('192.168.198.200/24', 'cidr'); + pg_input_error_message +------------------------------------------ + invalid cidr value: "192.168.198.200/24" +(1 row) + +SELECT pg_input_is_valid('1234', 'inet'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('1234', 'inet'); + pg_input_error_message +-------------------------------------------- + invalid input syntax for type inet: "1234" +(1 row) + diff --git a/src/test/regress/expected/macaddr.out b/src/test/regress/expected/macaddr.out index 151f9ce59b..cb646af79b 100644 --- a/src/test/regress/expected/macaddr.out +++ b/src/test/regress/expected/macaddr.out @@ -158,3 +158,28 @@ SELECT b | '01:02:03:04:05:06' FROM macaddr_data; (12 rows) DROP TABLE macaddr_data; +-- test non-error-throwing API for some core types +SELECT pg_input_is_valid('08:00:2b:01:02:ZZ', 'macaddr'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('08:00:2b:01:02:ZZ', 'macaddr'); + pg_input_error_message +------------------------------------------------------------ + invalid input syntax for type macaddr: "08:00:2b:01:02:ZZ" +(1 row) + +SELECT pg_input_is_valid('08:00:2b:01:02:', 'macaddr'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('08:00:2b:01:02:', 'macaddr'); + pg_input_error_message +---------------------------------------------------------- + invalid input syntax for type macaddr: "08:00:2b:01:02:" +(1 row) + diff --git a/src/test/regress/expected/macaddr8.out b/src/test/regress/expected/macaddr8.out index 74f53a121f..bf681988f8 100644 --- a/src/test/regress/expected/macaddr8.out +++ b/src/test/regress/expected/macaddr8.out @@ -352,3 +352,28 @@ SELECT b | '01:02:03:04:05:06' FROM macaddr8_data; (20 rows) DROP TABLE macaddr8_data; +-- test non-error-throwing API for some core types +SELECT pg_input_is_valid('08:00:2b:01:02:03:04:ZZ', 'macaddr8'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('08:00:2b:01:02:03:04:ZZ', 'macaddr8'); + pg_input_error_message +------------------------------------------------------------------- + invalid input syntax for type macaddr8: "08:00:2b:01:02:03:04:ZZ" +(1 row) + +SELECT pg_input_is_valid('08:00:2b:01:02:03:04:', 'macaddr8'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('08:00:2b:01:02:03:04:', 'macaddr8'); + pg_input_error_message +----------------------------------------------------------------- + invalid input syntax for type macaddr8: "08:00:2b:01:02:03:04:" +(1 row) + diff --git a/src/test/regress/sql/bit.sql b/src/test/regress/sql/bit.sql index 0a424e796b..8814249c2a 100644 --- a/src/test/regress/sql/bit.sql +++ b/src/test/regress/sql/bit.sql @@ -229,3 +229,16 @@ CREATE TABLE bit_defaults( \d bit_defaults INSERT INTO bit_defaults DEFAULT VALUES; TABLE bit_defaults; + +-- test non-error-throwing API for some core types +SELECT pg_input_is_valid('01010001', 'bit(10)'); +SELECT pg_input_error_message('01010001', 'bit(10)'); +SELECT pg_input_is_valid('01010Z01', 'bit(8)'); +SELECT pg_input_error_message('01010Z01', 'bit(8)'); +SELECT pg_input_is_valid('x01010Z01', 'bit(32)'); +SELECT pg_input_error_message('x01010Z01', 'bit(32)'); + +SELECT pg_input_is_valid('01010Z01', 'varbit'); +SELECT pg_input_error_message('01010Z01', 'varbit'); +SELECT pg_input_is_valid('x01010Z01', 'varbit'); +SELECT pg_input_error_message('x01010Z01', 'varbit'); diff --git a/src/test/regress/sql/inet.sql b/src/test/regress/sql/inet.sql index d2ac85bb7f..abfcd4242f 100644 --- a/src/test/regress/sql/inet.sql +++ b/src/test/regress/sql/inet.sql @@ -252,3 +252,12 @@ SELECT a FROM (VALUES ('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/0'::inet), ('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128'::inet) ) AS i(a) ORDER BY a; + +-- test non-error-throwing API for some core types +SELECT pg_input_is_valid('1234', 'cidr'); +SELECT pg_input_error_message('1234', 'cidr'); +SELECT pg_input_is_valid('192.168.198.200/24', 'cidr'); +SELECT pg_input_error_message('192.168.198.200/24', 'cidr'); + +SELECT pg_input_is_valid('1234', 'inet'); +SELECT pg_input_error_message('1234', 'inet'); diff --git a/src/test/regress/sql/macaddr.sql b/src/test/regress/sql/macaddr.sql index 7bad8f5d7a..211397c8f3 100644 --- a/src/test/regress/sql/macaddr.sql +++ b/src/test/regress/sql/macaddr.sql @@ -41,3 +41,9 @@ SELECT b & '00:00:00:ff:ff:ff' FROM macaddr_data; SELECT b | '01:02:03:04:05:06' FROM macaddr_data; DROP TABLE macaddr_data; + +-- test non-error-throwing API for some core types +SELECT pg_input_is_valid('08:00:2b:01:02:ZZ', 'macaddr'); +SELECT pg_input_error_message('08:00:2b:01:02:ZZ', 'macaddr'); +SELECT pg_input_is_valid('08:00:2b:01:02:', 'macaddr'); +SELECT pg_input_error_message('08:00:2b:01:02:', 'macaddr'); diff --git a/src/test/regress/sql/macaddr8.sql b/src/test/regress/sql/macaddr8.sql index 57a227c5ab..b29f785b41 100644 --- a/src/test/regress/sql/macaddr8.sql +++ b/src/test/regress/sql/macaddr8.sql @@ -87,3 +87,9 @@ SELECT b & '00:00:00:ff:ff:ff' FROM macaddr8_data; SELECT b | '01:02:03:04:05:06' FROM macaddr8_data; DROP TABLE macaddr8_data; + +-- test non-error-throwing API for some core types +SELECT pg_input_is_valid('08:00:2b:01:02:03:04:ZZ', 'macaddr8'); +SELECT pg_input_error_message('08:00:2b:01:02:03:04:ZZ', 'macaddr8'); +SELECT pg_input_is_valid('08:00:2b:01:02:03:04:', 'macaddr8'); +SELECT pg_input_error_message('08:00:2b:01:02:03:04:', 'macaddr8'); -- 2.30.2