Convert contrib/seg's input function to report errors softly
authorAndrew Dunstan <andrew@dunslane.net>
Fri, 23 Dec 2022 14:17:24 +0000 (09:17 -0500)
committerAndrew Dunstan <andrew@dunslane.net>
Fri, 23 Dec 2022 14:17:24 +0000 (09:17 -0500)
Reviewed by Tom Lane

Discussion: https://postgr.es/m/a8dc5700-c341-3ba8-0507-cc09881e6200@dunslane.net

contrib/seg/expected/seg.out
contrib/seg/seg.c
contrib/seg/segdata.h
contrib/seg/segparse.y
contrib/seg/segscan.l
contrib/seg/sql/seg.sql

index 2320464dd4712555d6971355e9a3d7e264e4cc0a..7a06113ed821e3b8e2e56dd00f71714b7803de06 100644 (file)
@@ -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)
+
index a7effc1b190c44eca50a1a7a1baba1516dbe9ff7..7f9fc24eb4b60add583d6237e1dd575b17f58293 100644 (file)
@@ -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();
 
index f4eafc865d94df3a6f864f4efe69307cafa92601..3d6e3e3f24506979f5c40f0933abc3e5c1808eb9 100644 (file)
@@ -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);
index 0156c3e02748bddf847ce1203afa0c336a48fc51..bf759dbbd84df435843d94d32754605c9ec23e62 100644 (file)
@@ -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, "seg", value, escontext);
+   if (SOFT_ERROR_OCCURRED(escontext))
+       return false;
+   return true;
 }
 
 static int
index 4744fd5e9e84592520b374a400da71ca1b4f90a0..a1e9e9937ef3232777a084242ccda987a6f32e64 100644 (file)
@@ -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,15 @@ 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 we already reported an error, don't overwrite it */
+   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 +83,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" */
index a027d4de97ed7613c3935c56ba9f5dae70f41b79..b9a5d05d09ff077eb8996e3c912e882fcdb5e0f6 100644 (file)
@@ -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;