On 2022-12-18 Su 09:42, Andrew Dunstan wrote:
> On 2022-12-14 We 17:37, Tom Lane wrote:
>> Andrew Dunstan <and...@dunslane.net> writes:
>>> Thanks, I have been looking at jsonpath, but I'm not quite sure how to
>>> get the escontext argument to the yyerror calls in jsonath_scan.l. Maybe
>>> I need to specify a lex-param setting?
>> You want a parse-param option in jsonpath_gram.y, I think; adding that
>> will persuade Bison to change the signatures of relevant functions.
>> Compare the mods I made in contrib/cube in ccff2d20e.
>>
>>                      
>
> Yeah, I started there, but it's substantially more complex - unlike cube
> the jsonpath scanner calls the error routines as well as the parser.
>
>
> Anyway, here's a patch.
>
>

And here's another for contrib/seg

I'm planning to commit these two in the next day or so.


cheers


andew

--
Andrew Dunstan
EDB: https://www.enterprisedb.com
From d7a0d93ee90ccc61b7179f236dcd1a824f30c8e6 Mon Sep 17 00:00:00 2001
From: Andrew Dunstan <and...@dunslane.net>
Date: Wed, 21 Dec 2022 18:14:03 -0500
Subject: [PATCH] Provide error safety for contrib/seg's input function

---
 contrib/seg/expected/seg.out | 20 ++++++++++++++++++++
 contrib/seg/seg.c            |  4 ++--
 contrib/seg/segdata.h        |  5 +++--
 contrib/seg/segparse.y       | 34 +++++++++++++++++++++++-----------
 contrib/seg/segscan.l        | 10 +++++++---
 contrib/seg/sql/seg.sql      | 13 +++++++++++++
 6 files changed, 68 insertions(+), 18 deletions(-)

diff --git a/contrib/seg/expected/seg.out b/contrib/seg/expected/seg.out
index 2320464dd4..7a06113ed8 100644
--- a/contrib/seg/expected/seg.out
+++ b/contrib/seg/expected/seg.out
@@ -1273,3 +1273,23 @@ FROM test_seg WHERE s @> '11.2..11.3' OR s IS NULL ORDER BY s;
            |            |          
 (144 rows)
 
+-- test non error throwing API
+SELECT str as seg,
+       pg_input_is_valid(str,'seg') as ok,
+       pg_input_error_message(str,'seg') as errmsg
+FROM unnest(ARRAY['-1 .. 1'::text,
+                  '100(+-)1',
+                  '',
+                  'ABC',
+                  '1 e7',
+                  '1e700']) str;
+   seg    | ok |                errmsg                 
+----------+----+---------------------------------------
+ -1 .. 1  | t  | 
+ 100(+-)1 | t  | 
+          | f  | bad seg representation
+ ABC      | f  | bad seg representation
+ 1 e7     | f  | bad seg representation
+ 1e700    | f  | "1e700" is out of range for type real
+(6 rows)
+
diff --git a/contrib/seg/seg.c b/contrib/seg/seg.c
index a7effc1b19..7f9fc24eb4 100644
--- a/contrib/seg/seg.c
+++ b/contrib/seg/seg.c
@@ -108,8 +108,8 @@ seg_in(PG_FUNCTION_ARGS)
 
 	seg_scanner_init(str);
 
-	if (seg_yyparse(result) != 0)
-		seg_yyerror(result, "bogus input");
+	if (seg_yyparse(result, fcinfo->context) != 0)
+		seg_yyerror(result, fcinfo->context, "bogus input");
 
 	seg_scanner_finish();
 
diff --git a/contrib/seg/segdata.h b/contrib/seg/segdata.h
index f4eafc865d..3d6e3e3f24 100644
--- a/contrib/seg/segdata.h
+++ b/contrib/seg/segdata.h
@@ -16,9 +16,10 @@ extern int	significant_digits(const char *s);
 
 /* in segscan.l */
 extern int	seg_yylex(void);
-extern void seg_yyerror(SEG *result, const char *message) pg_attribute_noreturn();
+extern void seg_yyerror(SEG *result, struct Node *escontext,
+						const char *message);
 extern void seg_scanner_init(const char *str);
 extern void seg_scanner_finish(void);
 
 /* in segparse.y */
-extern int	seg_yyparse(SEG *result);
+extern int	seg_yyparse(SEG *result, struct Node *escontext);
diff --git a/contrib/seg/segparse.y b/contrib/seg/segparse.y
index 0156c3e027..19f1dba50f 100644
--- a/contrib/seg/segparse.y
+++ b/contrib/seg/segparse.y
@@ -7,7 +7,9 @@
 #include <math.h>
 
 #include "fmgr.h"
+#include "nodes/miscnodes.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 
 #include "segdata.h"
 
@@ -19,7 +21,7 @@
 #define YYMALLOC palloc
 #define YYFREE   pfree
 
-static float seg_atof(const char *value);
+static bool seg_atof(char *value, float *result, struct Node *escontext);
 
 static int sig_digits(const char *value);
 
