On Mon, Dec 12, 2022 at 12:00 AM Tom Lane <t...@sss.pgh.pa.us> wrote: > > Andrew Dunstan <and...@dunslane.net> writes: > > Maybe as we work through the remaining input functions (there are about > > 60 core candidates left on my list) we should mark them with a comment > > if no adjustment is needed. > > I did a quick pass through them last night. Assuming that we don't > need to touch the unimplemented input functions (eg for pseudotypes), > I count these core functions as still needing work: > > aclitemin > bit_in > box_in > bpcharin > byteain > cash_in > cidin > cidr_in > circle_in > inet_in > int2vectorin > jsonpath_in > line_in > lseg_in > macaddr8_in > macaddr_in
Attaching patches changing these functions except bpcharin, byteain, jsonpath_in, and cidin. I am continuing work on the next items below: > multirange_in > namein > oidin > oidvectorin > path_in > pg_lsn_in > pg_snapshot_in > point_in > poly_in > range_in > regclassin > regcollationin > regconfigin > regdictionaryin > regnamespacein > regoperatorin > regoperin > regprocedurein > regprocin > regrolein > regtypein > tidin > tsqueryin > tsvectorin > uuid_in > varbit_in > varcharin > xid8in > xidin > xml_in > > and these contrib functions: > > hstore: > hstore_in > intarray: > bqarr_in > isn: > ean13_in > isbn_in > ismn_in > issn_in > upc_in > ltree: > ltree_in > lquery_in > ltxtq_in > seg: > seg_in > > Maybe we should have a conversation about which of these are > highest priority to get to a credible feature. We clearly need > to fix the remaining SQL-spec types (varchar and bpchar, mainly). > At the other extreme, likely nobody would weep if we never fixed > int2vectorin, for instance. > > I'm a little concerned about the cost-benefit of fixing the reg* types. > The ones that accept type names actually use the core grammar to parse > those. Now, we probably could fix the grammar to be non-throwing, but > it'd be very invasive and I'm not sure about the performance impact. > It might be best to content ourselves with soft reporting of lookup > failures, as opposed to syntax problems. > Regards, Amul
From 4c4c18bd8104114351ca58a73a9d92fbb0c85dd2 Mon Sep 17 00:00:00 2001 From: Amul Sul <amul.sul@enterprisedb.com> Date: Tue, 13 Dec 2022 17:29:04 +0530 Subject: [PATCH v1 13/14] Change macaddr8_in to allow non-throw error reporting --- src/backend/utils/adt/mac8.c | 36 +++++++++++++------------- src/test/regress/expected/macaddr8.out | 25 ++++++++++++++++++ src/test/regress/sql/macaddr8.sql | 6 +++++ 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/src/backend/utils/adt/mac8.c b/src/backend/utils/adt/mac8.c index 24d219f6386..adb253a6ac0 100644 --- a/src/backend/utils/adt/mac8.c +++ b/src/backend/utils/adt/mac8.c @@ -35,7 +35,8 @@ #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, const unsigned char *str, + Node *escontext); static const signed char hexlookup[128] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -58,7 +59,8 @@ static const signed char hexlookup[128] = { * 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, const unsigned char *str, + Node *escontext) { unsigned char ret = 0; signed char lookup; @@ -88,13 +90,10 @@ hex2_to_uchar(const unsigned char *ptr, const unsigned char *str) return ret; invalid_input: - ereport(ERROR, + ereturn(escontext, 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8", str))); - - /* We do not actually reach here */ - return 0; } /* @@ -104,6 +103,7 @@ 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; macaddr8 *result; unsigned char a = 0, @@ -136,32 +136,32 @@ macaddr8_in(PG_FUNCTION_ARGS) switch (count) { case 1: - a = hex2_to_uchar(ptr, str); + a = hex2_to_uchar(ptr, str, escontext); break; case 2: - b = hex2_to_uchar(ptr, str); + b = hex2_to_uchar(ptr, str, escontext); break; case 3: - c = hex2_to_uchar(ptr, str); + c = hex2_to_uchar(ptr, str, escontext); break; case 4: - d = hex2_to_uchar(ptr, str); + d = hex2_to_uchar(ptr, str, escontext); break; case 5: - e = hex2_to_uchar(ptr, str); + e = hex2_to_uchar(ptr, str, escontext); break; case 6: - f = hex2_to_uchar(ptr, str); + f = hex2_to_uchar(ptr, str, escontext); break; case 7: - g = hex2_to_uchar(ptr, str); + g = hex2_to_uchar(ptr, str, escontext); break; case 8: - h = hex2_to_uchar(ptr, str); + h = hex2_to_uchar(ptr, str, escontext); break; default: /* must be trailing garbage... */ - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8", str))); @@ -179,7 +179,7 @@ macaddr8_in(PG_FUNCTION_ARGS) /* Have to use the same spacer throughout */ else if (spacer != *ptr) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8", str))); @@ -197,7 +197,7 @@ macaddr8_in(PG_FUNCTION_ARGS) /* If we found a space and then non-space, it's invalid */ if (*ptr) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8", str))); @@ -216,7 +216,7 @@ macaddr8_in(PG_FUNCTION_ARGS) e = 0xFE; } else if (count != 8) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8", str))); diff --git a/src/test/regress/expected/macaddr8.out b/src/test/regress/expected/macaddr8.out index 74f53a121f2..bf681988f87 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/macaddr8.sql b/src/test/regress/sql/macaddr8.sql index 57a227c5ab7..b29f785b41e 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.18.0
From 87b35edfdef4e5255810e903a2df5e331b6003e6 Mon Sep 17 00:00:00 2001 From: Amul Sul <amul.sul@enterprisedb.com> Date: Tue, 13 Dec 2022 17:36:03 +0530 Subject: [PATCH v1 14/14] Change macaddr_in to allow non-throw error reporting --- src/backend/utils/adt/mac.c | 5 +++-- src/test/regress/expected/macaddr.out | 25 +++++++++++++++++++++++++ src/test/regress/sql/macaddr.sql | 6 ++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/backend/utils/adt/mac.c b/src/backend/utils/adt/mac.c index ac7342cfca7..089450dac34 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/test/regress/expected/macaddr.out b/src/test/regress/expected/macaddr.out index 151f9ce59bb..cb646af79bd 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/sql/macaddr.sql b/src/test/regress/sql/macaddr.sql index 7bad8f5d7ae..211397c8f3c 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'); -- 2.18.0
From ba071042d08f9dd55de1800ac1c04ffafceecff4 Mon Sep 17 00:00:00 2001 From: Amul Sul <amul.sul@enterprisedb.com> Date: Tue, 13 Dec 2022 14:41:05 +0530 Subject: [PATCH v1 10/14] Change int2vectorin to allow non-throw error reporting --- src/backend/utils/adt/int.c | 9 +++++---- src/test/regress/expected/type_sanity.out | 24 +++++++++++++++++++++++ src/test/regress/sql/type_sanity.sql | 5 +++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/backend/utils/adt/int.c b/src/backend/utils/adt/int.c index 8de38abd11d..2c90e526a60 100644 --- a/src/backend/utils/adt/int.c +++ b/src/backend/utils/adt/int.c @@ -141,6 +141,7 @@ Datum int2vectorin(PG_FUNCTION_ARGS) { char *intString = PG_GETARG_CSTRING(0); + Node *escontext = fcinfo->context; int2vector *result; int n; @@ -160,19 +161,19 @@ int2vectorin(PG_FUNCTION_ARGS) l = strtol(intString, &endp, 10); if (intString == endp) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", "smallint", intString))); if (errno == ERANGE || l < SHRT_MIN || l > SHRT_MAX) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("value \"%s\" is out of range for type %s", intString, "smallint"))); if (*endp && *endp != ' ') - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", "integer", intString))); @@ -183,7 +184,7 @@ int2vectorin(PG_FUNCTION_ARGS) while (*intString && isspace((unsigned char) *intString)) intString++; if (*intString) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("int2vector has too many elements"))); diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out index 0b015b424f1..241b628fb07 100644 --- a/src/test/regress/expected/type_sanity.out +++ b/src/test/regress/expected/type_sanity.out @@ -832,3 +832,27 @@ SELECT pg_input_error_message('1', 'gtsvector'); cannot accept a value of type gtsvector (1 row) +SELECT pg_input_is_valid('1 XYZ', 'int2vector'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('1 XYZ', 'int2vector'); + pg_input_error_message +----------------------------------------------- + invalid input syntax for type smallint: "XYZ" +(1 row) + +SELECT pg_input_is_valid('1 99999', 'int2vector'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('1 99999', 'int2vector'); + pg_input_error_message +------------------------------------------------- + value "99999" is out of range for type smallint +(1 row) + diff --git a/src/test/regress/sql/type_sanity.sql b/src/test/regress/sql/type_sanity.sql index d024d950b3e..b59ebf9490c 100644 --- a/src/test/regress/sql/type_sanity.sql +++ b/src/test/regress/sql/type_sanity.sql @@ -605,3 +605,8 @@ SELECT pg_input_error_message('1', 'pg_brin_minmax_multi_summary'); SELECT pg_input_is_valid('1', 'gtsvector'); SELECT pg_input_error_message('1', 'gtsvector'); + +SELECT pg_input_is_valid('1 XYZ', 'int2vector'); +SELECT pg_input_error_message('1 XYZ', 'int2vector'); +SELECT pg_input_is_valid('1 99999', 'int2vector'); +SELECT pg_input_error_message('1 99999', 'int2vector'); -- 2.18.0
From 508919f004d671cda39f4f2f2bc0a06b7b377e64 Mon Sep 17 00:00:00 2001 From: Amul Sul <amul.sul@enterprisedb.com> Date: Tue, 13 Dec 2022 17:12:53 +0530 Subject: [PATCH v1 12/14] Change lseg_in to allow non-throw error reporting --- src/backend/utils/adt/geo_ops.c | 7 +++++-- src/test/regress/expected/lseg.out | 13 +++++++++++++ src/test/regress/sql/lseg.sql | 4 ++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c index 480d3d4a64a..52bd62c4cc1 100644 --- a/src/backend/utils/adt/geo_ops.c +++ b/src/backend/utils/adt/geo_ops.c @@ -2065,11 +2065,14 @@ Datum lseg_in(PG_FUNCTION_ARGS) { char *str = PG_GETARG_CSTRING(0); + Node *escontext = fcinfo->context; LSEG *lseg = (LSEG *) palloc(sizeof(LSEG)); bool isopen; - path_decode(str, true, 2, &lseg->p[0], &isopen, NULL, "lseg", str, - NULL); + if (!path_decode(str, true, 2, &lseg->p[0], &isopen, NULL, "lseg", str, + escontext)) + PG_RETURN_NULL(); + PG_RETURN_LSEG_P(lseg); } diff --git a/src/test/regress/expected/lseg.out b/src/test/regress/expected/lseg.out index 7e878b55779..afb323fe04c 100644 --- a/src/test/regress/expected/lseg.out +++ b/src/test/regress/expected/lseg.out @@ -42,3 +42,16 @@ select * from LSEG_TBL; [(NaN,1),(NaN,90)] (8 rows) +-- test non-error-throwing API for some core types +SELECT pg_input_is_valid('[(1,2),(3)]', 'lseg'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('[(1,2),(3)]', 'lseg'); + pg_input_error_message +--------------------------------------------------- + invalid input syntax for type lseg: "[(1,2),(3)]" +(1 row) + diff --git a/src/test/regress/sql/lseg.sql b/src/test/regress/sql/lseg.sql index f266ca3e09e..0fece162e01 100644 --- a/src/test/regress/sql/lseg.sql +++ b/src/test/regress/sql/lseg.sql @@ -22,3 +22,7 @@ INSERT INTO LSEG_TBL VALUES ('[(,2),(3,4)]'); INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)'); select * from LSEG_TBL; + +-- test non-error-throwing API for some core types +SELECT pg_input_is_valid('[(1,2),(3)]', 'lseg'); +SELECT pg_input_error_message('[(1,2),(3)]', 'lseg'); -- 2.18.0
From 19133fbe50c39563739931374fbe937eeec2b879 Mon Sep 17 00:00:00 2001 From: Amul Sul <amul.sul@enterprisedb.com> Date: Tue, 13 Dec 2022 16:10:03 +0530 Subject: [PATCH v1 11/14] Change line_in to allow non-throw error reporting --- src/backend/utils/adt/float.c | 90 +++++++++++++++--------------- src/backend/utils/adt/geo_ops.c | 58 +++++++++++-------- src/include/utils/float.h | 53 ++++++++++++------ src/test/regress/expected/line.out | 37 ++++++++++++ src/test/regress/sql/line.sql | 8 +++ 5 files changed, 163 insertions(+), 83 deletions(-) diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c index b02a19be24d..3662a697f8a 100644 --- a/src/backend/utils/adt/float.c +++ b/src/backend/utils/adt/float.c @@ -82,17 +82,17 @@ static void init_degree_constants(void); * This does mean that you don't get a useful error location indicator. */ pg_noinline void -float_overflow_error(void) +float_overflow_error(Node *escontext) { - ereport(ERROR, + errsave(escontext, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("value out of range: overflow"))); } pg_noinline void -float_underflow_error(void) +float_underflow_error(Node *escontext) { - ereport(ERROR, + errsave(escontext, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("value out of range: underflow"))); } @@ -1172,9 +1172,9 @@ dtof(PG_FUNCTION_ARGS) result = (float4) num; if (unlikely(isinf(result)) && !isinf(num)) - float_overflow_error(); + float_overflow_error(NULL); if (unlikely(result == 0.0f) && num != 0.0) - float_underflow_error(); + float_underflow_error(NULL); PG_RETURN_FLOAT4(result); } @@ -1428,9 +1428,9 @@ dsqrt(PG_FUNCTION_ARGS) result = sqrt(arg1); if (unlikely(isinf(result)) && !isinf(arg1)) - float_overflow_error(); + float_overflow_error(NULL); if (unlikely(result == 0.0) && arg1 != 0.0) - float_underflow_error(); + float_underflow_error(NULL); PG_RETURN_FLOAT8(result); } @@ -1447,9 +1447,9 @@ dcbrt(PG_FUNCTION_ARGS) result = cbrt(arg1); if (unlikely(isinf(result)) && !isinf(arg1)) - float_overflow_error(); + float_overflow_error(NULL); if (unlikely(result == 0.0) && arg1 != 0.0) - float_underflow_error(); + float_underflow_error(NULL); PG_RETURN_FLOAT8(result); } @@ -1585,24 +1585,24 @@ dpow(PG_FUNCTION_ARGS) if (absx == 1.0) result = 1.0; else if (arg2 >= 0.0 ? (absx > 1.0) : (absx < 1.0)) - float_overflow_error(); + float_overflow_error(NULL); else - float_underflow_error(); + float_underflow_error(NULL); } } else if (errno == ERANGE) { if (result != 0.0) - float_overflow_error(); + float_overflow_error(NULL); else - float_underflow_error(); + float_underflow_error(NULL); } else { if (unlikely(isinf(result))) - float_overflow_error(); + float_overflow_error(NULL); if (unlikely(result == 0.0) && arg1 != 0.0) - float_underflow_error(); + float_underflow_error(NULL); } } @@ -1642,14 +1642,14 @@ dexp(PG_FUNCTION_ARGS) if (unlikely(errno == ERANGE)) { if (result != 0.0) - float_overflow_error(); + float_overflow_error(NULL); else - float_underflow_error(); + float_underflow_error(NULL); } else if (unlikely(isinf(result))) - float_overflow_error(); + float_overflow_error(NULL); else if (unlikely(result == 0.0)) - float_underflow_error(); + float_underflow_error(NULL); } PG_RETURN_FLOAT8(result); @@ -1680,9 +1680,9 @@ dlog1(PG_FUNCTION_ARGS) result = log(arg1); if (unlikely(isinf(result)) && !isinf(arg1)) - float_overflow_error(); + float_overflow_error(NULL); if (unlikely(result == 0.0) && arg1 != 1.0) - float_underflow_error(); + float_underflow_error(NULL); PG_RETURN_FLOAT8(result); } @@ -1713,9 +1713,9 @@ dlog10(PG_FUNCTION_ARGS) result = log10(arg1); if (unlikely(isinf(result)) && !isinf(arg1)) - float_overflow_error(); + float_overflow_error(NULL); if (unlikely(result == 0.0) && arg1 != 1.0) - float_underflow_error(); + float_underflow_error(NULL); PG_RETURN_FLOAT8(result); } @@ -1746,7 +1746,7 @@ dacos(PG_FUNCTION_ARGS) result = acos(arg1); if (unlikely(isinf(result))) - float_overflow_error(); + float_overflow_error(NULL); PG_RETURN_FLOAT8(result); } @@ -1777,7 +1777,7 @@ dasin(PG_FUNCTION_ARGS) result = asin(arg1); if (unlikely(isinf(result))) - float_overflow_error(); + float_overflow_error(NULL); PG_RETURN_FLOAT8(result); } @@ -1803,7 +1803,7 @@ datan(PG_FUNCTION_ARGS) */ result = atan(arg1); if (unlikely(isinf(result))) - float_overflow_error(); + float_overflow_error(NULL); PG_RETURN_FLOAT8(result); } @@ -1829,7 +1829,7 @@ datan2(PG_FUNCTION_ARGS) */ result = atan2(arg1, arg2); if (unlikely(isinf(result))) - float_overflow_error(); + float_overflow_error(NULL); PG_RETURN_FLOAT8(result); } @@ -1870,7 +1870,7 @@ dcos(PG_FUNCTION_ARGS) (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); if (unlikely(isinf(result))) - float_overflow_error(); + float_overflow_error(NULL); PG_RETURN_FLOAT8(result); } @@ -1925,7 +1925,7 @@ dsin(PG_FUNCTION_ARGS) (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); if (unlikely(isinf(result))) - float_overflow_error(); + float_overflow_error(NULL); PG_RETURN_FLOAT8(result); } @@ -2105,7 +2105,7 @@ dacosd(PG_FUNCTION_ARGS) result = 90.0 + asind_q1(-arg1); if (unlikely(isinf(result))) - float_overflow_error(); + float_overflow_error(NULL); PG_RETURN_FLOAT8(result); } @@ -2142,7 +2142,7 @@ dasind(PG_FUNCTION_ARGS) result = -asind_q1(-arg1); if (unlikely(isinf(result))) - float_overflow_error(); + float_overflow_error(NULL); PG_RETURN_FLOAT8(result); } @@ -2174,7 +2174,7 @@ datand(PG_FUNCTION_ARGS) result = (atan_arg1 / atan_1_0) * 45.0; if (unlikely(isinf(result))) - float_overflow_error(); + float_overflow_error(NULL); PG_RETURN_FLOAT8(result); } @@ -2210,7 +2210,7 @@ datan2d(PG_FUNCTION_ARGS) result = (atan2_arg1_arg2 / atan_1_0) * 45.0; if (unlikely(isinf(result))) - float_overflow_error(); + float_overflow_error(NULL); PG_RETURN_FLOAT8(result); } @@ -2333,7 +2333,7 @@ dcosd(PG_FUNCTION_ARGS) result = sign * cosd_q1(arg1); if (unlikely(isinf(result))) - float_overflow_error(); + float_overflow_error(NULL); PG_RETURN_FLOAT8(result); } @@ -2455,7 +2455,7 @@ dsind(PG_FUNCTION_ARGS) result = sign * sind_q1(arg1); if (unlikely(isinf(result))) - float_overflow_error(); + float_overflow_error(NULL); PG_RETURN_FLOAT8(result); } @@ -2613,7 +2613,7 @@ dcosh(PG_FUNCTION_ARGS) result = get_float8_infinity(); if (unlikely(result == 0.0)) - float_underflow_error(); + float_underflow_error(NULL); PG_RETURN_FLOAT8(result); } @@ -2633,7 +2633,7 @@ dtanh(PG_FUNCTION_ARGS) result = tanh(arg1); if (unlikely(isinf(result))) - float_overflow_error(); + float_overflow_error(NULL); PG_RETURN_FLOAT8(result); } @@ -2905,7 +2905,7 @@ float8_combine(PG_FUNCTION_ARGS) tmp = Sx1 / N1 - Sx2 / N2; Sxx = Sxx1 + Sxx2 + N1 * N2 * tmp * tmp / N; if (unlikely(isinf(Sxx)) && !isinf(Sxx1) && !isinf(Sxx2)) - float_overflow_error(); + float_overflow_error(NULL); } /* @@ -2974,7 +2974,7 @@ float8_accum(PG_FUNCTION_ARGS) if (isinf(Sx) || isinf(Sxx)) { if (!isinf(transvalues[1]) && !isinf(newval)) - float_overflow_error(); + float_overflow_error(NULL); Sxx = get_float8_nan(); } @@ -3059,7 +3059,7 @@ float4_accum(PG_FUNCTION_ARGS) if (isinf(Sx) || isinf(Sxx)) { if (!isinf(transvalues[1]) && !isinf(newval)) - float_overflow_error(); + float_overflow_error(NULL); Sxx = get_float8_nan(); } @@ -3291,7 +3291,7 @@ float8_regr_accum(PG_FUNCTION_ARGS) (isinf(Sxy) && !isinf(transvalues[1]) && !isinf(newvalX) && !isinf(transvalues[3]) && !isinf(newvalY))) - float_overflow_error(); + float_overflow_error(NULL); if (isinf(Sxx)) Sxx = get_float8_nan(); @@ -3445,15 +3445,15 @@ float8_regr_combine(PG_FUNCTION_ARGS) tmp1 = Sx1 / N1 - Sx2 / N2; Sxx = Sxx1 + Sxx2 + N1 * N2 * tmp1 * tmp1 / N; if (unlikely(isinf(Sxx)) && !isinf(Sxx1) && !isinf(Sxx2)) - float_overflow_error(); + float_overflow_error(NULL); Sy = float8_pl(Sy1, Sy2); tmp2 = Sy1 / N1 - Sy2 / N2; Syy = Syy1 + Syy2 + N1 * N2 * tmp2 * tmp2 / N; if (unlikely(isinf(Syy)) && !isinf(Syy1) && !isinf(Syy2)) - float_overflow_error(); + float_overflow_error(NULL); Sxy = Sxy1 + Sxy2 + N1 * N2 * tmp1 * tmp2 / N; if (unlikely(isinf(Sxy)) && !isinf(Sxy1) && !isinf(Sxy2)) - float_overflow_error(); + float_overflow_error(NULL); } /* diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c index cf4246214a5..480d3d4a64a 100644 --- a/src/backend/utils/adt/geo_ops.c +++ b/src/backend/utils/adt/geo_ops.c @@ -86,7 +86,8 @@ static inline float8 point_sl(Point *pt1, Point *pt2); static int point_inside(Point *p, int npts, Point *plist); /* Routines for lines */ -static inline void line_construct(LINE *result, Point *pt, float8 m); +static inline bool line_construct(LINE *result, Point *pt, float8 m, + Node *escontext); static inline float8 line_sl(LINE *line); static inline float8 line_invsl(LINE *line); static bool line_interpt_line(Point *result, LINE *l1, LINE *l2); @@ -954,15 +955,17 @@ box_diagonal(PG_FUNCTION_ARGS) static bool line_decode(char *s, const char *str, LINE *line) { + ErrorSaveContext escontext = {T_ErrorSaveContext}; + /* s was already advanced over leading '{' */ - line->A = single_decode(s, &s, "line", str, NULL); - if (*s++ != DELIM) + line->A = single_decode(s, &s, "line", str, (Node *) &escontext); + if (escontext.error_occurred || *s++ != DELIM) return false; - line->B = single_decode(s, &s, "line", str, NULL); - if (*s++ != DELIM) + line->B = single_decode(s, &s, "line", str, (Node *) &escontext); + if (escontext.error_occurred || *s++ != DELIM) return false; - line->C = single_decode(s, &s, "line", str, NULL); - if (*s++ != RDELIM_L) + line->C = single_decode(s, &s, "line", str, (Node *) &escontext); + if (escontext.error_occurred || *s++ != RDELIM_L) return false; while (isspace((unsigned char) *s)) s++; @@ -975,6 +978,7 @@ Datum line_in(PG_FUNCTION_ARGS) { char *str = PG_GETARG_CSTRING(0); + Node *escontext = fcinfo->context; LINE *line = (LINE *) palloc(sizeof(LINE)); LSEG lseg; bool isopen; @@ -986,23 +990,27 @@ line_in(PG_FUNCTION_ARGS) if (*s == LDELIM_L) { if (!line_decode(s + 1, str, line)) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", "line", str))); if (FPzero(line->A) && FPzero(line->B)) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid line specification: A and B cannot both be zero"))); } else { - path_decode(s, true, 2, &lseg.p[0], &isopen, NULL, "line", str, NULL); + if (!path_decode(s, true, 2, &lseg.p[0], &isopen, NULL, "line", str, + escontext)) + PG_RETURN_NULL(); + if (point_eq_point(&lseg.p[0], &lseg.p[1])) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid line specification: must be two distinct points"))); - line_construct(line, &lseg.p[0], lseg_sl(&lseg)); + if (!line_construct(line, &lseg.p[0], lseg_sl(&lseg), escontext)) + PG_RETURN_NULL(); } PG_RETURN_LINE_P(line); @@ -1069,8 +1077,8 @@ line_send(PG_FUNCTION_ARGS) /* * Fill already-allocated LINE struct from the point and the slope */ -static inline void -line_construct(LINE *result, Point *pt, float8 m) +static inline bool +line_construct(LINE *result, Point *pt, float8 m, Node *escontext) { if (isinf(m)) { @@ -1091,11 +1099,17 @@ line_construct(LINE *result, Point *pt, float8 m) /* use "mx - y + yinter = 0" */ result->A = m; result->B = -1.0; - result->C = float8_mi(pt->y, float8_mul(m, pt->x)); + result->C = float8_mul_safe(m, pt->x, escontext); + if (SOFT_ERROR_OCCURRED(escontext)) + return false; + result->C = float8_mi_safe(pt->y, result->C, escontext); + if (SOFT_ERROR_OCCURRED(escontext)) + return false; /* on some platforms, the preceding expression tends to produce -0 */ if (result->C == 0.0) result->C = 0.0; } + return true; } /* line_construct_pp() @@ -1113,7 +1127,7 @@ line_construct_pp(PG_FUNCTION_ARGS) (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid line specification: must be two distinct points"))); - line_construct(result, pt1, point_sl(pt1, pt2)); + line_construct(result, pt1, point_sl(pt1, pt2), NULL); PG_RETURN_LINE_P(result); } @@ -2323,7 +2337,7 @@ lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2) Point interpt; LINE tmp; - line_construct(&tmp, &l2->p[0], lseg_sl(l2)); + line_construct(&tmp, &l2->p[0], lseg_sl(l2), NULL); if (!lseg_interpt_line(&interpt, l1, &tmp)) return false; @@ -2665,7 +2679,7 @@ lseg_interpt_line(Point *result, LSEG *lseg, LINE *line) * find the intersection point of two lines. If they don't have an * intersection point, we are done. */ - line_construct(&tmp, &lseg->p[0], lseg_sl(lseg)); + line_construct(&tmp, &lseg->p[0], lseg_sl(lseg), NULL); if (!line_interpt_line(&interpt, &tmp, line)) return false; @@ -2714,7 +2728,7 @@ line_closept_point(Point *result, LINE *line, Point *point) * should always find it, but that can fail in the presence of NaN * coordinates, and perhaps even from simple roundoff issues. */ - line_construct(&tmp, point, line_invsl(line)); + line_construct(&tmp, point, line_invsl(line), NULL); if (!line_interpt_line(&closept, &tmp, line)) { if (result != NULL) @@ -2761,7 +2775,7 @@ lseg_closept_point(Point *result, LSEG *lseg, Point *pt) * To find the closest point, we draw a perpendicular line from the point * to the line segment. */ - line_construct(&tmp, pt, point_invsl(&lseg->p[0], &lseg->p[1])); + line_construct(&tmp, pt, point_invsl(&lseg->p[0], &lseg->p[1]), NULL); lseg_closept_line(&closept, lseg, &tmp); if (result != NULL) @@ -5536,9 +5550,9 @@ pg_hypot(float8 x, float8 y) result = x * sqrt(1.0 + (yx * yx)); if (unlikely(isinf(result))) - float_overflow_error(); + float_overflow_error(NULL); if (unlikely(result == 0.0)) - float_underflow_error(); + float_underflow_error(NULL); return result; } diff --git a/src/include/utils/float.h b/src/include/utils/float.h index f92860b4a46..d61206d8609 100644 --- a/src/include/utils/float.h +++ b/src/include/utils/float.h @@ -37,8 +37,8 @@ extern PGDLLIMPORT int extra_float_digits; /* * Utility functions in float.c */ -extern void float_overflow_error(void) pg_attribute_noreturn(); -extern void float_underflow_error(void) pg_attribute_noreturn(); +extern void float_overflow_error(Node *escontext); +extern void float_underflow_error(Node *escontext); extern void float_zero_divide_error(void) pg_attribute_noreturn(); extern int is_infinite(float8 val); extern float8 float8in_internal(char *num, char **endptr_p, @@ -146,7 +146,7 @@ float4_pl(const float4 val1, const float4 val2) result = val1 + val2; if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2)) - float_overflow_error(); + float_overflow_error(NULL); return result; } @@ -158,7 +158,7 @@ float8_pl(const float8 val1, const float8 val2) result = val1 + val2; if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2)) - float_overflow_error(); + float_overflow_error(NULL); return result; } @@ -170,23 +170,32 @@ float4_mi(const float4 val1, const float4 val2) result = val1 - val2; if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2)) - float_overflow_error(); + float_overflow_error(NULL); return result; } static inline float8 -float8_mi(const float8 val1, const float8 val2) +float8_mi_safe(const float8 val1, const float8 val2, Node *escontext) { float8 result; result = val1 - val2; if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2)) - float_overflow_error(); + { + float_overflow_error(escontext); + return 0; + } return result; } +static inline float8 +float8_mi(const float8 val1, const float8 val2) +{ + return float8_mi_safe(val1, val2, NULL); +} + static inline float4 float4_mul(const float4 val1, const float4 val2) { @@ -194,27 +203,39 @@ float4_mul(const float4 val1, const float4 val2) result = val1 * val2; if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2)) - float_overflow_error(); + float_overflow_error(NULL); if (unlikely(result == 0.0f) && val1 != 0.0f && val2 != 0.0f) - float_underflow_error(); + float_underflow_error(NULL); return result; } static inline float8 -float8_mul(const float8 val1, const float8 val2) +float8_mul_safe(const float8 val1, const float8 val2, Node *escontext) { float8 result; result = val1 * val2; if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2)) - float_overflow_error(); + { + float_overflow_error(escontext); + return 0; + } if (unlikely(result == 0.0) && val1 != 0.0 && val2 != 0.0) - float_underflow_error(); + { + float_underflow_error(escontext); + return 0; + } return result; } +static inline float8 +float8_mul(const float8 val1, const float8 val2) +{ + return float8_mul_safe(val1, val2, NULL); +} + static inline float4 float4_div(const float4 val1, const float4 val2) { @@ -224,9 +245,9 @@ float4_div(const float4 val1, const float4 val2) float_zero_divide_error(); result = val1 / val2; if (unlikely(isinf(result)) && !isinf(val1)) - float_overflow_error(); + float_overflow_error(NULL); if (unlikely(result == 0.0f) && val1 != 0.0f && !isinf(val2)) - float_underflow_error(); + float_underflow_error(NULL); return result; } @@ -240,9 +261,9 @@ float8_div(const float8 val1, const float8 val2) float_zero_divide_error(); result = val1 / val2; if (unlikely(isinf(result)) && !isinf(val1)) - float_overflow_error(); + float_overflow_error(NULL); if (unlikely(result == 0.0) && val1 != 0.0 && !isinf(val2)) - float_underflow_error(); + float_underflow_error(NULL); return result; } diff --git a/src/test/regress/expected/line.out b/src/test/regress/expected/line.out index fe106589c6a..8145b7df56c 100644 --- a/src/test/regress/expected/line.out +++ b/src/test/regress/expected/line.out @@ -85,3 +85,40 @@ select '{nan, 1, nan}'::line = '{nan, 1, nan}'::line as true, t | f (1 row) +-- test non-error-throwing API for some core types +SELECT pg_input_is_valid('{1, 1}', 'line'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('{1, 1}', 'line'); + pg_input_error_message +---------------------------------------------- + invalid input syntax for type line: "{1, 1}" +(1 row) + +SELECT pg_input_is_valid('{0, 0, 0}', 'line'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('{0, 0, 0}', 'line'); + pg_input_error_message +--------------------------------------------------------- + invalid line specification: A and B cannot both be zero +(1 row) + +SELECT pg_input_is_valid('{1, 1, a}', 'line'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('{1, 1, a}', 'line'); + pg_input_error_message +------------------------------------------------- + invalid input syntax for type line: "{1, 1, a}" +(1 row) + diff --git a/src/test/regress/sql/line.sql b/src/test/regress/sql/line.sql index f589ffecc84..f34c6ae353f 100644 --- a/src/test/regress/sql/line.sql +++ b/src/test/regress/sql/line.sql @@ -40,3 +40,11 @@ select * from LINE_TBL; select '{nan, 1, nan}'::line = '{nan, 1, nan}'::line as true, '{nan, 1, nan}'::line = '{nan, 2, nan}'::line as false; + +-- test non-error-throwing API for some core types +SELECT pg_input_is_valid('{1, 1}', 'line'); +SELECT pg_input_error_message('{1, 1}', 'line'); +SELECT pg_input_is_valid('{0, 0, 0}', 'line'); +SELECT pg_input_error_message('{0, 0, 0}', 'line'); +SELECT pg_input_is_valid('{1, 1, a}', 'line'); +SELECT pg_input_error_message('{1, 1, a}', 'line'); -- 2.18.0
From 32908e516a2ea66f226bef543a81b0a22d9a1169 Mon Sep 17 00:00:00 2001 From: Amul Sul <amul.sul@enterprisedb.com> Date: Tue, 13 Dec 2022 14:28:19 +0530 Subject: [PATCH v1 09/14] Change gtsvectorin to allow non-throw error reporting --- src/backend/utils/adt/tsgistidx.c | 2 +- src/test/regress/expected/type_sanity.out | 12 ++++++++++++ src/test/regress/sql/type_sanity.sql | 3 +++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/backend/utils/adt/tsgistidx.c b/src/backend/utils/adt/tsgistidx.c index cabfe4d1485..13e6fcf067b 100644 --- a/src/backend/utils/adt/tsgistidx.c +++ b/src/backend/utils/adt/tsgistidx.c @@ -88,7 +88,7 @@ Datum gtsvectorin(PG_FUNCTION_ARGS) { /* There's no need to support input of gtsvectors */ - ereport(ERROR, + ereturn(fcinfo->context, (Datum) 0, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot accept a value of type %s", "gtsvector"))); diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out index 140dc6b948a..0b015b424f1 100644 --- a/src/test/regress/expected/type_sanity.out +++ b/src/test/regress/expected/type_sanity.out @@ -820,3 +820,15 @@ SELECT pg_input_error_message('1', 'pg_brin_minmax_multi_summary'); cannot accept a value of type brin_minmax_multi_summary (1 row) +SELECT pg_input_is_valid('1', 'gtsvector'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('1', 'gtsvector'); + pg_input_error_message +----------------------------------------- + cannot accept a value of type gtsvector +(1 row) + diff --git a/src/test/regress/sql/type_sanity.sql b/src/test/regress/sql/type_sanity.sql index 7c1aff8a65b..d024d950b3e 100644 --- a/src/test/regress/sql/type_sanity.sql +++ b/src/test/regress/sql/type_sanity.sql @@ -602,3 +602,6 @@ SELECT pg_input_error_message('1', 'pg_brin_bloom_summary'); SELECT pg_input_is_valid('1', 'pg_brin_minmax_multi_summary'); SELECT pg_input_error_message('1', 'pg_brin_minmax_multi_summary'); + +SELECT pg_input_is_valid('1', 'gtsvector'); +SELECT pg_input_error_message('1', 'gtsvector'); -- 2.18.0
From 7b37918f53dce1cc8cafc473f9d253590a9295ba Mon Sep 17 00:00:00 2001 From: Amul Sul <amul.sul@enterprisedb.com> Date: Tue, 13 Dec 2022 16:28:30 +0530 Subject: [PATCH v1 08/14] Change circle_in to allow non-throw error reporting --- src/backend/utils/adt/geo_ops.c | 30 +++++++++++++++----------- src/test/regress/expected/geometry.out | 25 +++++++++++++++++++++ src/test/regress/sql/geometry.sql | 6 ++++++ 3 files changed, 49 insertions(+), 12 deletions(-) diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c index 5655f2f64cd..cf4246214a5 100644 --- a/src/backend/utils/adt/geo_ops.c +++ b/src/backend/utils/adt/geo_ops.c @@ -132,7 +132,8 @@ static float8 dist_ppoly_internal(Point *pt, POLYGON *poly); /* Routines for encoding and decoding */ static float8 single_decode(char *num, char **endptr_p, - const char *type_name, const char *orig_string); + const char *type_name, const char *orig_string, + Node *escontext); static void single_encode(float8 x, StringInfo str); static bool pair_decode(char *str, float8 *x, float8 *y, char **endptr_p, const char *type_name, const char *orig_string, @@ -190,9 +191,9 @@ static char *path_encode(enum path_delim path_delim, int npts, Point *pt); static float8 single_decode(char *num, char **endptr_p, - const char *type_name, const char *orig_string) + const char *type_name, const char *orig_string, Node *escontext) { - return float8in_internal(num, endptr_p, type_name, orig_string, NULL); + return float8in_internal(num, endptr_p, type_name, orig_string, escontext); } /* single_decode() */ static void @@ -954,13 +955,13 @@ static bool line_decode(char *s, const char *str, LINE *line) { /* s was already advanced over leading '{' */ - line->A = single_decode(s, &s, "line", str); + line->A = single_decode(s, &s, "line", str, NULL); if (*s++ != DELIM) return false; - line->B = single_decode(s, &s, "line", str); + line->B = single_decode(s, &s, "line", str, NULL); if (*s++ != DELIM) return false; - line->C = single_decode(s, &s, "line", str); + line->C = single_decode(s, &s, "line", str, NULL); if (*s++ != RDELIM_L) return false; while (isspace((unsigned char) *s)) @@ -4591,6 +4592,7 @@ Datum circle_in(PG_FUNCTION_ARGS) { char *str = PG_GETARG_CSTRING(0); + Node *escontext = fcinfo->context; CIRCLE *circle = (CIRCLE *) palloc(sizeof(CIRCLE)); char *s, *cp; @@ -4612,16 +4614,20 @@ circle_in(PG_FUNCTION_ARGS) } /* pair_decode will consume parens around the pair, if any */ - pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str, - NULL); + if (!pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str, + escontext)) + PG_RETURN_NULL(); if (*s == DELIM) s++; - circle->radius = single_decode(s, &s, "circle", str); + circle->radius = single_decode(s, &s, "circle", str, escontext); + if (SOFT_ERROR_OCCURRED(escontext)) + PG_RETURN_NULL(); + /* We have to accept NaN. */ if (circle->radius < 0.0) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", "circle", str))); @@ -4636,14 +4642,14 @@ circle_in(PG_FUNCTION_ARGS) s++; } else - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", "circle", str))); } if (*s != '\0') - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", "circle", str))); diff --git a/src/test/regress/expected/geometry.out b/src/test/regress/expected/geometry.out index b50103b2165..291cacdf4fb 100644 --- a/src/test/regress/expected/geometry.out +++ b/src/test/regress/expected/geometry.out @@ -5295,3 +5295,28 @@ SELECT * FROM polygon_tbl WHERE f1 @> '((1,1),(2,2),(2,1))'::polygon ((2,0),(2,4),(0,0)) (1 row) +-- test non-error-throwing API for some core types +SELECT pg_input_is_valid('(1', 'circle'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('1,', 'circle'); + pg_input_error_message +-------------------------------------------- + invalid input syntax for type circle: "1," +(1 row) + +SELECT pg_input_is_valid('(1,2),-1', 'circle'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('(1,2),-1', 'circle'); + pg_input_error_message +-------------------------------------------------- + invalid input syntax for type circle: "(1,2),-1" +(1 row) + diff --git a/src/test/regress/sql/geometry.sql b/src/test/regress/sql/geometry.sql index 8928d04aa3f..309234b76c1 100644 --- a/src/test/regress/sql/geometry.sql +++ b/src/test/regress/sql/geometry.sql @@ -523,3 +523,9 @@ SELECT * FROM polygon_tbl WHERE f1 @> '((1,1),(2,2),(2,1))'::polygon ORDER BY (poly_center(f1))[0]; SELECT * FROM polygon_tbl WHERE f1 @> '((1,1),(2,2),(2,1))'::polygon ORDER BY (poly_center(f1))[0]; + +-- test non-error-throwing API for some core types +SELECT pg_input_is_valid('(1', 'circle'); +SELECT pg_input_error_message('1,', 'circle'); +SELECT pg_input_is_valid('(1,2),-1', 'circle'); +SELECT pg_input_error_message('(1,2),-1', 'circle'); -- 2.18.0
From 5cc0f02ea41128e9c8588ab058319e1b93aef87b Mon Sep 17 00:00:00 2001 From: Amul Sul <amul.sul@enterprisedb.com> Date: Tue, 13 Dec 2022 12:19:47 +0530 Subject: [PATCH v1 07/14] Change cidr_in and inet_in to allow non-throw error reporting --- src/backend/utils/adt/network.c | 14 +++++------ src/test/regress/expected/inet.out | 37 ++++++++++++++++++++++++++++++ src/test/regress/sql/inet.sql | 9 ++++++++ 3 files changed, 53 insertions(+), 7 deletions(-) diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c index 6d580ea78f6..42a4d9d44ec 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/test/regress/expected/inet.out b/src/test/regress/expected/inet.out index d5bf9e2aaa5..c9f466ac1d3 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/sql/inet.sql b/src/test/regress/sql/inet.sql index d2ac85bb7f0..abfcd4242f8 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'); -- 2.18.0
From d17e37b36d809074955053dc96ea6680bce6a911 Mon Sep 17 00:00:00 2001 From: Amul Sul <amul.sul@enterprisedb.com> Date: Tue, 13 Dec 2022 11:44:03 +0530 Subject: [PATCH v1 06/14] Change money_in to allow non-throw error reporting --- src/backend/utils/adt/cash.c | 11 ++++++----- src/test/regress/expected/money.out | 25 +++++++++++++++++++++++++ src/test/regress/sql/money.sql | 6 ++++++ 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/backend/utils/adt/cash.c b/src/backend/utils/adt/cash.c index f7e78fa1056..32fbad2f57d 100644 --- a/src/backend/utils/adt/cash.c +++ b/src/backend/utils/adt/cash.c @@ -96,6 +96,7 @@ Datum cash_in(PG_FUNCTION_ARGS) { char *str = PG_GETARG_CSTRING(0); + Node *escontext = fcinfo->context; Cash result; Cash value = 0; Cash dec = 0; @@ -209,7 +210,7 @@ cash_in(PG_FUNCTION_ARGS) if (pg_mul_s64_overflow(value, 10, &value) || pg_sub_s64_overflow(value, digit, &value)) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("value \"%s\" is out of range for type %s", str, "money"))); @@ -234,7 +235,7 @@ cash_in(PG_FUNCTION_ARGS) { /* remember we build the value in the negative */ if (pg_sub_s64_overflow(value, 1, &value)) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("value \"%s\" is out of range for type %s", str, "money"))); @@ -244,7 +245,7 @@ cash_in(PG_FUNCTION_ARGS) for (; dec < fpoint; dec++) { if (pg_mul_s64_overflow(value, 10, &value)) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("value \"%s\" is out of range for type %s", str, "money"))); @@ -271,7 +272,7 @@ cash_in(PG_FUNCTION_ARGS) else if (strncmp(s, csymbol, strlen(csymbol)) == 0) s += strlen(csymbol); else - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", "money", str))); @@ -284,7 +285,7 @@ cash_in(PG_FUNCTION_ARGS) if (sgn > 0) { if (value == PG_INT64_MIN) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("value \"%s\" is out of range for type %s", str, "money"))); diff --git a/src/test/regress/expected/money.out b/src/test/regress/expected/money.out index fc71a72fed3..6b6f59005d2 100644 --- a/src/test/regress/expected/money.out +++ b/src/test/regress/expected/money.out @@ -503,3 +503,28 @@ SELECT '-92233720368547758.08'::money::numeric; -92233720368547758.08 (1 row) +-- test non-error-throwing API for some core types +SELECT pg_input_is_valid('\x0001', 'money'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('\x0001', 'money'); + pg_input_error_message +----------------------------------------------- + invalid input syntax for type money: "\x0001" +(1 row) + +SELECT pg_input_is_valid('992233720368547758.07', 'money'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('192233720368547758.07', 'money'); + pg_input_error_message +-------------------------------------------------------------- + value "192233720368547758.07" is out of range for type money +(1 row) + diff --git a/src/test/regress/sql/money.sql b/src/test/regress/sql/money.sql index 5e746286c90..39886eb8266 100644 --- a/src/test/regress/sql/money.sql +++ b/src/test/regress/sql/money.sql @@ -129,3 +129,9 @@ SELECT '12345678901234567'::money::numeric; SELECT '-12345678901234567'::money::numeric; SELECT '92233720368547758.07'::money::numeric; SELECT '-92233720368547758.08'::money::numeric; + +-- test non-error-throwing API for some core types +SELECT pg_input_is_valid('\x0001', 'money'); +SELECT pg_input_error_message('\x0001', 'money'); +SELECT pg_input_is_valid('992233720368547758.07', 'money'); +SELECT pg_input_error_message('192233720368547758.07', 'money'); -- 2.18.0
From 139ef29a7074fa0aa2df472134f67c3793f846e4 Mon Sep 17 00:00:00 2001 From: Amul Sul <amul.sul@enterprisedb.com> Date: Tue, 13 Dec 2022 10:59:32 +0530 Subject: [PATCH v1 05/14] Change brin_minmax_multi_summary_in to allow non-throw error reporting --- src/backend/access/brin/brin_minmax_multi.c | 2 +- src/test/regress/expected/type_sanity.out | 12 ++++++++++++ src/test/regress/sql/type_sanity.sql | 3 +++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/backend/access/brin/brin_minmax_multi.c b/src/backend/access/brin/brin_minmax_multi.c index 9a0bcf6698d..99ea7910c79 100644 --- a/src/backend/access/brin/brin_minmax_multi.c +++ b/src/backend/access/brin/brin_minmax_multi.c @@ -3003,7 +3003,7 @@ brin_minmax_multi_summary_in(PG_FUNCTION_ARGS) * brin_minmax_multi_summary stores the data in binary form and parsing * text input is not needed, so disallow this. */ - ereport(ERROR, + ereturn(fcinfo->context, (Datum) 0, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot accept a value of type %s", "brin_minmax_multi_summary"))); diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out index 95aa04e69ef..140dc6b948a 100644 --- a/src/test/regress/expected/type_sanity.out +++ b/src/test/regress/expected/type_sanity.out @@ -808,3 +808,15 @@ SELECT pg_input_error_message('1', 'pg_brin_bloom_summary'); cannot accept a value of type pg_brin_bloom_summary (1 row) +SELECT pg_input_is_valid('1', 'pg_brin_minmax_multi_summary'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('1', 'pg_brin_minmax_multi_summary'); + pg_input_error_message +--------------------------------------------------------- + cannot accept a value of type brin_minmax_multi_summary +(1 row) + diff --git a/src/test/regress/sql/type_sanity.sql b/src/test/regress/sql/type_sanity.sql index a75f6abfd27..7c1aff8a65b 100644 --- a/src/test/regress/sql/type_sanity.sql +++ b/src/test/regress/sql/type_sanity.sql @@ -599,3 +599,6 @@ SELECT pg_input_error_message('pg_monitor=rY', 'aclitem'); SELECT pg_input_is_valid('1', 'pg_brin_bloom_summary'); SELECT pg_input_error_message('1', 'pg_brin_bloom_summary'); + +SELECT pg_input_is_valid('1', 'pg_brin_minmax_multi_summary'); +SELECT pg_input_error_message('1', 'pg_brin_minmax_multi_summary'); -- 2.18.0
From 4cbdd4075c9b50820da4a954f6d2b806a2997e07 Mon Sep 17 00:00:00 2001 From: Amul Sul <amul.sul@enterprisedb.com> Date: Tue, 13 Dec 2022 10:52:29 +0530 Subject: [PATCH v1 04/14] Change brin_bloom_summary_in to allow non-throw error reporting --- src/backend/access/brin/brin_bloom.c | 2 +- src/test/regress/expected/type_sanity.out | 12 ++++++++++++ src/test/regress/sql/type_sanity.sql | 3 +++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/backend/access/brin/brin_bloom.c b/src/backend/access/brin/brin_bloom.c index 6b0af7267d5..883802cb5d9 100644 --- a/src/backend/access/brin/brin_bloom.c +++ b/src/backend/access/brin/brin_bloom.c @@ -745,7 +745,7 @@ brin_bloom_summary_in(PG_FUNCTION_ARGS) * brin_bloom_summary stores the data in binary form and parsing text * input is not needed, so disallow this. */ - ereport(ERROR, + ereturn(fcinfo->context, (Datum) 0, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot accept a value of type %s", "pg_brin_bloom_summary"))); diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out index b2bc0205a76..95aa04e69ef 100644 --- a/src/test/regress/expected/type_sanity.out +++ b/src/test/regress/expected/type_sanity.out @@ -796,3 +796,15 @@ SELECT pg_input_error_message('pg_monitor=rY', 'aclitem'); invalid mode character: must be one of "arwdDxtXUCTcsAvz" (1 row) +SELECT pg_input_is_valid('1', 'pg_brin_bloom_summary'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('1', 'pg_brin_bloom_summary'); + pg_input_error_message +----------------------------------------------------- + cannot accept a value of type pg_brin_bloom_summary +(1 row) + diff --git a/src/test/regress/sql/type_sanity.sql b/src/test/regress/sql/type_sanity.sql index 080ac15b6c8..a75f6abfd27 100644 --- a/src/test/regress/sql/type_sanity.sql +++ b/src/test/regress/sql/type_sanity.sql @@ -596,3 +596,6 @@ SELECT pg_input_is_valid('pg_monitor=r/', 'aclitem'); SELECT pg_input_error_message('pg_monitor=r/', 'aclitem'); SELECT pg_input_is_valid('pg_monitor=rY', 'aclitem'); SELECT pg_input_error_message('pg_monitor=rY', 'aclitem'); + +SELECT pg_input_is_valid('1', 'pg_brin_bloom_summary'); +SELECT pg_input_error_message('1', 'pg_brin_bloom_summary'); -- 2.18.0
From 92fe9e755d3f8e2ae49829f4c20f399a58652c6c Mon Sep 17 00:00:00 2001 From: Amul Sul <amul.sul@enterprisedb.com> Date: Tue, 13 Dec 2022 16:21:32 +0530 Subject: [PATCH v1 03/14] Change box_in to allow non-throw error reporting --- src/backend/utils/adt/geo_ops.c | 67 ++++++++++++++++++++----------- src/test/regress/expected/box.out | 25 ++++++++++++ src/test/regress/sql/box.sql | 6 +++ 3 files changed, 74 insertions(+), 24 deletions(-) diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c index 721ce6634f8..5655f2f64cd 100644 --- a/src/backend/utils/adt/geo_ops.c +++ b/src/backend/utils/adt/geo_ops.c @@ -31,6 +31,7 @@ #include "libpq/pqformat.h" #include "miscadmin.h" +#include "nodes/miscnodes.h" #include "utils/float.h" #include "utils/fmgrprotos.h" #include "utils/geo_decls.h" @@ -133,13 +134,15 @@ static float8 dist_ppoly_internal(Point *pt, POLYGON *poly); static float8 single_decode(char *num, char **endptr_p, const char *type_name, const char *orig_string); static void single_encode(float8 x, StringInfo str); -static void pair_decode(char *str, float8 *x, float8 *y, char **endptr_p, - const char *type_name, const char *orig_string); +static bool pair_decode(char *str, float8 *x, float8 *y, char **endptr_p, + const char *type_name, const char *orig_string, + Node *escontext); static void pair_encode(float8 x, float8 y, StringInfo str); static int pair_count(char *s, char delim); -static void path_decode(char *str, bool opentype, int npts, Point *p, +static bool path_decode(char *str, bool opentype, int npts, Point *p, bool *isopen, char **endptr_p, - const char *type_name, const char *orig_string); + const char *type_name, const char *orig_string, + Node *escontext); static char *path_encode(enum path_delim path_delim, int npts, Point *pt); @@ -201,9 +204,10 @@ single_encode(float8 x, StringInfo str) pfree(xstr); } /* single_encode() */ -static void +static bool pair_decode(char *str, float8 *x, float8 *y, char **endptr_p, - const char *type_name, const char *orig_string) + const char *type_name, const char *orig_string, + Node *escontext) { bool has_delim; @@ -212,20 +216,24 @@ pair_decode(char *str, float8 *x, float8 *y, char **endptr_p, if ((has_delim = (*str == LDELIM))) str++; - *x = float8in_internal(str, &str, type_name, orig_string, NULL); + *x = float8in_internal(str, &str, type_name, orig_string, escontext); + if (SOFT_ERROR_OCCURRED(escontext)) + return false; if (*str++ != DELIM) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", type_name, orig_string))); - *y = float8in_internal(str, &str, type_name, orig_string, NULL); + *y = float8in_internal(str, &str, type_name, orig_string, escontext); + if (SOFT_ERROR_OCCURRED(escontext)) + return false; if (has_delim) { if (*str++ != RDELIM) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", type_name, orig_string))); @@ -237,10 +245,11 @@ pair_decode(char *str, float8 *x, float8 *y, char **endptr_p, if (endptr_p) *endptr_p = str; else if (*str != '\0') - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", type_name, orig_string))); + return true; } static void @@ -254,10 +263,11 @@ pair_encode(float8 x, float8 y, StringInfo str) pfree(ystr); } -static void +static bool path_decode(char *str, bool opentype, int npts, Point *p, bool *isopen, char **endptr_p, - const char *type_name, const char *orig_string) + const char *type_name, const char *orig_string, + Node *escontext) { int depth = 0; char *cp; @@ -269,7 +279,7 @@ path_decode(char *str, bool opentype, int npts, Point *p, { /* no open delimiter allowed? */ if (!opentype) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", type_name, orig_string))); @@ -295,7 +305,9 @@ path_decode(char *str, bool opentype, int npts, Point *p, for (i = 0; i < npts; i++) { - pair_decode(str, &(p->x), &(p->y), &str, type_name, orig_string); + if (!pair_decode(str, &(p->x), &(p->y), &str, type_name, orig_string, + escontext)) + return false; if (*str == DELIM) str++; p++; @@ -311,7 +323,7 @@ path_decode(char *str, bool opentype, int npts, Point *p, str++; } else - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", type_name, orig_string))); @@ -321,10 +333,11 @@ path_decode(char *str, bool opentype, int npts, Point *p, if (endptr_p) *endptr_p = str; else if (*str != '\0') - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", type_name, orig_string))); + return true; } /* path_decode() */ static char * @@ -413,12 +426,15 @@ Datum box_in(PG_FUNCTION_ARGS) { char *str = PG_GETARG_CSTRING(0); + Node *escontext = fcinfo->context; BOX *box = (BOX *) palloc(sizeof(BOX)); bool isopen; float8 x, y; - path_decode(str, false, 2, &(box->high), &isopen, NULL, "box", str); + if (!path_decode(str, false, 2, &(box->high), &isopen, NULL, "box", str, + escontext)) + PG_RETURN_NULL(); /* reorder corners if necessary... */ if (float8_lt(box->high.x, box->low.x)) @@ -980,7 +996,7 @@ line_in(PG_FUNCTION_ARGS) } else { - path_decode(s, true, 2, &lseg.p[0], &isopen, NULL, "line", str); + path_decode(s, true, 2, &lseg.p[0], &isopen, NULL, "line", str, NULL); if (point_eq_point(&lseg.p[0], &lseg.p[1])) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), @@ -1414,7 +1430,7 @@ path_in(PG_FUNCTION_ARGS) SET_VARSIZE(path, size); path->npts = npts; - path_decode(s, true, npts, &(path->p[0]), &isopen, &s, "path", str); + path_decode(s, true, npts, &(path->p[0]), &isopen, &s, "path", str, NULL); if (depth >= 1) { @@ -1803,7 +1819,7 @@ point_in(PG_FUNCTION_ARGS) char *str = PG_GETARG_CSTRING(0); Point *point = (Point *) palloc(sizeof(Point)); - pair_decode(str, &point->x, &point->y, NULL, "point", str); + pair_decode(str, &point->x, &point->y, NULL, "point", str, NULL); PG_RETURN_POINT_P(point); } @@ -2037,7 +2053,8 @@ lseg_in(PG_FUNCTION_ARGS) LSEG *lseg = (LSEG *) palloc(sizeof(LSEG)); bool isopen; - path_decode(str, true, 2, &lseg->p[0], &isopen, NULL, "lseg", str); + path_decode(str, true, 2, &lseg->p[0], &isopen, NULL, "lseg", str, + NULL); PG_RETURN_LSEG_P(lseg); } @@ -3406,7 +3423,8 @@ poly_in(PG_FUNCTION_ARGS) SET_VARSIZE(poly, size); poly->npts = npts; - path_decode(str, false, npts, &(poly->p[0]), &isopen, NULL, "polygon", str); + path_decode(str, false, npts, &(poly->p[0]), &isopen, NULL, "polygon", str, + NULL); make_bound_box(poly); @@ -4594,7 +4612,8 @@ circle_in(PG_FUNCTION_ARGS) } /* pair_decode will consume parens around the pair, if any */ - pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str); + pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str, + NULL); if (*s == DELIM) s++; diff --git a/src/test/regress/expected/box.out b/src/test/regress/expected/box.out index 6bf4d0bdc6d..0d70194def5 100644 --- a/src/test/regress/expected/box.out +++ b/src/test/regress/expected/box.out @@ -639,3 +639,28 @@ WHERE seq.id IS NULL OR idx.id IS NULL; RESET enable_seqscan; RESET enable_indexscan; RESET enable_bitmapscan; +-- test non-error-throwing API for some core types +SELECT pg_input_is_valid('200', 'box'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('200', 'box'); + pg_input_error_message +------------------------------------------ + invalid input syntax for type box: "200" +(1 row) + +SELECT pg_input_is_valid('((200,300),(500, xyz))', 'box'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('((200,300),(500, xyz))', 'box'); + pg_input_error_message +------------------------------------------------------------- + invalid input syntax for type box: "((200,300),(500, xyz))" +(1 row) + diff --git a/src/test/regress/sql/box.sql b/src/test/regress/sql/box.sql index ceae58fc02f..02e100391b4 100644 --- a/src/test/regress/sql/box.sql +++ b/src/test/regress/sql/box.sql @@ -281,3 +281,9 @@ WHERE seq.id IS NULL OR idx.id IS NULL; RESET enable_seqscan; RESET enable_indexscan; RESET enable_bitmapscan; + +-- test non-error-throwing API for some core types +SELECT pg_input_is_valid('200', 'box'); +SELECT pg_input_error_message('200', 'box'); +SELECT pg_input_is_valid('((200,300),(500, xyz))', 'box'); +SELECT pg_input_error_message('((200,300),(500, xyz))', 'box'); -- 2.18.0
From 29c236c6552784229274e3803c2b05a20200a952 Mon Sep 17 00:00:00 2001 From: Amul Sul <amul.sul@enterprisedb.com> Date: Mon, 12 Dec 2022 12:46:54 +0530 Subject: [PATCH v1 02/14] Change bit_in to allow non-throw error reporting --- src/backend/utils/adt/varbit.c | 9 ++++---- src/test/regress/expected/bit.out | 37 +++++++++++++++++++++++++++++++ src/test/regress/sql/bit.sql | 8 +++++++ 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c index 73e41e0808f..7519d6b6a35 100644 --- a/src/backend/utils/adt/varbit.c +++ b/src/backend/utils/adt/varbit.c @@ -152,6 +152,7 @@ bit_in(PG_FUNCTION_ARGS) 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 +194,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 +208,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 +230,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 +255,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))); diff --git a/src/test/regress/expected/bit.out b/src/test/regress/expected/bit.out index a5aab9c0e35..059fdf66156 100644 --- a/src/test/regress/expected/bit.out +++ b/src/test/regress/expected/bit.out @@ -746,3 +746,40 @@ 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) + diff --git a/src/test/regress/sql/bit.sql b/src/test/regress/sql/bit.sql index 0a424e796b9..93100833c24 100644 --- a/src/test/regress/sql/bit.sql +++ b/src/test/regress/sql/bit.sql @@ -229,3 +229,11 @@ 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)'); -- 2.18.0
From 0e56a01c00737bab39f3b0a192767e9f3110ecda Mon Sep 17 00:00:00 2001 From: Amul Sul <amul.sul@enterprisedb.com> Date: Mon, 12 Dec 2022 11:18:23 +0530 Subject: [PATCH v1 01/14] Change aclitemin to allow non-throw error reporting --- src/backend/utils/adt/acl.c | 23 +++++++++++++-------- src/test/regress/expected/type_sanity.out | 25 +++++++++++++++++++++++ src/test/regress/sql/type_sanity.sql | 6 ++++++ 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index ed1b6a41cfb..8d0aa603aea 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -85,7 +85,7 @@ static const char *getid(const char *s, char *n); static void putid(char *p, const char *s); static Acl *allocacl(int n); static void check_acl(const Acl *acl); -static const char *aclparse(const char *s, AclItem *aip); +static const char *aclparse(const char *s, AclItem *aip, Node *escontext); static bool aclitem_match(const AclItem *a1, const AclItem *a2); static int aclitemComparator(const void *arg1, const void *arg2); static void check_circularity(const Acl *old_acl, const AclItem *mod_aip, @@ -238,7 +238,7 @@ putid(char *p, const char *s) * UID/GID, id type identifier and mode type values. */ static const char * -aclparse(const char *s, AclItem *aip) +aclparse(const char *s, AclItem *aip, Node *escontext) { AclMode privs, goption, @@ -253,20 +253,20 @@ aclparse(const char *s, AclItem *aip) { /* we just read a keyword, not a name */ if (strcmp(name, "group") != 0 && strcmp(name, "user") != 0) - ereport(ERROR, + ereturn(escontext, NULL, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("unrecognized key word: \"%s\"", name), errhint("ACL key word must be \"group\" or \"user\"."))); s = getid(s, name); /* move s to the name beyond the keyword */ if (name[0] == '\0') - ereport(ERROR, + ereturn(escontext, NULL, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("missing name"), errhint("A name must follow the \"group\" or \"user\" key word."))); } if (*s != '=') - ereport(ERROR, + ereturn(escontext, NULL, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("missing \"=\" sign"))); @@ -331,7 +331,7 @@ aclparse(const char *s, AclItem *aip) read = 0; break; default: - ereport(ERROR, + ereturn(escontext, NULL, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid mode character: must be one of \"%s\"", ACL_ALL_RIGHTS_STR))); @@ -353,7 +353,7 @@ aclparse(const char *s, AclItem *aip) { s = getid(s + 1, name2); if (name2[0] == '\0') - ereport(ERROR, + ereturn(escontext, NULL, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("a name must follow the \"/\" sign"))); aip->ai_grantor = get_role_oid(name2, false); @@ -572,14 +572,19 @@ Datum aclitemin(PG_FUNCTION_ARGS) { const char *s = PG_GETARG_CSTRING(0); + Node *escontext = fcinfo->context; AclItem *aip; aip = (AclItem *) palloc(sizeof(AclItem)); - s = aclparse(s, aip); + + /* aclparse() returns NULL in case of soft-errors */ + if ((s = aclparse(s, aip, escontext)) == NULL) + PG_RETURN_NULL(); + while (isspace((unsigned char) *s)) ++s; if (*s) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("extra garbage at the end of the ACL specification"))); diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out index d3ac08c9ee3..b2bc0205a76 100644 --- a/src/test/regress/expected/type_sanity.out +++ b/src/test/regress/expected/type_sanity.out @@ -771,3 +771,28 @@ SELECT oid, typname, typtype, typelem, typarray -----+---------+---------+---------+---------- (0 rows) +-- test non-error-throwing API for some core types +SELECT pg_input_is_valid('pg_monitor=r/', 'aclitem'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('pg_monitor=r/', 'aclitem'); + pg_input_error_message +--------------------------------- + a name must follow the "/" sign +(1 row) + +SELECT pg_input_is_valid('pg_monitor=rY', 'aclitem'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('pg_monitor=rY', 'aclitem'); + pg_input_error_message +----------------------------------------------------------- + invalid mode character: must be one of "arwdDxtXUCTcsAvz" +(1 row) + diff --git a/src/test/regress/sql/type_sanity.sql b/src/test/regress/sql/type_sanity.sql index 5edc1f1f6ed..080ac15b6c8 100644 --- a/src/test/regress/sql/type_sanity.sql +++ b/src/test/regress/sql/type_sanity.sql @@ -590,3 +590,9 @@ SELECT oid, typname, typtype, typelem, typarray WHERE a.atttypid=t.oid AND a.attnum > 0 AND a.attrelid='tab_core_types'::regclass); + +-- test non-error-throwing API for some core types +SELECT pg_input_is_valid('pg_monitor=r/', 'aclitem'); +SELECT pg_input_error_message('pg_monitor=r/', 'aclitem'); +SELECT pg_input_is_valid('pg_monitor=rY', 'aclitem'); +SELECT pg_input_error_message('pg_monitor=rY', 'aclitem'); -- 2.18.0