summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Dunstan <andrew@dunslane.net>2022-12-23 09:17:24 -0500
committerAndrew Dunstan <andrew@dunslane.net>2022-12-23 09:17:24 -0500
commit878ce16056c087e2dcd7cc31cd7e4700f407a770 (patch)
treea70260dcd16c84ea40222a753105998f867b486b
parent7a310338f4dd3195376477d502e93fba5f165769 (diff)
downloadpostgresql-878ce16056c087e2dcd7cc31cd7e4700f407a770.tar.gz
Convert contrib/seg's input function to report errors softly
Reviewed by Tom Lane Discussion: https://postgr.es/m/a8dc5700-c341-3ba8-0507-cc09881e6200@dunslane.net
-rw-r--r--contrib/seg/expected/seg.out20
-rw-r--r--contrib/seg/seg.c4
-rw-r--r--contrib/seg/segdata.h5
-rw-r--r--contrib/seg/segparse.y34
-rw-r--r--contrib/seg/segscan.l12
-rw-r--r--contrib/seg/sql/seg.sql13
6 files changed, 70 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..bf759dbbd8 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, "seg", 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..a1e9e9937e 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,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" */
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;