@@ -35,6 +37,7 @@ static char strbuf[25] = {
 
 /* BISON Declarations */
 %parse-param {SEG *result}
+%parse-param {struct Node *escontext}
 %expect 0
 %name-prefix="seg_yy"
 
@@ -77,7 +80,7 @@ range: boundary PLUMIN deviation
 		result->lower = $1.val;
 		result->upper = $3.val;
 		if ( result->lower > result->upper ) {
-			ereport(ERROR,
+			errsave(escontext,
 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 					 errmsg("swapped boundaries: %g is greater than %g",
 							result->lower, result->upper)));
@@ -121,7 +124,10 @@ range: boundary PLUMIN deviation
 boundary: SEGFLOAT
 	{
 		/* temp variable avoids a gcc 3.3.x bug on Sparc64 */
-		float		val = seg_atof($1);
+		float		val;
+
+		if (!seg_atof($1, &val, escontext))
+			YYABORT;
 
 		$$.ext = '\0';
 		$$.sigd = sig_digits($1);
@@ -130,7 +136,10 @@ boundary: SEGFLOAT
 	| EXTENSION SEGFLOAT
 	{
 		/* temp variable avoids a gcc 3.3.x bug on Sparc64 */
-		float		val = seg_atof($2);
+		float		val;
+
+		if (!seg_atof($2, &val, escontext))
+			YYABORT;
 
 		$$.ext = $1[0];
 		$$.sigd = sig_digits($2);
@@ -141,7 +150,10 @@ boundary: SEGFLOAT
 deviation: SEGFLOAT
 	{
 		/* temp variable avoids a gcc 3.3.x bug on Sparc64 */
-		float		val = seg_atof($1);
+		float		val;
+
+		if (!seg_atof($1, &val, escontext))
+			YYABORT;
 
 		$$.ext = '\0';
 		$$.sigd = sig_digits($1);
@@ -152,13 +164,13 @@ deviation: SEGFLOAT
 %%
 
 
-static float
-seg_atof(const char *value)
+static bool
+seg_atof(char *value, float *result, struct Node *escontext)
 {
-	Datum		datum;
-
-	datum = DirectFunctionCall1(float4in, CStringGetDatum(value));
-	return DatumGetFloat4(datum);
+	*result = float4in_internal(value, NULL, "real", value, escontext);
+	if (SOFT_ERROR_OCCURRED(escontext))
+		return false;
+	return true;
 }
 
 static int
diff --git a/contrib/seg/segscan.l b/contrib/seg/segscan.l
index 4744fd5e9e..2d15088ce7 100644
--- a/contrib/seg/segscan.l
+++ b/contrib/seg/segscan.l
@@ -4,6 +4,8 @@
  */
 #include "postgres.h"
 
+#include "nodes/miscnodes.h"
+
 /*
  * NB: include segparse.h only AFTER including segdata.h, because segdata.h
  * contains the definition for SEG.
@@ -65,11 +67,13 @@ float        ({integer}|{real})([eE]{integer})?
 /* LCOV_EXCL_STOP */
 
 void
-seg_yyerror(SEG *result, const char *message)
+seg_yyerror(SEG *result, struct Node *escontext, const char *message)
 {
+	if (SOFT_ERROR_OCCURRED(escontext))
+		return;
 	if (*yytext == YY_END_OF_BUFFER_CHAR)
 	{
-		ereport(ERROR,
+		errsave(escontext,
 				(errcode(ERRCODE_SYNTAX_ERROR),
 				 errmsg("bad seg representation"),
 				 /* translator: %s is typically "syntax error" */
@@ -77,7 +81,7 @@ seg_yyerror(SEG *result, const char *message)
 	}
 	else
 	{
-		ereport(ERROR,
+		errsave(escontext,
 				(errcode(ERRCODE_SYNTAX_ERROR),
 				 errmsg("bad seg representation"),
 				 /* translator: first %s is typically "syntax error" */
diff --git a/contrib/seg/sql/seg.sql b/contrib/seg/sql/seg.sql
index a027d4de97..b9a5d05d09 100644
--- a/contrib/seg/sql/seg.sql
+++ b/contrib/seg/sql/seg.sql
@@ -238,3 +238,16 @@ SELECT * FROM test_seg WHERE s @> '11..11.3' GROUP BY s;
 -- Test functions
 SELECT seg_lower(s), seg_center(s), seg_upper(s)
 FROM test_seg WHERE s @> '11.2..11.3' OR s IS NULL ORDER BY s;
+
+
+-- test non error throwing API
+
+SELECT str as seg,
+       pg_input_is_valid(str,'seg') as ok,
+       pg_input_error_message(str,'seg') as errmsg
+FROM unnest(ARRAY['-1 .. 1'::text,
+                  '100(+-)1',
+                  '',
+                  'ABC',
+                  '1 e7',
+                  '1e700']) str;
-- 
2.34.1

Reply via email to