Convert a few datatype input functions to use "soft" error reporting.
This patch converts the input functions for bool, int2, int4, int8, float4, float8, numeric, and contrib/cube to the new soft-error style. array_in and record_in are also converted. There's lots more to do, but this is enough to provide proof-of-concept that the soft-error API is usable, as well as reference examples for how to convert input functions. This patch is mostly by me, but it owes very substantial debt to earlier work by Nikita Glukhov, Andrew Dunstan, and Amul Sul. Thanks to Andres Freund for review. Discussion: https://postgr.es/m/3bbbb0df-7382-bf87-9737-340ba096e034@postgrespro.ru
This commit is contained in:
parent
1939d26282
commit
ccff2d20ed
@ -123,8 +123,9 @@ cube_in(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
cube_scanner_init(str, &scanbuflen);
|
cube_scanner_init(str, &scanbuflen);
|
||||||
|
|
||||||
cube_yyparse(&result, scanbuflen);
|
cube_yyparse(&result, scanbuflen, fcinfo->context);
|
||||||
|
|
||||||
|
/* We might as well run this even on failure. */
|
||||||
cube_scanner_finish();
|
cube_scanner_finish();
|
||||||
|
|
||||||
PG_RETURN_NDBOX_P(result);
|
PG_RETURN_NDBOX_P(result);
|
||||||
|
@ -61,9 +61,12 @@ typedef struct NDBOX
|
|||||||
|
|
||||||
/* in cubescan.l */
|
/* in cubescan.l */
|
||||||
extern int cube_yylex(void);
|
extern int cube_yylex(void);
|
||||||
extern void cube_yyerror(NDBOX **result, Size scanbuflen, const char *message) pg_attribute_noreturn();
|
extern void cube_yyerror(NDBOX **result, Size scanbuflen,
|
||||||
|
struct Node *escontext,
|
||||||
|
const char *message);
|
||||||
extern void cube_scanner_init(const char *str, Size *scanbuflen);
|
extern void cube_scanner_init(const char *str, Size *scanbuflen);
|
||||||
extern void cube_scanner_finish(void);
|
extern void cube_scanner_finish(void);
|
||||||
|
|
||||||
/* in cubeparse.y */
|
/* in cubeparse.y */
|
||||||
extern int cube_yyparse(NDBOX **result, Size scanbuflen);
|
extern int cube_yyparse(NDBOX **result, Size scanbuflen,
|
||||||
|
struct Node *escontext);
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "cubedata.h"
|
#include "cubedata.h"
|
||||||
|
#include "nodes/miscnodes.h"
|
||||||
#include "utils/float.h"
|
#include "utils/float.h"
|
||||||
|
|
||||||
/* All grammar constructs return strings */
|
/* All grammar constructs return strings */
|
||||||
@ -21,14 +22,17 @@
|
|||||||
#define YYFREE pfree
|
#define YYFREE pfree
|
||||||
|
|
||||||
static int item_count(const char *s, char delim);
|
static int item_count(const char *s, char delim);
|
||||||
static NDBOX *write_box(int dim, char *str1, char *str2);
|
static bool write_box(int dim, char *str1, char *str2,
|
||||||
static NDBOX *write_point_as_box(int dim, char *str);
|
NDBOX **result, struct Node *escontext);
|
||||||
|
static bool write_point_as_box(int dim, char *str,
|
||||||
|
NDBOX **result, struct Node *escontext);
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
/* BISON Declarations */
|
/* BISON Declarations */
|
||||||
%parse-param {NDBOX **result}
|
%parse-param {NDBOX **result}
|
||||||
%parse-param {Size scanbuflen}
|
%parse-param {Size scanbuflen}
|
||||||
|
%parse-param {struct Node *escontext}
|
||||||
%expect 0
|
%expect 0
|
||||||
%name-prefix="cube_yy"
|
%name-prefix="cube_yy"
|
||||||
|
|
||||||
@ -45,7 +49,7 @@ box: O_BRACKET paren_list COMMA paren_list C_BRACKET
|
|||||||
dim = item_count($2, ',');
|
dim = item_count($2, ',');
|
||||||
if (item_count($4, ',') != dim)
|
if (item_count($4, ',') != dim)
|
||||||
{
|
{
|
||||||
ereport(ERROR,
|
errsave(escontext,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("invalid input syntax for cube"),
|
errmsg("invalid input syntax for cube"),
|
||||||
errdetail("Different point dimensions in (%s) and (%s).",
|
errdetail("Different point dimensions in (%s) and (%s).",
|
||||||
@ -54,7 +58,7 @@ box: O_BRACKET paren_list COMMA paren_list C_BRACKET
|
|||||||
}
|
}
|
||||||
if (dim > CUBE_MAX_DIM)
|
if (dim > CUBE_MAX_DIM)
|
||||||
{
|
{
|
||||||
ereport(ERROR,
|
errsave(escontext,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("invalid input syntax for cube"),
|
errmsg("invalid input syntax for cube"),
|
||||||
errdetail("A cube cannot have more than %d dimensions.",
|
errdetail("A cube cannot have more than %d dimensions.",
|
||||||
@ -62,7 +66,8 @@ box: O_BRACKET paren_list COMMA paren_list C_BRACKET
|
|||||||
YYABORT;
|
YYABORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
*result = write_box( dim, $2, $4 );
|
if (!write_box(dim, $2, $4, result, escontext))
|
||||||
|
YYABORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
| paren_list COMMA paren_list
|
| paren_list COMMA paren_list
|
||||||
@ -72,7 +77,7 @@ box: O_BRACKET paren_list COMMA paren_list C_BRACKET
|
|||||||
dim = item_count($1, ',');
|
dim = item_count($1, ',');
|
||||||
if (item_count($3, ',') != dim)
|
if (item_count($3, ',') != dim)
|
||||||
{
|
{
|
||||||
ereport(ERROR,
|
errsave(escontext,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("invalid input syntax for cube"),
|
errmsg("invalid input syntax for cube"),
|
||||||
errdetail("Different point dimensions in (%s) and (%s).",
|
errdetail("Different point dimensions in (%s) and (%s).",
|
||||||
@ -81,7 +86,7 @@ box: O_BRACKET paren_list COMMA paren_list C_BRACKET
|
|||||||
}
|
}
|
||||||
if (dim > CUBE_MAX_DIM)
|
if (dim > CUBE_MAX_DIM)
|
||||||
{
|
{
|
||||||
ereport(ERROR,
|
errsave(escontext,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("invalid input syntax for cube"),
|
errmsg("invalid input syntax for cube"),
|
||||||
errdetail("A cube cannot have more than %d dimensions.",
|
errdetail("A cube cannot have more than %d dimensions.",
|
||||||
@ -89,7 +94,8 @@ box: O_BRACKET paren_list COMMA paren_list C_BRACKET
|
|||||||
YYABORT;
|
YYABORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
*result = write_box( dim, $1, $3 );
|
if (!write_box(dim, $1, $3, result, escontext))
|
||||||
|
YYABORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
| paren_list
|
| paren_list
|
||||||
@ -99,7 +105,7 @@ box: O_BRACKET paren_list COMMA paren_list C_BRACKET
|
|||||||
dim = item_count($1, ',');
|
dim = item_count($1, ',');
|
||||||
if (dim > CUBE_MAX_DIM)
|
if (dim > CUBE_MAX_DIM)
|
||||||
{
|
{
|
||||||
ereport(ERROR,
|
errsave(escontext,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("invalid input syntax for cube"),
|
errmsg("invalid input syntax for cube"),
|
||||||
errdetail("A cube cannot have more than %d dimensions.",
|
errdetail("A cube cannot have more than %d dimensions.",
|
||||||
@ -107,7 +113,8 @@ box: O_BRACKET paren_list COMMA paren_list C_BRACKET
|
|||||||
YYABORT;
|
YYABORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
*result = write_point_as_box(dim, $1);
|
if (!write_point_as_box(dim, $1, result, escontext))
|
||||||
|
YYABORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
| list
|
| list
|
||||||
@ -117,7 +124,7 @@ box: O_BRACKET paren_list COMMA paren_list C_BRACKET
|
|||||||
dim = item_count($1, ',');
|
dim = item_count($1, ',');
|
||||||
if (dim > CUBE_MAX_DIM)
|
if (dim > CUBE_MAX_DIM)
|
||||||
{
|
{
|
||||||
ereport(ERROR,
|
errsave(escontext,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("invalid input syntax for cube"),
|
errmsg("invalid input syntax for cube"),
|
||||||
errdetail("A cube cannot have more than %d dimensions.",
|
errdetail("A cube cannot have more than %d dimensions.",
|
||||||
@ -125,7 +132,8 @@ box: O_BRACKET paren_list COMMA paren_list C_BRACKET
|
|||||||
YYABORT;
|
YYABORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
*result = write_point_as_box(dim, $1);
|
if (!write_point_as_box(dim, $1, result, escontext))
|
||||||
|
YYABORT;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -173,8 +181,9 @@ item_count(const char *s, char delim)
|
|||||||
return nitems;
|
return nitems;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NDBOX *
|
static bool
|
||||||
write_box(int dim, char *str1, char *str2)
|
write_box(int dim, char *str1, char *str2,
|
||||||
|
NDBOX **result, struct Node *escontext)
|
||||||
{
|
{
|
||||||
NDBOX *bp;
|
NDBOX *bp;
|
||||||
char *s;
|
char *s;
|
||||||
@ -190,18 +199,26 @@ write_box(int dim, char *str1, char *str2)
|
|||||||
s = str1;
|
s = str1;
|
||||||
i = 0;
|
i = 0;
|
||||||
if (dim > 0)
|
if (dim > 0)
|
||||||
bp->x[i++] = float8in_internal(s, &endptr, "cube", str1);
|
{
|
||||||
|
bp->x[i++] = float8in_internal(s, &endptr, "cube", str1, escontext);
|
||||||
|
if (SOFT_ERROR_OCCURRED(escontext))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
while ((s = strchr(s, ',')) != NULL)
|
while ((s = strchr(s, ',')) != NULL)
|
||||||
{
|
{
|
||||||
s++;
|
s++;
|
||||||
bp->x[i++] = float8in_internal(s, &endptr, "cube", str1);
|
bp->x[i++] = float8in_internal(s, &endptr, "cube", str1, escontext);
|
||||||
|
if (SOFT_ERROR_OCCURRED(escontext))
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
Assert(i == dim);
|
Assert(i == dim);
|
||||||
|
|
||||||
s = str2;
|
s = str2;
|
||||||
if (dim > 0)
|
if (dim > 0)
|
||||||
{
|
{
|
||||||
bp->x[i] = float8in_internal(s, &endptr, "cube", str2);
|
bp->x[i] = float8in_internal(s, &endptr, "cube", str2, escontext);
|
||||||
|
if (SOFT_ERROR_OCCURRED(escontext))
|
||||||
|
return false;
|
||||||
/* code this way to do right thing with NaN */
|
/* code this way to do right thing with NaN */
|
||||||
point &= (bp->x[i] == bp->x[0]);
|
point &= (bp->x[i] == bp->x[0]);
|
||||||
i++;
|
i++;
|
||||||
@ -209,7 +226,9 @@ write_box(int dim, char *str1, char *str2)
|
|||||||
while ((s = strchr(s, ',')) != NULL)
|
while ((s = strchr(s, ',')) != NULL)
|
||||||
{
|
{
|
||||||
s++;
|
s++;
|
||||||
bp->x[i] = float8in_internal(s, &endptr, "cube", str2);
|
bp->x[i] = float8in_internal(s, &endptr, "cube", str2, escontext);
|
||||||
|
if (SOFT_ERROR_OCCURRED(escontext))
|
||||||
|
return false;
|
||||||
point &= (bp->x[i] == bp->x[i - dim]);
|
point &= (bp->x[i] == bp->x[i - dim]);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
@ -229,11 +248,13 @@ write_box(int dim, char *str1, char *str2)
|
|||||||
SET_POINT_BIT(bp);
|
SET_POINT_BIT(bp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bp;
|
*result = bp;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NDBOX *
|
static bool
|
||||||
write_point_as_box(int dim, char *str)
|
write_point_as_box(int dim, char *str,
|
||||||
|
NDBOX **result, struct Node *escontext)
|
||||||
{
|
{
|
||||||
NDBOX *bp;
|
NDBOX *bp;
|
||||||
int i,
|
int i,
|
||||||
@ -250,13 +271,20 @@ write_point_as_box(int dim, char *str)
|
|||||||
s = str;
|
s = str;
|
||||||
i = 0;
|
i = 0;
|
||||||
if (dim > 0)
|
if (dim > 0)
|
||||||
bp->x[i++] = float8in_internal(s, &endptr, "cube", str);
|
{
|
||||||
|
bp->x[i++] = float8in_internal(s, &endptr, "cube", str, escontext);
|
||||||
|
if (SOFT_ERROR_OCCURRED(escontext))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
while ((s = strchr(s, ',')) != NULL)
|
while ((s = strchr(s, ',')) != NULL)
|
||||||
{
|
{
|
||||||
s++;
|
s++;
|
||||||
bp->x[i++] = float8in_internal(s, &endptr, "cube", str);
|
bp->x[i++] = float8in_internal(s, &endptr, "cube", str, escontext);
|
||||||
|
if (SOFT_ERROR_OCCURRED(escontext))
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
Assert(i == dim);
|
Assert(i == dim);
|
||||||
|
|
||||||
return bp;
|
*result = bp;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -72,11 +72,13 @@ NaN [nN][aA][nN]
|
|||||||
|
|
||||||
/* result and scanbuflen are not used, but Bison expects this signature */
|
/* result and scanbuflen are not used, but Bison expects this signature */
|
||||||
void
|
void
|
||||||
cube_yyerror(NDBOX **result, Size scanbuflen, const char *message)
|
cube_yyerror(NDBOX **result, Size scanbuflen,
|
||||||
|
struct Node *escontext,
|
||||||
|
const char *message)
|
||||||
{
|
{
|
||||||
if (*yytext == YY_END_OF_BUFFER_CHAR)
|
if (*yytext == YY_END_OF_BUFFER_CHAR)
|
||||||
{
|
{
|
||||||
ereport(ERROR,
|
errsave(escontext,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("invalid input syntax for cube"),
|
errmsg("invalid input syntax for cube"),
|
||||||
/* translator: %s is typically "syntax error" */
|
/* translator: %s is typically "syntax error" */
|
||||||
@ -84,7 +86,7 @@ cube_yyerror(NDBOX **result, Size scanbuflen, const char *message)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ereport(ERROR,
|
errsave(escontext,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("invalid input syntax for cube"),
|
errmsg("invalid input syntax for cube"),
|
||||||
/* translator: first %s is typically "syntax error" */
|
/* translator: first %s is typically "syntax error" */
|
||||||
|
@ -325,6 +325,31 @@ SELECT '-1e-700'::cube AS cube; -- out of range
|
|||||||
ERROR: "-1e-700" is out of range for type double precision
|
ERROR: "-1e-700" is out of range for type double precision
|
||||||
LINE 1: SELECT '-1e-700'::cube AS cube;
|
LINE 1: SELECT '-1e-700'::cube AS cube;
|
||||||
^
|
^
|
||||||
|
-- Also try it with non-error-throwing API
|
||||||
|
SELECT pg_input_is_valid('(1,2)', 'cube');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_is_valid('[(1),]', 'cube');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_is_valid('-1e-700', 'cube');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_error_message('-1e-700', 'cube');
|
||||||
|
pg_input_error_message
|
||||||
|
-----------------------------------------------------
|
||||||
|
"-1e-700" is out of range for type double precision
|
||||||
|
(1 row)
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Testing building cubes from float8 values
|
-- Testing building cubes from float8 values
|
||||||
--
|
--
|
||||||
|
@ -79,6 +79,12 @@ SELECT '1,2a'::cube AS cube; -- 7
|
|||||||
SELECT '1..2'::cube AS cube; -- 7
|
SELECT '1..2'::cube AS cube; -- 7
|
||||||
SELECT '-1e-700'::cube AS cube; -- out of range
|
SELECT '-1e-700'::cube AS cube; -- out of range
|
||||||
|
|
||||||
|
-- Also try it with non-error-throwing API
|
||||||
|
SELECT pg_input_is_valid('(1,2)', 'cube');
|
||||||
|
SELECT pg_input_is_valid('[(1),]', 'cube');
|
||||||
|
SELECT pg_input_is_valid('-1e-700', 'cube');
|
||||||
|
SELECT pg_input_error_message('-1e-700', 'cube');
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Testing building cubes from float8 values
|
-- Testing building cubes from float8 values
|
||||||
--
|
--
|
||||||
|
@ -90,14 +90,15 @@ typedef struct ArrayIteratorData
|
|||||||
} ArrayIteratorData;
|
} ArrayIteratorData;
|
||||||
|
|
||||||
static bool array_isspace(char ch);
|
static bool array_isspace(char ch);
|
||||||
static int ArrayCount(const char *str, int *dim, char typdelim);
|
static int ArrayCount(const char *str, int *dim, char typdelim,
|
||||||
static void ReadArrayStr(char *arrayStr, const char *origStr,
|
Node *escontext);
|
||||||
|
static bool ReadArrayStr(char *arrayStr, const char *origStr,
|
||||||
int nitems, int ndim, int *dim,
|
int nitems, int ndim, int *dim,
|
||||||
FmgrInfo *inputproc, Oid typioparam, int32 typmod,
|
FmgrInfo *inputproc, Oid typioparam, int32 typmod,
|
||||||
char typdelim,
|
char typdelim,
|
||||||
int typlen, bool typbyval, char typalign,
|
int typlen, bool typbyval, char typalign,
|
||||||
Datum *values, bool *nulls,
|
Datum *values, bool *nulls,
|
||||||
bool *hasnulls, int32 *nbytes);
|
bool *hasnulls, int32 *nbytes, Node *escontext);
|
||||||
static void ReadArrayBinary(StringInfo buf, int nitems,
|
static void ReadArrayBinary(StringInfo buf, int nitems,
|
||||||
FmgrInfo *receiveproc, Oid typioparam, int32 typmod,
|
FmgrInfo *receiveproc, Oid typioparam, int32 typmod,
|
||||||
int typlen, bool typbyval, char typalign,
|
int typlen, bool typbyval, char typalign,
|
||||||
@ -177,6 +178,7 @@ array_in(PG_FUNCTION_ARGS)
|
|||||||
Oid element_type = PG_GETARG_OID(1); /* type of an array
|
Oid element_type = PG_GETARG_OID(1); /* type of an array
|
||||||
* element */
|
* element */
|
||||||
int32 typmod = PG_GETARG_INT32(2); /* typmod for array elements */
|
int32 typmod = PG_GETARG_INT32(2); /* typmod for array elements */
|
||||||
|
Node *escontext = fcinfo->context;
|
||||||
int typlen;
|
int typlen;
|
||||||
bool typbyval;
|
bool typbyval;
|
||||||
char typalign;
|
char typalign;
|
||||||
@ -258,7 +260,7 @@ array_in(PG_FUNCTION_ARGS)
|
|||||||
break; /* no more dimension items */
|
break; /* no more dimension items */
|
||||||
p++;
|
p++;
|
||||||
if (ndim >= MAXDIM)
|
if (ndim >= MAXDIM)
|
||||||
ereport(ERROR,
|
ereturn(escontext, (Datum) 0,
|
||||||
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
||||||
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
|
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
|
||||||
ndim + 1, MAXDIM)));
|
ndim + 1, MAXDIM)));
|
||||||
@ -266,7 +268,7 @@ array_in(PG_FUNCTION_ARGS)
|
|||||||
for (q = p; isdigit((unsigned char) *q) || (*q == '-') || (*q == '+'); q++)
|
for (q = p; isdigit((unsigned char) *q) || (*q == '-') || (*q == '+'); q++)
|
||||||
/* skip */ ;
|
/* skip */ ;
|
||||||
if (q == p) /* no digits? */
|
if (q == p) /* no digits? */
|
||||||
ereport(ERROR,
|
ereturn(escontext, (Datum) 0,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed array literal: \"%s\"", string),
|
errmsg("malformed array literal: \"%s\"", string),
|
||||||
errdetail("\"[\" must introduce explicitly-specified array dimensions.")));
|
errdetail("\"[\" must introduce explicitly-specified array dimensions.")));
|
||||||
@ -280,7 +282,7 @@ array_in(PG_FUNCTION_ARGS)
|
|||||||
for (q = p; isdigit((unsigned char) *q) || (*q == '-') || (*q == '+'); q++)
|
for (q = p; isdigit((unsigned char) *q) || (*q == '-') || (*q == '+'); q++)
|
||||||
/* skip */ ;
|
/* skip */ ;
|
||||||
if (q == p) /* no digits? */
|
if (q == p) /* no digits? */
|
||||||
ereport(ERROR,
|
ereturn(escontext, (Datum) 0,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed array literal: \"%s\"", string),
|
errmsg("malformed array literal: \"%s\"", string),
|
||||||
errdetail("Missing array dimension value.")));
|
errdetail("Missing array dimension value.")));
|
||||||
@ -291,7 +293,7 @@ array_in(PG_FUNCTION_ARGS)
|
|||||||
lBound[ndim] = 1;
|
lBound[ndim] = 1;
|
||||||
}
|
}
|
||||||
if (*q != ']')
|
if (*q != ']')
|
||||||
ereport(ERROR,
|
ereturn(escontext, (Datum) 0,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed array literal: \"%s\"", string),
|
errmsg("malformed array literal: \"%s\"", string),
|
||||||
errdetail("Missing \"%s\" after array dimensions.",
|
errdetail("Missing \"%s\" after array dimensions.",
|
||||||
@ -301,7 +303,7 @@ array_in(PG_FUNCTION_ARGS)
|
|||||||
ub = atoi(p);
|
ub = atoi(p);
|
||||||
p = q + 1;
|
p = q + 1;
|
||||||
if (ub < lBound[ndim])
|
if (ub < lBound[ndim])
|
||||||
ereport(ERROR,
|
ereturn(escontext, (Datum) 0,
|
||||||
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
||||||
errmsg("upper bound cannot be less than lower bound")));
|
errmsg("upper bound cannot be less than lower bound")));
|
||||||
|
|
||||||
@ -313,11 +315,13 @@ array_in(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
/* No array dimensions, so intuit dimensions from brace structure */
|
/* No array dimensions, so intuit dimensions from brace structure */
|
||||||
if (*p != '{')
|
if (*p != '{')
|
||||||
ereport(ERROR,
|
ereturn(escontext, (Datum) 0,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed array literal: \"%s\"", string),
|
errmsg("malformed array literal: \"%s\"", string),
|
||||||
errdetail("Array value must start with \"{\" or dimension information.")));
|
errdetail("Array value must start with \"{\" or dimension information.")));
|
||||||
ndim = ArrayCount(p, dim, typdelim);
|
ndim = ArrayCount(p, dim, typdelim, escontext);
|
||||||
|
if (ndim < 0)
|
||||||
|
PG_RETURN_NULL();
|
||||||
for (i = 0; i < ndim; i++)
|
for (i = 0; i < ndim; i++)
|
||||||
lBound[i] = 1;
|
lBound[i] = 1;
|
||||||
}
|
}
|
||||||
@ -328,7 +332,7 @@ array_in(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
/* If array dimensions are given, expect '=' operator */
|
/* If array dimensions are given, expect '=' operator */
|
||||||
if (strncmp(p, ASSGN, strlen(ASSGN)) != 0)
|
if (strncmp(p, ASSGN, strlen(ASSGN)) != 0)
|
||||||
ereport(ERROR,
|
ereturn(escontext, (Datum) 0,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed array literal: \"%s\"", string),
|
errmsg("malformed array literal: \"%s\"", string),
|
||||||
errdetail("Missing \"%s\" after array dimensions.",
|
errdetail("Missing \"%s\" after array dimensions.",
|
||||||
@ -342,20 +346,22 @@ array_in(PG_FUNCTION_ARGS)
|
|||||||
* were given
|
* were given
|
||||||
*/
|
*/
|
||||||
if (*p != '{')
|
if (*p != '{')
|
||||||
ereport(ERROR,
|
ereturn(escontext, (Datum) 0,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed array literal: \"%s\"", string),
|
errmsg("malformed array literal: \"%s\"", string),
|
||||||
errdetail("Array contents must start with \"{\".")));
|
errdetail("Array contents must start with \"{\".")));
|
||||||
ndim_braces = ArrayCount(p, dim_braces, typdelim);
|
ndim_braces = ArrayCount(p, dim_braces, typdelim, escontext);
|
||||||
|
if (ndim_braces < 0)
|
||||||
|
PG_RETURN_NULL();
|
||||||
if (ndim_braces != ndim)
|
if (ndim_braces != ndim)
|
||||||
ereport(ERROR,
|
ereturn(escontext, (Datum) 0,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed array literal: \"%s\"", string),
|
errmsg("malformed array literal: \"%s\"", string),
|
||||||
errdetail("Specified array dimensions do not match array contents.")));
|
errdetail("Specified array dimensions do not match array contents.")));
|
||||||
for (i = 0; i < ndim; ++i)
|
for (i = 0; i < ndim; ++i)
|
||||||
{
|
{
|
||||||
if (dim[i] != dim_braces[i])
|
if (dim[i] != dim_braces[i])
|
||||||
ereport(ERROR,
|
ereturn(escontext, (Datum) 0,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed array literal: \"%s\"", string),
|
errmsg("malformed array literal: \"%s\"", string),
|
||||||
errdetail("Specified array dimensions do not match array contents.")));
|
errdetail("Specified array dimensions do not match array contents.")));
|
||||||
@ -372,8 +378,11 @@ array_in(PG_FUNCTION_ARGS)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* This checks for overflow of the array dimensions */
|
/* This checks for overflow of the array dimensions */
|
||||||
nitems = ArrayGetNItems(ndim, dim);
|
nitems = ArrayGetNItemsSafe(ndim, dim, escontext);
|
||||||
ArrayCheckBounds(ndim, dim, lBound);
|
if (nitems < 0)
|
||||||
|
PG_RETURN_NULL();
|
||||||
|
if (!ArrayCheckBoundsSafe(ndim, dim, lBound, escontext))
|
||||||
|
PG_RETURN_NULL();
|
||||||
|
|
||||||
/* Empty array? */
|
/* Empty array? */
|
||||||
if (nitems == 0)
|
if (nitems == 0)
|
||||||
@ -381,13 +390,14 @@ array_in(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
dataPtr = (Datum *) palloc(nitems * sizeof(Datum));
|
dataPtr = (Datum *) palloc(nitems * sizeof(Datum));
|
||||||
nullsPtr = (bool *) palloc(nitems * sizeof(bool));
|
nullsPtr = (bool *) palloc(nitems * sizeof(bool));
|
||||||
ReadArrayStr(p, string,
|
if (!ReadArrayStr(p, string,
|
||||||
nitems, ndim, dim,
|
nitems, ndim, dim,
|
||||||
&my_extra->proc, typioparam, typmod,
|
&my_extra->proc, typioparam, typmod,
|
||||||
typdelim,
|
typdelim,
|
||||||
typlen, typbyval, typalign,
|
typlen, typbyval, typalign,
|
||||||
dataPtr, nullsPtr,
|
dataPtr, nullsPtr,
|
||||||
&hasnulls, &nbytes);
|
&hasnulls, &nbytes, escontext))
|
||||||
|
PG_RETURN_NULL();
|
||||||
if (hasnulls)
|
if (hasnulls)
|
||||||
{
|
{
|
||||||
dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, nitems);
|
dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, nitems);
|
||||||
@ -451,9 +461,12 @@ array_isspace(char ch)
|
|||||||
*
|
*
|
||||||
* Returns number of dimensions as function result. The axis lengths are
|
* Returns number of dimensions as function result. The axis lengths are
|
||||||
* returned in dim[], which must be of size MAXDIM.
|
* returned in dim[], which must be of size MAXDIM.
|
||||||
|
*
|
||||||
|
* If we detect an error, fill *escontext with error details and return -1
|
||||||
|
* (unless escontext isn't provided, in which case errors will be thrown).
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
ArrayCount(const char *str, int *dim, char typdelim)
|
ArrayCount(const char *str, int *dim, char typdelim, Node *escontext)
|
||||||
{
|
{
|
||||||
int nest_level = 0,
|
int nest_level = 0,
|
||||||
i;
|
i;
|
||||||
@ -488,11 +501,10 @@ ArrayCount(const char *str, int *dim, char typdelim)
|
|||||||
{
|
{
|
||||||
case '\0':
|
case '\0':
|
||||||
/* Signal a premature end of the string */
|
/* Signal a premature end of the string */
|
||||||
ereport(ERROR,
|
ereturn(escontext, -1,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed array literal: \"%s\"", str),
|
errmsg("malformed array literal: \"%s\"", str),
|
||||||
errdetail("Unexpected end of input.")));
|
errdetail("Unexpected end of input.")));
|
||||||
break;
|
|
||||||
case '\\':
|
case '\\':
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -504,7 +516,7 @@ ArrayCount(const char *str, int *dim, char typdelim)
|
|||||||
parse_state != ARRAY_ELEM_STARTED &&
|
parse_state != ARRAY_ELEM_STARTED &&
|
||||||
parse_state != ARRAY_QUOTED_ELEM_STARTED &&
|
parse_state != ARRAY_QUOTED_ELEM_STARTED &&
|
||||||
parse_state != ARRAY_ELEM_DELIMITED)
|
parse_state != ARRAY_ELEM_DELIMITED)
|
||||||
ereport(ERROR,
|
ereturn(escontext, -1,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed array literal: \"%s\"", str),
|
errmsg("malformed array literal: \"%s\"", str),
|
||||||
errdetail("Unexpected \"%c\" character.",
|
errdetail("Unexpected \"%c\" character.",
|
||||||
@ -515,7 +527,7 @@ ArrayCount(const char *str, int *dim, char typdelim)
|
|||||||
if (*(ptr + 1))
|
if (*(ptr + 1))
|
||||||
ptr++;
|
ptr++;
|
||||||
else
|
else
|
||||||
ereport(ERROR,
|
ereturn(escontext, -1,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed array literal: \"%s\"", str),
|
errmsg("malformed array literal: \"%s\"", str),
|
||||||
errdetail("Unexpected end of input.")));
|
errdetail("Unexpected end of input.")));
|
||||||
@ -530,7 +542,7 @@ ArrayCount(const char *str, int *dim, char typdelim)
|
|||||||
if (parse_state != ARRAY_LEVEL_STARTED &&
|
if (parse_state != ARRAY_LEVEL_STARTED &&
|
||||||
parse_state != ARRAY_QUOTED_ELEM_STARTED &&
|
parse_state != ARRAY_QUOTED_ELEM_STARTED &&
|
||||||
parse_state != ARRAY_ELEM_DELIMITED)
|
parse_state != ARRAY_ELEM_DELIMITED)
|
||||||
ereport(ERROR,
|
ereturn(escontext, -1,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed array literal: \"%s\"", str),
|
errmsg("malformed array literal: \"%s\"", str),
|
||||||
errdetail("Unexpected array element.")));
|
errdetail("Unexpected array element.")));
|
||||||
@ -551,14 +563,14 @@ ArrayCount(const char *str, int *dim, char typdelim)
|
|||||||
if (parse_state != ARRAY_NO_LEVEL &&
|
if (parse_state != ARRAY_NO_LEVEL &&
|
||||||
parse_state != ARRAY_LEVEL_STARTED &&
|
parse_state != ARRAY_LEVEL_STARTED &&
|
||||||
parse_state != ARRAY_LEVEL_DELIMITED)
|
parse_state != ARRAY_LEVEL_DELIMITED)
|
||||||
ereport(ERROR,
|
ereturn(escontext, -1,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed array literal: \"%s\"", str),
|
errmsg("malformed array literal: \"%s\"", str),
|
||||||
errdetail("Unexpected \"%c\" character.",
|
errdetail("Unexpected \"%c\" character.",
|
||||||
'{')));
|
'{')));
|
||||||
parse_state = ARRAY_LEVEL_STARTED;
|
parse_state = ARRAY_LEVEL_STARTED;
|
||||||
if (nest_level >= MAXDIM)
|
if (nest_level >= MAXDIM)
|
||||||
ereport(ERROR,
|
ereturn(escontext, -1,
|
||||||
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
||||||
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
|
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
|
||||||
nest_level + 1, MAXDIM)));
|
nest_level + 1, MAXDIM)));
|
||||||
@ -581,14 +593,14 @@ ArrayCount(const char *str, int *dim, char typdelim)
|
|||||||
parse_state != ARRAY_QUOTED_ELEM_COMPLETED &&
|
parse_state != ARRAY_QUOTED_ELEM_COMPLETED &&
|
||||||
parse_state != ARRAY_LEVEL_COMPLETED &&
|
parse_state != ARRAY_LEVEL_COMPLETED &&
|
||||||
!(nest_level == 1 && parse_state == ARRAY_LEVEL_STARTED))
|
!(nest_level == 1 && parse_state == ARRAY_LEVEL_STARTED))
|
||||||
ereport(ERROR,
|
ereturn(escontext, -1,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed array literal: \"%s\"", str),
|
errmsg("malformed array literal: \"%s\"", str),
|
||||||
errdetail("Unexpected \"%c\" character.",
|
errdetail("Unexpected \"%c\" character.",
|
||||||
'}')));
|
'}')));
|
||||||
parse_state = ARRAY_LEVEL_COMPLETED;
|
parse_state = ARRAY_LEVEL_COMPLETED;
|
||||||
if (nest_level == 0)
|
if (nest_level == 0)
|
||||||
ereport(ERROR,
|
ereturn(escontext, -1,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed array literal: \"%s\"", str),
|
errmsg("malformed array literal: \"%s\"", str),
|
||||||
errdetail("Unmatched \"%c\" character.", '}')));
|
errdetail("Unmatched \"%c\" character.", '}')));
|
||||||
@ -596,7 +608,7 @@ ArrayCount(const char *str, int *dim, char typdelim)
|
|||||||
|
|
||||||
if (nelems_last[nest_level] != 0 &&
|
if (nelems_last[nest_level] != 0 &&
|
||||||
nelems[nest_level] != nelems_last[nest_level])
|
nelems[nest_level] != nelems_last[nest_level])
|
||||||
ereport(ERROR,
|
ereturn(escontext, -1,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed array literal: \"%s\"", str),
|
errmsg("malformed array literal: \"%s\"", str),
|
||||||
errdetail("Multidimensional arrays must have "
|
errdetail("Multidimensional arrays must have "
|
||||||
@ -630,7 +642,7 @@ ArrayCount(const char *str, int *dim, char typdelim)
|
|||||||
parse_state != ARRAY_ELEM_COMPLETED &&
|
parse_state != ARRAY_ELEM_COMPLETED &&
|
||||||
parse_state != ARRAY_QUOTED_ELEM_COMPLETED &&
|
parse_state != ARRAY_QUOTED_ELEM_COMPLETED &&
|
||||||
parse_state != ARRAY_LEVEL_COMPLETED)
|
parse_state != ARRAY_LEVEL_COMPLETED)
|
||||||
ereport(ERROR,
|
ereturn(escontext, -1,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed array literal: \"%s\"", str),
|
errmsg("malformed array literal: \"%s\"", str),
|
||||||
errdetail("Unexpected \"%c\" character.",
|
errdetail("Unexpected \"%c\" character.",
|
||||||
@ -653,7 +665,7 @@ ArrayCount(const char *str, int *dim, char typdelim)
|
|||||||
if (parse_state != ARRAY_LEVEL_STARTED &&
|
if (parse_state != ARRAY_LEVEL_STARTED &&
|
||||||
parse_state != ARRAY_ELEM_STARTED &&
|
parse_state != ARRAY_ELEM_STARTED &&
|
||||||
parse_state != ARRAY_ELEM_DELIMITED)
|
parse_state != ARRAY_ELEM_DELIMITED)
|
||||||
ereport(ERROR,
|
ereturn(escontext, -1,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed array literal: \"%s\"", str),
|
errmsg("malformed array literal: \"%s\"", str),
|
||||||
errdetail("Unexpected array element.")));
|
errdetail("Unexpected array element.")));
|
||||||
@ -673,7 +685,7 @@ ArrayCount(const char *str, int *dim, char typdelim)
|
|||||||
while (*ptr)
|
while (*ptr)
|
||||||
{
|
{
|
||||||
if (!array_isspace(*ptr++))
|
if (!array_isspace(*ptr++))
|
||||||
ereport(ERROR,
|
ereturn(escontext, -1,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed array literal: \"%s\"", str),
|
errmsg("malformed array literal: \"%s\"", str),
|
||||||
errdetail("Junk after closing right brace.")));
|
errdetail("Junk after closing right brace.")));
|
||||||
@ -713,11 +725,16 @@ ArrayCount(const char *str, int *dim, char typdelim)
|
|||||||
* *hasnulls: set true iff there are any null elements.
|
* *hasnulls: set true iff there are any null elements.
|
||||||
* *nbytes: set to total size of data area needed (including alignment
|
* *nbytes: set to total size of data area needed (including alignment
|
||||||
* padding but not including array header overhead).
|
* padding but not including array header overhead).
|
||||||
|
* *escontext: if this points to an ErrorSaveContext, details of
|
||||||
|
* any error are reported there.
|
||||||
|
*
|
||||||
|
* Result:
|
||||||
|
* true for success, false for failure (if escontext is provided).
|
||||||
*
|
*
|
||||||
* Note that values[] and nulls[] are allocated by the caller, and must have
|
* Note that values[] and nulls[] are allocated by the caller, and must have
|
||||||
* nitems elements.
|
* nitems elements.
|
||||||
*/
|
*/
|
||||||
static void
|
static bool
|
||||||
ReadArrayStr(char *arrayStr,
|
ReadArrayStr(char *arrayStr,
|
||||||
const char *origStr,
|
const char *origStr,
|
||||||
int nitems,
|
int nitems,
|
||||||
@ -733,7 +750,8 @@ ReadArrayStr(char *arrayStr,
|
|||||||
Datum *values,
|
Datum *values,
|
||||||
bool *nulls,
|
bool *nulls,
|
||||||
bool *hasnulls,
|
bool *hasnulls,
|
||||||
int32 *nbytes)
|
int32 *nbytes,
|
||||||
|
Node *escontext)
|
||||||
{
|
{
|
||||||
int i,
|
int i,
|
||||||
nest_level = 0;
|
nest_level = 0;
|
||||||
@ -784,7 +802,7 @@ ReadArrayStr(char *arrayStr,
|
|||||||
{
|
{
|
||||||
case '\0':
|
case '\0':
|
||||||
/* Signal a premature end of the string */
|
/* Signal a premature end of the string */
|
||||||
ereport(ERROR,
|
ereturn(escontext, false,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed array literal: \"%s\"",
|
errmsg("malformed array literal: \"%s\"",
|
||||||
origStr)));
|
origStr)));
|
||||||
@ -793,7 +811,7 @@ ReadArrayStr(char *arrayStr,
|
|||||||
/* Skip backslash, copy next character as-is. */
|
/* Skip backslash, copy next character as-is. */
|
||||||
srcptr++;
|
srcptr++;
|
||||||
if (*srcptr == '\0')
|
if (*srcptr == '\0')
|
||||||
ereport(ERROR,
|
ereturn(escontext, false,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed array literal: \"%s\"",
|
errmsg("malformed array literal: \"%s\"",
|
||||||
origStr)));
|
origStr)));
|
||||||
@ -823,7 +841,7 @@ ReadArrayStr(char *arrayStr,
|
|||||||
if (!in_quotes)
|
if (!in_quotes)
|
||||||
{
|
{
|
||||||
if (nest_level >= ndim)
|
if (nest_level >= ndim)
|
||||||
ereport(ERROR,
|
ereturn(escontext, false,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed array literal: \"%s\"",
|
errmsg("malformed array literal: \"%s\"",
|
||||||
origStr)));
|
origStr)));
|
||||||
@ -838,7 +856,7 @@ ReadArrayStr(char *arrayStr,
|
|||||||
if (!in_quotes)
|
if (!in_quotes)
|
||||||
{
|
{
|
||||||
if (nest_level == 0)
|
if (nest_level == 0)
|
||||||
ereport(ERROR,
|
ereturn(escontext, false,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed array literal: \"%s\"",
|
errmsg("malformed array literal: \"%s\"",
|
||||||
origStr)));
|
origStr)));
|
||||||
@ -891,7 +909,7 @@ ReadArrayStr(char *arrayStr,
|
|||||||
*dstendptr = '\0';
|
*dstendptr = '\0';
|
||||||
|
|
||||||
if (i < 0 || i >= nitems)
|
if (i < 0 || i >= nitems)
|
||||||
ereport(ERROR,
|
ereturn(escontext, false,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed array literal: \"%s\"",
|
errmsg("malformed array literal: \"%s\"",
|
||||||
origStr)));
|
origStr)));
|
||||||
@ -900,14 +918,20 @@ ReadArrayStr(char *arrayStr,
|
|||||||
pg_strcasecmp(itemstart, "NULL") == 0)
|
pg_strcasecmp(itemstart, "NULL") == 0)
|
||||||
{
|
{
|
||||||
/* it's a NULL item */
|
/* it's a NULL item */
|
||||||
values[i] = InputFunctionCall(inputproc, NULL,
|
if (!InputFunctionCallSafe(inputproc, NULL,
|
||||||
typioparam, typmod);
|
typioparam, typmod,
|
||||||
|
escontext,
|
||||||
|
&values[i]))
|
||||||
|
return false;
|
||||||
nulls[i] = true;
|
nulls[i] = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
values[i] = InputFunctionCall(inputproc, itemstart,
|
if (!InputFunctionCallSafe(inputproc, itemstart,
|
||||||
typioparam, typmod);
|
typioparam, typmod,
|
||||||
|
escontext,
|
||||||
|
&values[i]))
|
||||||
|
return false;
|
||||||
nulls[i] = false;
|
nulls[i] = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -930,7 +954,7 @@ ReadArrayStr(char *arrayStr,
|
|||||||
totbytes = att_align_nominal(totbytes, typalign);
|
totbytes = att_align_nominal(totbytes, typalign);
|
||||||
/* check for overflow of total request */
|
/* check for overflow of total request */
|
||||||
if (!AllocSizeIsValid(totbytes))
|
if (!AllocSizeIsValid(totbytes))
|
||||||
ereport(ERROR,
|
ereturn(escontext, false,
|
||||||
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
||||||
errmsg("array size exceeds the maximum allowed (%d)",
|
errmsg("array size exceeds the maximum allowed (%d)",
|
||||||
(int) MaxAllocSize)));
|
(int) MaxAllocSize)));
|
||||||
@ -938,6 +962,7 @@ ReadArrayStr(char *arrayStr,
|
|||||||
}
|
}
|
||||||
*hasnulls = hasnull;
|
*hasnulls = hasnull;
|
||||||
*nbytes = totbytes;
|
*nbytes = totbytes;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -74,6 +74,16 @@ ArrayGetOffset0(int n, const int *tup, const int *scale)
|
|||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
ArrayGetNItems(int ndim, const int *dims)
|
ArrayGetNItems(int ndim, const int *dims)
|
||||||
|
{
|
||||||
|
return ArrayGetNItemsSafe(ndim, dims, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This entry point can return the error into an ErrorSaveContext
|
||||||
|
* instead of throwing an exception. -1 is returned after an error.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
ArrayGetNItemsSafe(int ndim, const int *dims, struct Node *escontext)
|
||||||
{
|
{
|
||||||
int32 ret;
|
int32 ret;
|
||||||
int i;
|
int i;
|
||||||
@ -89,7 +99,7 @@ ArrayGetNItems(int ndim, const int *dims)
|
|||||||
|
|
||||||
/* A negative dimension implies that UB-LB overflowed ... */
|
/* A negative dimension implies that UB-LB overflowed ... */
|
||||||
if (dims[i] < 0)
|
if (dims[i] < 0)
|
||||||
ereport(ERROR,
|
ereturn(escontext, -1,
|
||||||
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
||||||
errmsg("array size exceeds the maximum allowed (%d)",
|
errmsg("array size exceeds the maximum allowed (%d)",
|
||||||
(int) MaxArraySize)));
|
(int) MaxArraySize)));
|
||||||
@ -98,14 +108,14 @@ ArrayGetNItems(int ndim, const int *dims)
|
|||||||
|
|
||||||
ret = (int32) prod;
|
ret = (int32) prod;
|
||||||
if ((int64) ret != prod)
|
if ((int64) ret != prod)
|
||||||
ereport(ERROR,
|
ereturn(escontext, -1,
|
||||||
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
||||||
errmsg("array size exceeds the maximum allowed (%d)",
|
errmsg("array size exceeds the maximum allowed (%d)",
|
||||||
(int) MaxArraySize)));
|
(int) MaxArraySize)));
|
||||||
}
|
}
|
||||||
Assert(ret >= 0);
|
Assert(ret >= 0);
|
||||||
if ((Size) ret > MaxArraySize)
|
if ((Size) ret > MaxArraySize)
|
||||||
ereport(ERROR,
|
ereturn(escontext, -1,
|
||||||
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
||||||
errmsg("array size exceeds the maximum allowed (%d)",
|
errmsg("array size exceeds the maximum allowed (%d)",
|
||||||
(int) MaxArraySize)));
|
(int) MaxArraySize)));
|
||||||
@ -126,6 +136,17 @@ ArrayGetNItems(int ndim, const int *dims)
|
|||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ArrayCheckBounds(int ndim, const int *dims, const int *lb)
|
ArrayCheckBounds(int ndim, const int *dims, const int *lb)
|
||||||
|
{
|
||||||
|
(void) ArrayCheckBoundsSafe(ndim, dims, lb, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This entry point can return the error into an ErrorSaveContext
|
||||||
|
* instead of throwing an exception.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
ArrayCheckBoundsSafe(int ndim, const int *dims, const int *lb,
|
||||||
|
struct Node *escontext)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -135,11 +156,13 @@ ArrayCheckBounds(int ndim, const int *dims, const int *lb)
|
|||||||
int32 sum PG_USED_FOR_ASSERTS_ONLY;
|
int32 sum PG_USED_FOR_ASSERTS_ONLY;
|
||||||
|
|
||||||
if (pg_add_s32_overflow(dims[i], lb[i], &sum))
|
if (pg_add_s32_overflow(dims[i], lb[i], &sum))
|
||||||
ereport(ERROR,
|
ereturn(escontext, false,
|
||||||
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
||||||
errmsg("array lower bound is too large: %d",
|
errmsg("array lower bound is too large: %d",
|
||||||
lb[i])));
|
lb[i])));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -148,13 +148,10 @@ boolin(PG_FUNCTION_ARGS)
|
|||||||
if (parse_bool_with_len(str, len, &result))
|
if (parse_bool_with_len(str, len, &result))
|
||||||
PG_RETURN_BOOL(result);
|
PG_RETURN_BOOL(result);
|
||||||
|
|
||||||
ereport(ERROR,
|
ereturn(fcinfo->context, (Datum) 0,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("invalid input syntax for type %s: \"%s\"",
|
errmsg("invalid input syntax for type %s: \"%s\"",
|
||||||
"boolean", in_str)));
|
"boolean", in_str)));
|
||||||
|
|
||||||
/* not reached */
|
|
||||||
PG_RETURN_BOOL(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -163,6 +163,7 @@ Datum
|
|||||||
float4in(PG_FUNCTION_ARGS)
|
float4in(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
char *num = PG_GETARG_CSTRING(0);
|
char *num = PG_GETARG_CSTRING(0);
|
||||||
|
Node *escontext = fcinfo->context;
|
||||||
char *orig_num;
|
char *orig_num;
|
||||||
float val;
|
float val;
|
||||||
char *endptr;
|
char *endptr;
|
||||||
@ -183,7 +184,7 @@ float4in(PG_FUNCTION_ARGS)
|
|||||||
* strtod() on different platforms.
|
* strtod() on different platforms.
|
||||||
*/
|
*/
|
||||||
if (*num == '\0')
|
if (*num == '\0')
|
||||||
ereport(ERROR,
|
ereturn(escontext, (Datum) 0,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("invalid input syntax for type %s: \"%s\"",
|
errmsg("invalid input syntax for type %s: \"%s\"",
|
||||||
"real", orig_num)));
|
"real", orig_num)));
|
||||||
@ -257,13 +258,13 @@ float4in(PG_FUNCTION_ARGS)
|
|||||||
(val >= HUGE_VALF || val <= -HUGE_VALF)
|
(val >= HUGE_VALF || val <= -HUGE_VALF)
|
||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
ereport(ERROR,
|
ereturn(escontext, (Datum) 0,
|
||||||
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
||||||
errmsg("\"%s\" is out of range for type real",
|
errmsg("\"%s\" is out of range for type real",
|
||||||
orig_num)));
|
orig_num)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ereport(ERROR,
|
ereturn(escontext, (Datum) 0,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("invalid input syntax for type %s: \"%s\"",
|
errmsg("invalid input syntax for type %s: \"%s\"",
|
||||||
"real", orig_num)));
|
"real", orig_num)));
|
||||||
@ -275,7 +276,7 @@ float4in(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
/* if there is any junk left at the end of the string, bail out */
|
/* if there is any junk left at the end of the string, bail out */
|
||||||
if (*endptr != '\0')
|
if (*endptr != '\0')
|
||||||
ereport(ERROR,
|
ereturn(escontext, (Datum) 0,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("invalid input syntax for type %s: \"%s\"",
|
errmsg("invalid input syntax for type %s: \"%s\"",
|
||||||
"real", orig_num)));
|
"real", orig_num)));
|
||||||
@ -337,52 +338,40 @@ float8in(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
char *num = PG_GETARG_CSTRING(0);
|
char *num = PG_GETARG_CSTRING(0);
|
||||||
|
|
||||||
PG_RETURN_FLOAT8(float8in_internal(num, NULL, "double precision", num));
|
PG_RETURN_FLOAT8(float8in_internal(num, NULL, "double precision", num,
|
||||||
|
fcinfo->context));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convenience macro: set *have_error flag (if provided) or throw error */
|
|
||||||
#define RETURN_ERROR(throw_error, have_error) \
|
|
||||||
do { \
|
|
||||||
if (have_error) { \
|
|
||||||
*have_error = true; \
|
|
||||||
return 0.0; \
|
|
||||||
} else { \
|
|
||||||
throw_error; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* float8in_internal_opt_error - guts of float8in()
|
* float8in_internal - guts of float8in()
|
||||||
*
|
*
|
||||||
* This is exposed for use by functions that want a reasonably
|
* This is exposed for use by functions that want a reasonably
|
||||||
* platform-independent way of inputting doubles. The behavior is
|
* platform-independent way of inputting doubles. The behavior is
|
||||||
* essentially like strtod + ereport on error, but note the following
|
* essentially like strtod + ereturn on error, but note the following
|
||||||
* differences:
|
* differences:
|
||||||
* 1. Both leading and trailing whitespace are skipped.
|
* 1. Both leading and trailing whitespace are skipped.
|
||||||
* 2. If endptr_p is NULL, we throw error if there's trailing junk.
|
* 2. If endptr_p is NULL, we report error if there's trailing junk.
|
||||||
* Otherwise, it's up to the caller to complain about trailing junk.
|
* Otherwise, it's up to the caller to complain about trailing junk.
|
||||||
* 3. In event of a syntax error, the report mentions the given type_name
|
* 3. In event of a syntax error, the report mentions the given type_name
|
||||||
* and prints orig_string as the input; this is meant to support use of
|
* and prints orig_string as the input; this is meant to support use of
|
||||||
* this function with types such as "box" and "point", where what we are
|
* this function with types such as "box" and "point", where what we are
|
||||||
* parsing here is just a substring of orig_string.
|
* parsing here is just a substring of orig_string.
|
||||||
*
|
*
|
||||||
|
* If escontext points to an ErrorSaveContext node, that is filled instead
|
||||||
|
* of throwing an error; the caller must check SOFT_ERROR_OCCURRED()
|
||||||
|
* to detect errors.
|
||||||
|
*
|
||||||
* "num" could validly be declared "const char *", but that results in an
|
* "num" could validly be declared "const char *", but that results in an
|
||||||
* unreasonable amount of extra casting both here and in callers, so we don't.
|
* unreasonable amount of extra casting both here and in callers, so we don't.
|
||||||
*
|
|
||||||
* When "*have_error" flag is provided, it's set instead of throwing an
|
|
||||||
* error. This is helpful when caller need to handle errors by itself.
|
|
||||||
*/
|
*/
|
||||||
double
|
float8
|
||||||
float8in_internal_opt_error(char *num, char **endptr_p,
|
float8in_internal(char *num, char **endptr_p,
|
||||||
const char *type_name, const char *orig_string,
|
const char *type_name, const char *orig_string,
|
||||||
bool *have_error)
|
struct Node *escontext)
|
||||||
{
|
{
|
||||||
double val;
|
double val;
|
||||||
char *endptr;
|
char *endptr;
|
||||||
|
|
||||||
if (have_error)
|
|
||||||
*have_error = false;
|
|
||||||
|
|
||||||
/* skip leading whitespace */
|
/* skip leading whitespace */
|
||||||
while (*num != '\0' && isspace((unsigned char) *num))
|
while (*num != '\0' && isspace((unsigned char) *num))
|
||||||
num++;
|
num++;
|
||||||
@ -392,11 +381,10 @@ float8in_internal_opt_error(char *num, char **endptr_p,
|
|||||||
* strtod() on different platforms.
|
* strtod() on different platforms.
|
||||||
*/
|
*/
|
||||||
if (*num == '\0')
|
if (*num == '\0')
|
||||||
RETURN_ERROR(ereport(ERROR,
|
ereturn(escontext, 0,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("invalid input syntax for type %s: \"%s\"",
|
errmsg("invalid input syntax for type %s: \"%s\"",
|
||||||
type_name, orig_string))),
|
type_name, orig_string)));
|
||||||
have_error);
|
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
val = strtod(num, &endptr);
|
val = strtod(num, &endptr);
|
||||||
@ -469,20 +457,17 @@ float8in_internal_opt_error(char *num, char **endptr_p,
|
|||||||
char *errnumber = pstrdup(num);
|
char *errnumber = pstrdup(num);
|
||||||
|
|
||||||
errnumber[endptr - num] = '\0';
|
errnumber[endptr - num] = '\0';
|
||||||
RETURN_ERROR(ereport(ERROR,
|
ereturn(escontext, 0,
|
||||||
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
||||||
errmsg("\"%s\" is out of range for type double precision",
|
errmsg("\"%s\" is out of range for type double precision",
|
||||||
errnumber))),
|
errnumber)));
|
||||||
have_error);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
RETURN_ERROR(ereport(ERROR,
|
ereturn(escontext, 0,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("invalid input syntax for type "
|
errmsg("invalid input syntax for type %s: \"%s\"",
|
||||||
"%s: \"%s\"",
|
type_name, orig_string)));
|
||||||
type_name, orig_string))),
|
|
||||||
have_error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* skip trailing whitespace */
|
/* skip trailing whitespace */
|
||||||
@ -493,27 +478,14 @@ float8in_internal_opt_error(char *num, char **endptr_p,
|
|||||||
if (endptr_p)
|
if (endptr_p)
|
||||||
*endptr_p = endptr;
|
*endptr_p = endptr;
|
||||||
else if (*endptr != '\0')
|
else if (*endptr != '\0')
|
||||||
RETURN_ERROR(ereport(ERROR,
|
ereturn(escontext, 0,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("invalid input syntax for type "
|
errmsg("invalid input syntax for type %s: \"%s\"",
|
||||||
"%s: \"%s\"",
|
type_name, orig_string)));
|
||||||
type_name, orig_string))),
|
|
||||||
have_error);
|
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Interface to float8in_internal_opt_error() without "have_error" argument.
|
|
||||||
*/
|
|
||||||
double
|
|
||||||
float8in_internal(char *num, char **endptr_p,
|
|
||||||
const char *type_name, const char *orig_string)
|
|
||||||
{
|
|
||||||
return float8in_internal_opt_error(num, endptr_p, type_name,
|
|
||||||
orig_string, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* float8out - converts float8 number to a string
|
* float8out - converts float8 number to a string
|
||||||
|
@ -189,7 +189,7 @@ static float8
|
|||||||
single_decode(char *num, char **endptr_p,
|
single_decode(char *num, char **endptr_p,
|
||||||
const char *type_name, const char *orig_string)
|
const char *type_name, const char *orig_string)
|
||||||
{
|
{
|
||||||
return float8in_internal(num, endptr_p, type_name, orig_string);
|
return float8in_internal(num, endptr_p, type_name, orig_string, NULL);
|
||||||
} /* single_decode() */
|
} /* single_decode() */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -212,7 +212,7 @@ pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
|
|||||||
if ((has_delim = (*str == LDELIM)))
|
if ((has_delim = (*str == LDELIM)))
|
||||||
str++;
|
str++;
|
||||||
|
|
||||||
*x = float8in_internal(str, &str, type_name, orig_string);
|
*x = float8in_internal(str, &str, type_name, orig_string, NULL);
|
||||||
|
|
||||||
if (*str++ != DELIM)
|
if (*str++ != DELIM)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -220,7 +220,7 @@ pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
|
|||||||
errmsg("invalid input syntax for type %s: \"%s\"",
|
errmsg("invalid input syntax for type %s: \"%s\"",
|
||||||
type_name, orig_string)));
|
type_name, orig_string)));
|
||||||
|
|
||||||
*y = float8in_internal(str, &str, type_name, orig_string);
|
*y = float8in_internal(str, &str, type_name, orig_string, NULL);
|
||||||
|
|
||||||
if (has_delim)
|
if (has_delim)
|
||||||
{
|
{
|
||||||
|
@ -64,7 +64,7 @@ int2in(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
char *num = PG_GETARG_CSTRING(0);
|
char *num = PG_GETARG_CSTRING(0);
|
||||||
|
|
||||||
PG_RETURN_INT16(pg_strtoint16(num));
|
PG_RETURN_INT16(pg_strtoint16_safe(num, fcinfo->context));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -291,7 +291,7 @@ int4in(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
char *num = PG_GETARG_CSTRING(0);
|
char *num = PG_GETARG_CSTRING(0);
|
||||||
|
|
||||||
PG_RETURN_INT32(pg_strtoint32(num));
|
PG_RETURN_INT32(pg_strtoint32_safe(num, fcinfo->context));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -52,7 +52,7 @@ int8in(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
char *num = PG_GETARG_CSTRING(0);
|
char *num = PG_GETARG_CSTRING(0);
|
||||||
|
|
||||||
PG_RETURN_INT64(pg_strtoint64(num));
|
PG_RETURN_INT64(pg_strtoint64_safe(num, fcinfo->context));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -64,6 +64,7 @@
|
|||||||
#include "funcapi.h"
|
#include "funcapi.h"
|
||||||
#include "lib/stringinfo.h"
|
#include "lib/stringinfo.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
|
#include "nodes/miscnodes.h"
|
||||||
#include "regex/regex.h"
|
#include "regex/regex.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/date.h"
|
#include "utils/date.h"
|
||||||
@ -1041,15 +1042,15 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
|
|||||||
char *tmp = DatumGetCString(DirectFunctionCall1(numeric_out,
|
char *tmp = DatumGetCString(DirectFunctionCall1(numeric_out,
|
||||||
NumericGetDatum(jb->val.numeric)));
|
NumericGetDatum(jb->val.numeric)));
|
||||||
double val;
|
double val;
|
||||||
bool have_error = false;
|
ErrorSaveContext escontext = {T_ErrorSaveContext};
|
||||||
|
|
||||||
val = float8in_internal_opt_error(tmp,
|
val = float8in_internal(tmp,
|
||||||
NULL,
|
NULL,
|
||||||
"double precision",
|
"double precision",
|
||||||
tmp,
|
tmp,
|
||||||
&have_error);
|
(Node *) &escontext);
|
||||||
|
|
||||||
if (have_error || isinf(val) || isnan(val))
|
if (escontext.error_occurred || isinf(val) || isnan(val))
|
||||||
RETURN_ERROR(ereport(ERROR,
|
RETURN_ERROR(ereport(ERROR,
|
||||||
(errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
|
(errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
|
||||||
errmsg("numeric argument of jsonpath item method .%s() is out of range for type double precision",
|
errmsg("numeric argument of jsonpath item method .%s() is out of range for type double precision",
|
||||||
@ -1062,15 +1063,15 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
|
|||||||
double val;
|
double val;
|
||||||
char *tmp = pnstrdup(jb->val.string.val,
|
char *tmp = pnstrdup(jb->val.string.val,
|
||||||
jb->val.string.len);
|
jb->val.string.len);
|
||||||
bool have_error = false;
|
ErrorSaveContext escontext = {T_ErrorSaveContext};
|
||||||
|
|
||||||
val = float8in_internal_opt_error(tmp,
|
val = float8in_internal(tmp,
|
||||||
NULL,
|
NULL,
|
||||||
"double precision",
|
"double precision",
|
||||||
tmp,
|
tmp,
|
||||||
&have_error);
|
(Node *) &escontext);
|
||||||
|
|
||||||
if (have_error || isinf(val) || isnan(val))
|
if (escontext.error_occurred || isinf(val) || isnan(val))
|
||||||
RETURN_ERROR(ereport(ERROR,
|
RETURN_ERROR(ereport(ERROR,
|
||||||
(errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
|
(errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
|
||||||
errmsg("string argument of jsonpath item method .%s() is not a valid representation of a double precision number",
|
errmsg("string argument of jsonpath item method .%s() is not a valid representation of a double precision number",
|
||||||
|
@ -497,8 +497,9 @@ static void alloc_var(NumericVar *var, int ndigits);
|
|||||||
static void free_var(NumericVar *var);
|
static void free_var(NumericVar *var);
|
||||||
static void zero_var(NumericVar *var);
|
static void zero_var(NumericVar *var);
|
||||||
|
|
||||||
static const char *set_var_from_str(const char *str, const char *cp,
|
static bool set_var_from_str(const char *str, const char *cp,
|
||||||
NumericVar *dest);
|
NumericVar *dest, const char **endptr,
|
||||||
|
Node *escontext);
|
||||||
static void set_var_from_num(Numeric num, NumericVar *dest);
|
static void set_var_from_num(Numeric num, NumericVar *dest);
|
||||||
static void init_var_from_num(Numeric num, NumericVar *dest);
|
static void init_var_from_num(Numeric num, NumericVar *dest);
|
||||||
static void set_var_from_var(const NumericVar *value, NumericVar *dest);
|
static void set_var_from_var(const NumericVar *value, NumericVar *dest);
|
||||||
@ -512,8 +513,8 @@ static Numeric duplicate_numeric(Numeric num);
|
|||||||
static Numeric make_result(const NumericVar *var);
|
static Numeric make_result(const NumericVar *var);
|
||||||
static Numeric make_result_opt_error(const NumericVar *var, bool *have_error);
|
static Numeric make_result_opt_error(const NumericVar *var, bool *have_error);
|
||||||
|
|
||||||
static void apply_typmod(NumericVar *var, int32 typmod);
|
static bool apply_typmod(NumericVar *var, int32 typmod, Node *escontext);
|
||||||
static void apply_typmod_special(Numeric num, int32 typmod);
|
static bool apply_typmod_special(Numeric num, int32 typmod, Node *escontext);
|
||||||
|
|
||||||
static bool numericvar_to_int32(const NumericVar *var, int32 *result);
|
static bool numericvar_to_int32(const NumericVar *var, int32 *result);
|
||||||
static bool numericvar_to_int64(const NumericVar *var, int64 *result);
|
static bool numericvar_to_int64(const NumericVar *var, int64 *result);
|
||||||
@ -617,11 +618,11 @@ Datum
|
|||||||
numeric_in(PG_FUNCTION_ARGS)
|
numeric_in(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
char *str = PG_GETARG_CSTRING(0);
|
char *str = PG_GETARG_CSTRING(0);
|
||||||
|
|
||||||
#ifdef NOT_USED
|
#ifdef NOT_USED
|
||||||
Oid typelem = PG_GETARG_OID(1);
|
Oid typelem = PG_GETARG_OID(1);
|
||||||
#endif
|
#endif
|
||||||
int32 typmod = PG_GETARG_INT32(2);
|
int32 typmod = PG_GETARG_INT32(2);
|
||||||
|
Node *escontext = fcinfo->context;
|
||||||
Numeric res;
|
Numeric res;
|
||||||
const char *cp;
|
const char *cp;
|
||||||
|
|
||||||
@ -679,10 +680,12 @@ numeric_in(PG_FUNCTION_ARGS)
|
|||||||
* Use set_var_from_str() to parse a normal numeric value
|
* Use set_var_from_str() to parse a normal numeric value
|
||||||
*/
|
*/
|
||||||
NumericVar value;
|
NumericVar value;
|
||||||
|
bool have_error;
|
||||||
|
|
||||||
init_var(&value);
|
init_var(&value);
|
||||||
|
|
||||||
cp = set_var_from_str(str, cp, &value);
|
if (!set_var_from_str(str, cp, &value, &cp, escontext))
|
||||||
|
PG_RETURN_NULL();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We duplicate a few lines of code here because we would like to
|
* We duplicate a few lines of code here because we would like to
|
||||||
@ -693,16 +696,23 @@ numeric_in(PG_FUNCTION_ARGS)
|
|||||||
while (*cp)
|
while (*cp)
|
||||||
{
|
{
|
||||||
if (!isspace((unsigned char) *cp))
|
if (!isspace((unsigned char) *cp))
|
||||||
ereport(ERROR,
|
ereturn(escontext, (Datum) 0,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("invalid input syntax for type %s: \"%s\"",
|
errmsg("invalid input syntax for type %s: \"%s\"",
|
||||||
"numeric", str)));
|
"numeric", str)));
|
||||||
cp++;
|
cp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
apply_typmod(&value, typmod);
|
if (!apply_typmod(&value, typmod, escontext))
|
||||||
|
PG_RETURN_NULL();
|
||||||
|
|
||||||
|
res = make_result_opt_error(&value, &have_error);
|
||||||
|
|
||||||
|
if (have_error)
|
||||||
|
ereturn(escontext, (Datum) 0,
|
||||||
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
||||||
|
errmsg("value overflows numeric format")));
|
||||||
|
|
||||||
res = make_result(&value);
|
|
||||||
free_var(&value);
|
free_var(&value);
|
||||||
|
|
||||||
PG_RETURN_NUMERIC(res);
|
PG_RETURN_NUMERIC(res);
|
||||||
@ -712,7 +722,7 @@ numeric_in(PG_FUNCTION_ARGS)
|
|||||||
while (*cp)
|
while (*cp)
|
||||||
{
|
{
|
||||||
if (!isspace((unsigned char) *cp))
|
if (!isspace((unsigned char) *cp))
|
||||||
ereport(ERROR,
|
ereturn(escontext, (Datum) 0,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("invalid input syntax for type %s: \"%s\"",
|
errmsg("invalid input syntax for type %s: \"%s\"",
|
||||||
"numeric", str)));
|
"numeric", str)));
|
||||||
@ -720,7 +730,8 @@ numeric_in(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* As above, throw any typmod error after finishing syntax check */
|
/* As above, throw any typmod error after finishing syntax check */
|
||||||
apply_typmod_special(res, typmod);
|
if (!apply_typmod_special(res, typmod, escontext))
|
||||||
|
PG_RETURN_NULL();
|
||||||
|
|
||||||
PG_RETURN_NUMERIC(res);
|
PG_RETURN_NUMERIC(res);
|
||||||
}
|
}
|
||||||
@ -1058,7 +1069,7 @@ numeric_recv(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
trunc_var(&value, value.dscale);
|
trunc_var(&value, value.dscale);
|
||||||
|
|
||||||
apply_typmod(&value, typmod);
|
(void) apply_typmod(&value, typmod, NULL);
|
||||||
|
|
||||||
res = make_result(&value);
|
res = make_result(&value);
|
||||||
}
|
}
|
||||||
@ -1067,7 +1078,7 @@ numeric_recv(PG_FUNCTION_ARGS)
|
|||||||
/* apply_typmod_special wants us to make the Numeric first */
|
/* apply_typmod_special wants us to make the Numeric first */
|
||||||
res = make_result(&value);
|
res = make_result(&value);
|
||||||
|
|
||||||
apply_typmod_special(res, typmod);
|
(void) apply_typmod_special(res, typmod, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
free_var(&value);
|
free_var(&value);
|
||||||
@ -1180,7 +1191,7 @@ numeric (PG_FUNCTION_ARGS)
|
|||||||
*/
|
*/
|
||||||
if (NUMERIC_IS_SPECIAL(num))
|
if (NUMERIC_IS_SPECIAL(num))
|
||||||
{
|
{
|
||||||
apply_typmod_special(num, typmod);
|
(void) apply_typmod_special(num, typmod, NULL);
|
||||||
PG_RETURN_NUMERIC(duplicate_numeric(num));
|
PG_RETURN_NUMERIC(duplicate_numeric(num));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1231,7 +1242,7 @@ numeric (PG_FUNCTION_ARGS)
|
|||||||
init_var(&var);
|
init_var(&var);
|
||||||
|
|
||||||
set_var_from_num(num, &var);
|
set_var_from_num(num, &var);
|
||||||
apply_typmod(&var, typmod);
|
(void) apply_typmod(&var, typmod, NULL);
|
||||||
new = make_result(&var);
|
new = make_result(&var);
|
||||||
|
|
||||||
free_var(&var);
|
free_var(&var);
|
||||||
@ -4395,6 +4406,7 @@ float8_numeric(PG_FUNCTION_ARGS)
|
|||||||
Numeric res;
|
Numeric res;
|
||||||
NumericVar result;
|
NumericVar result;
|
||||||
char buf[DBL_DIG + 100];
|
char buf[DBL_DIG + 100];
|
||||||
|
const char *endptr;
|
||||||
|
|
||||||
if (isnan(val))
|
if (isnan(val))
|
||||||
PG_RETURN_NUMERIC(make_result(&const_nan));
|
PG_RETURN_NUMERIC(make_result(&const_nan));
|
||||||
@ -4412,7 +4424,7 @@ float8_numeric(PG_FUNCTION_ARGS)
|
|||||||
init_var(&result);
|
init_var(&result);
|
||||||
|
|
||||||
/* Assume we need not worry about leading/trailing spaces */
|
/* Assume we need not worry about leading/trailing spaces */
|
||||||
(void) set_var_from_str(buf, buf, &result);
|
(void) set_var_from_str(buf, buf, &result, &endptr, NULL);
|
||||||
|
|
||||||
res = make_result(&result);
|
res = make_result(&result);
|
||||||
|
|
||||||
@ -4488,6 +4500,7 @@ float4_numeric(PG_FUNCTION_ARGS)
|
|||||||
Numeric res;
|
Numeric res;
|
||||||
NumericVar result;
|
NumericVar result;
|
||||||
char buf[FLT_DIG + 100];
|
char buf[FLT_DIG + 100];
|
||||||
|
const char *endptr;
|
||||||
|
|
||||||
if (isnan(val))
|
if (isnan(val))
|
||||||
PG_RETURN_NUMERIC(make_result(&const_nan));
|
PG_RETURN_NUMERIC(make_result(&const_nan));
|
||||||
@ -4505,7 +4518,7 @@ float4_numeric(PG_FUNCTION_ARGS)
|
|||||||
init_var(&result);
|
init_var(&result);
|
||||||
|
|
||||||
/* Assume we need not worry about leading/trailing spaces */
|
/* Assume we need not worry about leading/trailing spaces */
|
||||||
(void) set_var_from_str(buf, buf, &result);
|
(void) set_var_from_str(buf, buf, &result, &endptr, NULL);
|
||||||
|
|
||||||
res = make_result(&result);
|
res = make_result(&result);
|
||||||
|
|
||||||
@ -6804,14 +6817,19 @@ zero_var(NumericVar *var)
|
|||||||
* Parse a string and put the number into a variable
|
* Parse a string and put the number into a variable
|
||||||
*
|
*
|
||||||
* This function does not handle leading or trailing spaces. It returns
|
* This function does not handle leading or trailing spaces. It returns
|
||||||
* the end+1 position parsed, so that caller can check for trailing
|
* the end+1 position parsed into *endptr, so that caller can check for
|
||||||
* spaces/garbage if deemed necessary.
|
* trailing spaces/garbage if deemed necessary.
|
||||||
*
|
*
|
||||||
* cp is the place to actually start parsing; str is what to use in error
|
* cp is the place to actually start parsing; str is what to use in error
|
||||||
* reports. (Typically cp would be the same except advanced over spaces.)
|
* reports. (Typically cp would be the same except advanced over spaces.)
|
||||||
|
*
|
||||||
|
* Returns true on success, false on failure (if escontext points to an
|
||||||
|
* ErrorSaveContext; otherwise errors are thrown).
|
||||||
*/
|
*/
|
||||||
static const char *
|
static bool
|
||||||
set_var_from_str(const char *str, const char *cp, NumericVar *dest)
|
set_var_from_str(const char *str, const char *cp,
|
||||||
|
NumericVar *dest, const char **endptr,
|
||||||
|
Node *escontext)
|
||||||
{
|
{
|
||||||
bool have_dp = false;
|
bool have_dp = false;
|
||||||
int i;
|
int i;
|
||||||
@ -6849,7 +6867,7 @@ set_var_from_str(const char *str, const char *cp, NumericVar *dest)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!isdigit((unsigned char) *cp))
|
if (!isdigit((unsigned char) *cp))
|
||||||
ereport(ERROR,
|
ereturn(escontext, false,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("invalid input syntax for type %s: \"%s\"",
|
errmsg("invalid input syntax for type %s: \"%s\"",
|
||||||
"numeric", str)));
|
"numeric", str)));
|
||||||
@ -6873,7 +6891,7 @@ set_var_from_str(const char *str, const char *cp, NumericVar *dest)
|
|||||||
else if (*cp == '.')
|
else if (*cp == '.')
|
||||||
{
|
{
|
||||||
if (have_dp)
|
if (have_dp)
|
||||||
ereport(ERROR,
|
ereturn(escontext, false,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("invalid input syntax for type %s: \"%s\"",
|
errmsg("invalid input syntax for type %s: \"%s\"",
|
||||||
"numeric", str)));
|
"numeric", str)));
|
||||||
@ -6897,7 +6915,7 @@ set_var_from_str(const char *str, const char *cp, NumericVar *dest)
|
|||||||
cp++;
|
cp++;
|
||||||
exponent = strtol(cp, &endptr, 10);
|
exponent = strtol(cp, &endptr, 10);
|
||||||
if (endptr == cp)
|
if (endptr == cp)
|
||||||
ereport(ERROR,
|
ereturn(escontext, false,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("invalid input syntax for type %s: \"%s\"",
|
errmsg("invalid input syntax for type %s: \"%s\"",
|
||||||
"numeric", str)));
|
"numeric", str)));
|
||||||
@ -6912,7 +6930,7 @@ set_var_from_str(const char *str, const char *cp, NumericVar *dest)
|
|||||||
* for consistency use the same ereport errcode/text as make_result().
|
* for consistency use the same ereport errcode/text as make_result().
|
||||||
*/
|
*/
|
||||||
if (exponent >= INT_MAX / 2 || exponent <= -(INT_MAX / 2))
|
if (exponent >= INT_MAX / 2 || exponent <= -(INT_MAX / 2))
|
||||||
ereport(ERROR,
|
ereturn(escontext, false,
|
||||||
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
||||||
errmsg("value overflows numeric format")));
|
errmsg("value overflows numeric format")));
|
||||||
dweight += (int) exponent;
|
dweight += (int) exponent;
|
||||||
@ -6963,7 +6981,9 @@ set_var_from_str(const char *str, const char *cp, NumericVar *dest)
|
|||||||
strip_var(dest);
|
strip_var(dest);
|
||||||
|
|
||||||
/* Return end+1 position for caller */
|
/* Return end+1 position for caller */
|
||||||
return cp;
|
*endptr = cp;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -7455,9 +7475,12 @@ make_result(const NumericVar *var)
|
|||||||
*
|
*
|
||||||
* Do bounds checking and rounding according to the specified typmod.
|
* Do bounds checking and rounding according to the specified typmod.
|
||||||
* Note that this is only applied to normal finite values.
|
* Note that this is only applied to normal finite values.
|
||||||
|
*
|
||||||
|
* Returns true on success, false on failure (if escontext points to an
|
||||||
|
* ErrorSaveContext; otherwise errors are thrown).
|
||||||
*/
|
*/
|
||||||
static void
|
static bool
|
||||||
apply_typmod(NumericVar *var, int32 typmod)
|
apply_typmod(NumericVar *var, int32 typmod, Node *escontext)
|
||||||
{
|
{
|
||||||
int precision;
|
int precision;
|
||||||
int scale;
|
int scale;
|
||||||
@ -7467,7 +7490,7 @@ apply_typmod(NumericVar *var, int32 typmod)
|
|||||||
|
|
||||||
/* Do nothing if we have an invalid typmod */
|
/* Do nothing if we have an invalid typmod */
|
||||||
if (!is_valid_numeric_typmod(typmod))
|
if (!is_valid_numeric_typmod(typmod))
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
precision = numeric_typmod_precision(typmod);
|
precision = numeric_typmod_precision(typmod);
|
||||||
scale = numeric_typmod_scale(typmod);
|
scale = numeric_typmod_scale(typmod);
|
||||||
@ -7514,7 +7537,7 @@ apply_typmod(NumericVar *var, int32 typmod)
|
|||||||
#error unsupported NBASE
|
#error unsupported NBASE
|
||||||
#endif
|
#endif
|
||||||
if (ddigits > maxdigits)
|
if (ddigits > maxdigits)
|
||||||
ereport(ERROR,
|
ereturn(escontext, false,
|
||||||
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
||||||
errmsg("numeric field overflow"),
|
errmsg("numeric field overflow"),
|
||||||
errdetail("A field with precision %d, scale %d must round to an absolute value less than %s%d.",
|
errdetail("A field with precision %d, scale %d must round to an absolute value less than %s%d.",
|
||||||
@ -7528,6 +7551,8 @@ apply_typmod(NumericVar *var, int32 typmod)
|
|||||||
ddigits -= DEC_DIGITS;
|
ddigits -= DEC_DIGITS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -7535,9 +7560,12 @@ apply_typmod(NumericVar *var, int32 typmod)
|
|||||||
*
|
*
|
||||||
* Do bounds checking according to the specified typmod, for an Inf or NaN.
|
* Do bounds checking according to the specified typmod, for an Inf or NaN.
|
||||||
* For convenience of most callers, the value is presented in packed form.
|
* For convenience of most callers, the value is presented in packed form.
|
||||||
|
*
|
||||||
|
* Returns true on success, false on failure (if escontext points to an
|
||||||
|
* ErrorSaveContext; otherwise errors are thrown).
|
||||||
*/
|
*/
|
||||||
static void
|
static bool
|
||||||
apply_typmod_special(Numeric num, int32 typmod)
|
apply_typmod_special(Numeric num, int32 typmod, Node *escontext)
|
||||||
{
|
{
|
||||||
int precision;
|
int precision;
|
||||||
int scale;
|
int scale;
|
||||||
@ -7551,16 +7579,16 @@ apply_typmod_special(Numeric num, int32 typmod)
|
|||||||
* any finite number of digits.
|
* any finite number of digits.
|
||||||
*/
|
*/
|
||||||
if (NUMERIC_IS_NAN(num))
|
if (NUMERIC_IS_NAN(num))
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
/* Do nothing if we have a default typmod (-1) */
|
/* Do nothing if we have a default typmod (-1) */
|
||||||
if (!is_valid_numeric_typmod(typmod))
|
if (!is_valid_numeric_typmod(typmod))
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
precision = numeric_typmod_precision(typmod);
|
precision = numeric_typmod_precision(typmod);
|
||||||
scale = numeric_typmod_scale(typmod);
|
scale = numeric_typmod_scale(typmod);
|
||||||
|
|
||||||
ereport(ERROR,
|
ereturn(escontext, false,
|
||||||
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
||||||
errmsg("numeric field overflow"),
|
errmsg("numeric field overflow"),
|
||||||
errdetail("A field with precision %d, scale %d cannot hold an infinite value.",
|
errdetail("A field with precision %d, scale %d cannot hold an infinite value.",
|
||||||
|
@ -88,15 +88,24 @@ decimalLength64(const uint64 v)
|
|||||||
/*
|
/*
|
||||||
* Convert input string to a signed 16 bit integer.
|
* Convert input string to a signed 16 bit integer.
|
||||||
*
|
*
|
||||||
* Allows any number of leading or trailing whitespace characters. Will throw
|
* Allows any number of leading or trailing whitespace characters.
|
||||||
* ereport() upon bad input format or overflow.
|
|
||||||
*
|
*
|
||||||
|
* pg_strtoint16() will throw ereport() upon bad input format or overflow;
|
||||||
|
* while pg_strtoint16_safe() instead returns such complaints in *escontext,
|
||||||
|
* if it's an ErrorSaveContext.
|
||||||
|
*
|
||||||
* NB: Accumulate input as an unsigned number, to deal with two's complement
|
* NB: Accumulate input as an unsigned number, to deal with two's complement
|
||||||
* representation of the most negative number, which can't be represented as a
|
* representation of the most negative number, which can't be represented as a
|
||||||
* signed positive number.
|
* signed positive number.
|
||||||
*/
|
*/
|
||||||
int16
|
int16
|
||||||
pg_strtoint16(const char *s)
|
pg_strtoint16(const char *s)
|
||||||
|
{
|
||||||
|
return pg_strtoint16_safe(s, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int16
|
||||||
|
pg_strtoint16_safe(const char *s, Node *escontext)
|
||||||
{
|
{
|
||||||
const char *ptr = s;
|
const char *ptr = s;
|
||||||
uint16 tmp = 0;
|
uint16 tmp = 0;
|
||||||
@ -149,25 +158,26 @@ pg_strtoint16(const char *s)
|
|||||||
return (int16) tmp;
|
return (int16) tmp;
|
||||||
|
|
||||||
out_of_range:
|
out_of_range:
|
||||||
ereport(ERROR,
|
ereturn(escontext, 0,
|
||||||
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
||||||
errmsg("value \"%s\" is out of range for type %s",
|
errmsg("value \"%s\" is out of range for type %s",
|
||||||
s, "smallint")));
|
s, "smallint")));
|
||||||
|
|
||||||
invalid_syntax:
|
invalid_syntax:
|
||||||
ereport(ERROR,
|
ereturn(escontext, 0,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("invalid input syntax for type %s: \"%s\"",
|
errmsg("invalid input syntax for type %s: \"%s\"",
|
||||||
"smallint", s)));
|
"smallint", s)));
|
||||||
|
|
||||||
return 0; /* keep compiler quiet */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert input string to a signed 32 bit integer.
|
* Convert input string to a signed 32 bit integer.
|
||||||
*
|
*
|
||||||
* Allows any number of leading or trailing whitespace characters. Will throw
|
* Allows any number of leading or trailing whitespace characters.
|
||||||
* ereport() upon bad input format or overflow.
|
*
|
||||||
|
* pg_strtoint32() will throw ereport() upon bad input format or overflow;
|
||||||
|
* while pg_strtoint32_safe() instead returns such complaints in *escontext,
|
||||||
|
* if it's an ErrorSaveContext.
|
||||||
*
|
*
|
||||||
* NB: Accumulate input as an unsigned number, to deal with two's complement
|
* NB: Accumulate input as an unsigned number, to deal with two's complement
|
||||||
* representation of the most negative number, which can't be represented as a
|
* representation of the most negative number, which can't be represented as a
|
||||||
@ -175,6 +185,12 @@ invalid_syntax:
|
|||||||
*/
|
*/
|
||||||
int32
|
int32
|
||||||
pg_strtoint32(const char *s)
|
pg_strtoint32(const char *s)
|
||||||
|
{
|
||||||
|
return pg_strtoint32_safe(s, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32
|
||||||
|
pg_strtoint32_safe(const char *s, Node *escontext)
|
||||||
{
|
{
|
||||||
const char *ptr = s;
|
const char *ptr = s;
|
||||||
uint32 tmp = 0;
|
uint32 tmp = 0;
|
||||||
@ -227,25 +243,26 @@ pg_strtoint32(const char *s)
|
|||||||
return (int32) tmp;
|
return (int32) tmp;
|
||||||
|
|
||||||
out_of_range:
|
out_of_range:
|
||||||
ereport(ERROR,
|
ereturn(escontext, 0,
|
||||||
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
||||||
errmsg("value \"%s\" is out of range for type %s",
|
errmsg("value \"%s\" is out of range for type %s",
|
||||||
s, "integer")));
|
s, "integer")));
|
||||||
|
|
||||||
invalid_syntax:
|
invalid_syntax:
|
||||||
ereport(ERROR,
|
ereturn(escontext, 0,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("invalid input syntax for type %s: \"%s\"",
|
errmsg("invalid input syntax for type %s: \"%s\"",
|
||||||
"integer", s)));
|
"integer", s)));
|
||||||
|
|
||||||
return 0; /* keep compiler quiet */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert input string to a signed 64 bit integer.
|
* Convert input string to a signed 64 bit integer.
|
||||||
*
|
*
|
||||||
* Allows any number of leading or trailing whitespace characters. Will throw
|
* Allows any number of leading or trailing whitespace characters.
|
||||||
* ereport() upon bad input format or overflow.
|
*
|
||||||
|
* pg_strtoint64() will throw ereport() upon bad input format or overflow;
|
||||||
|
* while pg_strtoint64_safe() instead returns such complaints in *escontext,
|
||||||
|
* if it's an ErrorSaveContext.
|
||||||
*
|
*
|
||||||
* NB: Accumulate input as an unsigned number, to deal with two's complement
|
* NB: Accumulate input as an unsigned number, to deal with two's complement
|
||||||
* representation of the most negative number, which can't be represented as a
|
* representation of the most negative number, which can't be represented as a
|
||||||
@ -253,6 +270,12 @@ invalid_syntax:
|
|||||||
*/
|
*/
|
||||||
int64
|
int64
|
||||||
pg_strtoint64(const char *s)
|
pg_strtoint64(const char *s)
|
||||||
|
{
|
||||||
|
return pg_strtoint64_safe(s, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64
|
||||||
|
pg_strtoint64_safe(const char *s, Node *escontext)
|
||||||
{
|
{
|
||||||
const char *ptr = s;
|
const char *ptr = s;
|
||||||
uint64 tmp = 0;
|
uint64 tmp = 0;
|
||||||
@ -305,18 +328,16 @@ pg_strtoint64(const char *s)
|
|||||||
return (int64) tmp;
|
return (int64) tmp;
|
||||||
|
|
||||||
out_of_range:
|
out_of_range:
|
||||||
ereport(ERROR,
|
ereturn(escontext, 0,
|
||||||
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
||||||
errmsg("value \"%s\" is out of range for type %s",
|
errmsg("value \"%s\" is out of range for type %s",
|
||||||
s, "bigint")));
|
s, "bigint")));
|
||||||
|
|
||||||
invalid_syntax:
|
invalid_syntax:
|
||||||
ereport(ERROR,
|
ereturn(escontext, 0,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("invalid input syntax for type %s: \"%s\"",
|
errmsg("invalid input syntax for type %s: \"%s\"",
|
||||||
"bigint", s)));
|
"bigint", s)));
|
||||||
|
|
||||||
return 0; /* keep compiler quiet */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -77,6 +77,7 @@ record_in(PG_FUNCTION_ARGS)
|
|||||||
char *string = PG_GETARG_CSTRING(0);
|
char *string = PG_GETARG_CSTRING(0);
|
||||||
Oid tupType = PG_GETARG_OID(1);
|
Oid tupType = PG_GETARG_OID(1);
|
||||||
int32 tupTypmod = PG_GETARG_INT32(2);
|
int32 tupTypmod = PG_GETARG_INT32(2);
|
||||||
|
Node *escontext = fcinfo->context;
|
||||||
HeapTupleHeader result;
|
HeapTupleHeader result;
|
||||||
TupleDesc tupdesc;
|
TupleDesc tupdesc;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
@ -100,7 +101,7 @@ record_in(PG_FUNCTION_ARGS)
|
|||||||
* supply a valid typmod, and then we can do something useful for RECORD.
|
* supply a valid typmod, and then we can do something useful for RECORD.
|
||||||
*/
|
*/
|
||||||
if (tupType == RECORDOID && tupTypmod < 0)
|
if (tupType == RECORDOID && tupTypmod < 0)
|
||||||
ereport(ERROR,
|
ereturn(escontext, (Datum) 0,
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
errmsg("input of anonymous composite types is not implemented")));
|
errmsg("input of anonymous composite types is not implemented")));
|
||||||
|
|
||||||
@ -152,10 +153,13 @@ record_in(PG_FUNCTION_ARGS)
|
|||||||
while (*ptr && isspace((unsigned char) *ptr))
|
while (*ptr && isspace((unsigned char) *ptr))
|
||||||
ptr++;
|
ptr++;
|
||||||
if (*ptr++ != '(')
|
if (*ptr++ != '(')
|
||||||
ereport(ERROR,
|
{
|
||||||
|
errsave(escontext,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed record literal: \"%s\"", string),
|
errmsg("malformed record literal: \"%s\"", string),
|
||||||
errdetail("Missing left parenthesis.")));
|
errdetail("Missing left parenthesis.")));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
initStringInfo(&buf);
|
initStringInfo(&buf);
|
||||||
|
|
||||||
@ -181,10 +185,13 @@ record_in(PG_FUNCTION_ARGS)
|
|||||||
ptr++;
|
ptr++;
|
||||||
else
|
else
|
||||||
/* *ptr must be ')' */
|
/* *ptr must be ')' */
|
||||||
ereport(ERROR,
|
{
|
||||||
|
errsave(escontext,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed record literal: \"%s\"", string),
|
errmsg("malformed record literal: \"%s\"", string),
|
||||||
errdetail("Too few columns.")));
|
errdetail("Too few columns.")));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for null: completely empty input means null */
|
/* Check for null: completely empty input means null */
|
||||||
@ -204,19 +211,25 @@ record_in(PG_FUNCTION_ARGS)
|
|||||||
char ch = *ptr++;
|
char ch = *ptr++;
|
||||||
|
|
||||||
if (ch == '\0')
|
if (ch == '\0')
|
||||||
ereport(ERROR,
|
{
|
||||||
|
errsave(escontext,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed record literal: \"%s\"",
|
errmsg("malformed record literal: \"%s\"",
|
||||||
string),
|
string),
|
||||||
errdetail("Unexpected end of input.")));
|
errdetail("Unexpected end of input.")));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
if (ch == '\\')
|
if (ch == '\\')
|
||||||
{
|
{
|
||||||
if (*ptr == '\0')
|
if (*ptr == '\0')
|
||||||
ereport(ERROR,
|
{
|
||||||
|
errsave(escontext,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed record literal: \"%s\"",
|
errmsg("malformed record literal: \"%s\"",
|
||||||
string),
|
string),
|
||||||
errdetail("Unexpected end of input.")));
|
errdetail("Unexpected end of input.")));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
appendStringInfoChar(&buf, *ptr++);
|
appendStringInfoChar(&buf, *ptr++);
|
||||||
}
|
}
|
||||||
else if (ch == '"')
|
else if (ch == '"')
|
||||||
@ -252,10 +265,13 @@ record_in(PG_FUNCTION_ARGS)
|
|||||||
column_info->column_type = column_type;
|
column_info->column_type = column_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
values[i] = InputFunctionCall(&column_info->proc,
|
if (!InputFunctionCallSafe(&column_info->proc,
|
||||||
column_data,
|
column_data,
|
||||||
column_info->typioparam,
|
column_info->typioparam,
|
||||||
att->atttypmod);
|
att->atttypmod,
|
||||||
|
escontext,
|
||||||
|
&values[i]))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prep for next column
|
* Prep for next column
|
||||||
@ -264,18 +280,24 @@ record_in(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (*ptr++ != ')')
|
if (*ptr++ != ')')
|
||||||
ereport(ERROR,
|
{
|
||||||
|
errsave(escontext,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed record literal: \"%s\"", string),
|
errmsg("malformed record literal: \"%s\"", string),
|
||||||
errdetail("Too many columns.")));
|
errdetail("Too many columns.")));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
/* Allow trailing whitespace */
|
/* Allow trailing whitespace */
|
||||||
while (*ptr && isspace((unsigned char) *ptr))
|
while (*ptr && isspace((unsigned char) *ptr))
|
||||||
ptr++;
|
ptr++;
|
||||||
if (*ptr)
|
if (*ptr)
|
||||||
ereport(ERROR,
|
{
|
||||||
|
errsave(escontext,
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
errmsg("malformed record literal: \"%s\"", string),
|
errmsg("malformed record literal: \"%s\"", string),
|
||||||
errdetail("Junk after right parenthesis.")));
|
errdetail("Junk after right parenthesis.")));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
tuple = heap_form_tuple(tupdesc, values, nulls);
|
tuple = heap_form_tuple(tupdesc, values, nulls);
|
||||||
|
|
||||||
@ -294,6 +316,11 @@ record_in(PG_FUNCTION_ARGS)
|
|||||||
ReleaseTupleDesc(tupdesc);
|
ReleaseTupleDesc(tupdesc);
|
||||||
|
|
||||||
PG_RETURN_HEAPTUPLEHEADER(result);
|
PG_RETURN_HEAPTUPLEHEADER(result);
|
||||||
|
|
||||||
|
/* exit here once we've done lookup_rowtype_tupdesc */
|
||||||
|
fail:
|
||||||
|
ReleaseTupleDesc(tupdesc);
|
||||||
|
PG_RETURN_NULL();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -447,7 +447,11 @@ extern void array_free_iterator(ArrayIterator iterator);
|
|||||||
extern int ArrayGetOffset(int n, const int *dim, const int *lb, const int *indx);
|
extern int ArrayGetOffset(int n, const int *dim, const int *lb, const int *indx);
|
||||||
extern int ArrayGetOffset0(int n, const int *tup, const int *scale);
|
extern int ArrayGetOffset0(int n, const int *tup, const int *scale);
|
||||||
extern int ArrayGetNItems(int ndim, const int *dims);
|
extern int ArrayGetNItems(int ndim, const int *dims);
|
||||||
|
extern int ArrayGetNItemsSafe(int ndim, const int *dims,
|
||||||
|
struct Node *escontext);
|
||||||
extern void ArrayCheckBounds(int ndim, const int *dims, const int *lb);
|
extern void ArrayCheckBounds(int ndim, const int *dims, const int *lb);
|
||||||
|
extern bool ArrayCheckBoundsSafe(int ndim, const int *dims, const int *lb,
|
||||||
|
struct Node *escontext);
|
||||||
extern void mda_get_range(int n, int *span, const int *st, const int *endp);
|
extern void mda_get_range(int n, int *span, const int *st, const int *endp);
|
||||||
extern void mda_get_prod(int n, const int *range, int *prod);
|
extern void mda_get_prod(int n, const int *range, int *prod);
|
||||||
extern void mda_get_offset_values(int n, int *dist, const int *prod, const int *span);
|
extern void mda_get_offset_values(int n, int *dist, const int *prod, const int *span);
|
||||||
|
@ -44,8 +44,11 @@ extern int namestrcmp(Name name, const char *str);
|
|||||||
|
|
||||||
/* numutils.c */
|
/* numutils.c */
|
||||||
extern int16 pg_strtoint16(const char *s);
|
extern int16 pg_strtoint16(const char *s);
|
||||||
|
extern int16 pg_strtoint16_safe(const char *s, Node *escontext);
|
||||||
extern int32 pg_strtoint32(const char *s);
|
extern int32 pg_strtoint32(const char *s);
|
||||||
|
extern int32 pg_strtoint32_safe(const char *s, Node *escontext);
|
||||||
extern int64 pg_strtoint64(const char *s);
|
extern int64 pg_strtoint64(const char *s);
|
||||||
|
extern int64 pg_strtoint64_safe(const char *s, Node *escontext);
|
||||||
extern int pg_itoa(int16 i, char *a);
|
extern int pg_itoa(int16 i, char *a);
|
||||||
extern int pg_ultoa_n(uint32 value, char *a);
|
extern int pg_ultoa_n(uint32 value, char *a);
|
||||||
extern int pg_ulltoa_n(uint64 value, char *a);
|
extern int pg_ulltoa_n(uint64 value, char *a);
|
||||||
|
@ -42,10 +42,8 @@ extern void float_underflow_error(void) pg_attribute_noreturn();
|
|||||||
extern void float_zero_divide_error(void) pg_attribute_noreturn();
|
extern void float_zero_divide_error(void) pg_attribute_noreturn();
|
||||||
extern int is_infinite(float8 val);
|
extern int is_infinite(float8 val);
|
||||||
extern float8 float8in_internal(char *num, char **endptr_p,
|
extern float8 float8in_internal(char *num, char **endptr_p,
|
||||||
const char *type_name, const char *orig_string);
|
const char *type_name, const char *orig_string,
|
||||||
extern float8 float8in_internal_opt_error(char *num, char **endptr_p,
|
struct Node *escontext);
|
||||||
const char *type_name, const char *orig_string,
|
|
||||||
bool *have_error);
|
|
||||||
extern char *float8out_internal(float8 num);
|
extern char *float8out_internal(float8 num);
|
||||||
extern int float4_cmp_internal(float4 a, float4 b);
|
extern int float4_cmp_internal(float4 a, float4 b);
|
||||||
extern int float8_cmp_internal(float8 a, float8 b);
|
extern int float8_cmp_internal(float8 a, float8 b);
|
||||||
|
@ -182,6 +182,31 @@ SELECT a,b,c FROM arrtest;
|
|||||||
[4:4]={NULL} | {3,4} | {foo,new_word}
|
[4:4]={NULL} | {3,4} | {foo,new_word}
|
||||||
(3 rows)
|
(3 rows)
|
||||||
|
|
||||||
|
-- test non-error-throwing API
|
||||||
|
SELECT pg_input_is_valid('{1,2,3}', 'integer[]');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_is_valid('{1,2', 'integer[]');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_is_valid('{1,zed}', 'integer[]');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_error_message('{1,zed}', 'integer[]');
|
||||||
|
pg_input_error_message
|
||||||
|
----------------------------------------------
|
||||||
|
invalid input syntax for type integer: "zed"
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- test mixed slice/scalar subscripting
|
-- test mixed slice/scalar subscripting
|
||||||
select '{{1,2,3},{4,5,6},{7,8,9}}'::int[];
|
select '{{1,2,3},{4,5,6},{7,8,9}}'::int[];
|
||||||
int4
|
int4
|
||||||
|
@ -142,6 +142,25 @@ SELECT bool '' AS error;
|
|||||||
ERROR: invalid input syntax for type boolean: ""
|
ERROR: invalid input syntax for type boolean: ""
|
||||||
LINE 1: SELECT bool '' AS error;
|
LINE 1: SELECT bool '' AS error;
|
||||||
^
|
^
|
||||||
|
-- Also try it with non-error-throwing API
|
||||||
|
SELECT pg_input_is_valid('true', 'bool');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_is_valid('asdf', 'bool');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_error_message('junk', 'bool');
|
||||||
|
pg_input_error_message
|
||||||
|
-----------------------------------------------
|
||||||
|
invalid input syntax for type boolean: "junk"
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- and, or, not in qualifications
|
-- and, or, not in qualifications
|
||||||
SELECT bool 't' or bool 'f' AS true;
|
SELECT bool 't' or bool 'f' AS true;
|
||||||
true
|
true
|
||||||
|
@ -81,6 +81,31 @@ INSERT INTO FLOAT4_TBL(f1) VALUES ('123 5');
|
|||||||
ERROR: invalid input syntax for type real: "123 5"
|
ERROR: invalid input syntax for type real: "123 5"
|
||||||
LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('123 5');
|
LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('123 5');
|
||||||
^
|
^
|
||||||
|
-- Also try it with non-error-throwing API
|
||||||
|
SELECT pg_input_is_valid('34.5', 'float4');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_is_valid('xyz', 'float4');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_is_valid('1e400', 'float4');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_error_message('1e400', 'float4');
|
||||||
|
pg_input_error_message
|
||||||
|
---------------------------------------
|
||||||
|
"1e400" is out of range for type real
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- special inputs
|
-- special inputs
|
||||||
SELECT 'NaN'::float4;
|
SELECT 'NaN'::float4;
|
||||||
float4
|
float4
|
||||||
|
@ -81,6 +81,31 @@ INSERT INTO FLOAT4_TBL(f1) VALUES ('123 5');
|
|||||||
ERROR: invalid input syntax for type real: "123 5"
|
ERROR: invalid input syntax for type real: "123 5"
|
||||||
LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('123 5');
|
LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('123 5');
|
||||||
^
|
^
|
||||||
|
-- Also try it with non-error-throwing API
|
||||||
|
SELECT pg_input_is_valid('34.5', 'float4');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_is_valid('xyz', 'float4');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_is_valid('1e400', 'float4');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_error_message('1e400', 'float4');
|
||||||
|
pg_input_error_message
|
||||||
|
---------------------------------------
|
||||||
|
"1e400" is out of range for type real
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- special inputs
|
-- special inputs
|
||||||
SELECT 'NaN'::float4;
|
SELECT 'NaN'::float4;
|
||||||
float4
|
float4
|
||||||
|
@ -68,6 +68,31 @@ INSERT INTO FLOAT8_TBL(f1) VALUES ('123 5');
|
|||||||
ERROR: invalid input syntax for type double precision: "123 5"
|
ERROR: invalid input syntax for type double precision: "123 5"
|
||||||
LINE 1: INSERT INTO FLOAT8_TBL(f1) VALUES ('123 5');
|
LINE 1: INSERT INTO FLOAT8_TBL(f1) VALUES ('123 5');
|
||||||
^
|
^
|
||||||
|
-- Also try it with non-error-throwing API
|
||||||
|
SELECT pg_input_is_valid('34.5', 'float8');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_is_valid('xyz', 'float8');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_is_valid('1e4000', 'float8');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_error_message('1e4000', 'float8');
|
||||||
|
pg_input_error_message
|
||||||
|
----------------------------------------------------
|
||||||
|
"1e4000" is out of range for type double precision
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- special inputs
|
-- special inputs
|
||||||
SELECT 'NaN'::float8;
|
SELECT 'NaN'::float8;
|
||||||
float8
|
float8
|
||||||
|
@ -45,6 +45,31 @@ SELECT * FROM INT2_TBL;
|
|||||||
-32767
|
-32767
|
||||||
(5 rows)
|
(5 rows)
|
||||||
|
|
||||||
|
-- Also try it with non-error-throwing API
|
||||||
|
SELECT pg_input_is_valid('34', 'int2');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_is_valid('asdf', 'int2');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_is_valid('50000', 'int2');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_error_message('50000', 'int2');
|
||||||
|
pg_input_error_message
|
||||||
|
-------------------------------------------------
|
||||||
|
value "50000" is out of range for type smallint
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT * FROM INT2_TBL AS f(a, b);
|
SELECT * FROM INT2_TBL AS f(a, b);
|
||||||
ERROR: table "f" has 1 columns available but 2 columns specified
|
ERROR: table "f" has 1 columns available but 2 columns specified
|
||||||
SELECT * FROM (TABLE int2_tbl) AS s (a, b);
|
SELECT * FROM (TABLE int2_tbl) AS s (a, b);
|
||||||
|
@ -45,6 +45,31 @@ SELECT * FROM INT4_TBL;
|
|||||||
-2147483647
|
-2147483647
|
||||||
(5 rows)
|
(5 rows)
|
||||||
|
|
||||||
|
-- Also try it with non-error-throwing API
|
||||||
|
SELECT pg_input_is_valid('34', 'int4');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_is_valid('asdf', 'int4');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_is_valid('1000000000000', 'int4');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_error_message('1000000000000', 'int4');
|
||||||
|
pg_input_error_message
|
||||||
|
--------------------------------------------------------
|
||||||
|
value "1000000000000" is out of range for type integer
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT i.* FROM INT4_TBL i WHERE i.f1 <> int2 '0';
|
SELECT i.* FROM INT4_TBL i WHERE i.f1 <> int2 '0';
|
||||||
f1
|
f1
|
||||||
-------------
|
-------------
|
||||||
|
@ -42,6 +42,31 @@ SELECT * FROM INT8_TBL;
|
|||||||
4567890123456789 | -4567890123456789
|
4567890123456789 | -4567890123456789
|
||||||
(5 rows)
|
(5 rows)
|
||||||
|
|
||||||
|
-- Also try it with non-error-throwing API
|
||||||
|
SELECT pg_input_is_valid('34', 'int8');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_is_valid('asdf', 'int8');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_is_valid('10000000000000000000', 'int8');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_error_message('10000000000000000000', 'int8');
|
||||||
|
pg_input_error_message
|
||||||
|
--------------------------------------------------------------
|
||||||
|
value "10000000000000000000" is out of range for type bigint
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- int8/int8 cmp
|
-- int8/int8 cmp
|
||||||
SELECT * FROM INT8_TBL WHERE q2 = 4567890123456789;
|
SELECT * FROM INT8_TBL WHERE q2 = 4567890123456789;
|
||||||
q1 | q2
|
q1 | q2
|
||||||
|
@ -2199,6 +2199,49 @@ SELECT * FROM num_input_test;
|
|||||||
-Infinity
|
-Infinity
|
||||||
(13 rows)
|
(13 rows)
|
||||||
|
|
||||||
|
-- Also try it with non-error-throwing API
|
||||||
|
SELECT pg_input_is_valid('34.5', 'numeric');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_is_valid('34xyz', 'numeric');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_is_valid('1e400000', 'numeric');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_error_message('1e400000', 'numeric');
|
||||||
|
pg_input_error_message
|
||||||
|
--------------------------------
|
||||||
|
value overflows numeric format
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_is_valid('1234.567', 'numeric(8,4)');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_is_valid('1234.567', 'numeric(7,4)');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_error_message('1234.567', 'numeric(7,4)');
|
||||||
|
pg_input_error_message
|
||||||
|
------------------------
|
||||||
|
numeric field overflow
|
||||||
|
(1 row)
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Test precision and scale typemods
|
-- Test precision and scale typemods
|
||||||
--
|
--
|
||||||
|
@ -69,6 +69,37 @@ ERROR: malformed record literal: "(Joe,Blow) /"
|
|||||||
LINE 1: select '(Joe,Blow) /'::fullname;
|
LINE 1: select '(Joe,Blow) /'::fullname;
|
||||||
^
|
^
|
||||||
DETAIL: Junk after right parenthesis.
|
DETAIL: Junk after right parenthesis.
|
||||||
|
-- test non-error-throwing API
|
||||||
|
SELECT pg_input_is_valid('(1,2)', 'complex');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_is_valid('(1,2', 'complex');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_is_valid('(1,zed)', 'complex');
|
||||||
|
pg_input_is_valid
|
||||||
|
-------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_error_message('(1,zed)', 'complex');
|
||||||
|
pg_input_error_message
|
||||||
|
-------------------------------------------------------
|
||||||
|
invalid input syntax for type double precision: "zed"
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_input_error_message('(1,1e400)', 'complex');
|
||||||
|
pg_input_error_message
|
||||||
|
---------------------------------------------------
|
||||||
|
"1e400" is out of range for type double precision
|
||||||
|
(1 row)
|
||||||
|
|
||||||
create temp table quadtable(f1 int, q quad);
|
create temp table quadtable(f1 int, q quad);
|
||||||
insert into quadtable values (1, ((3.3,4.4),(5.5,6.6)));
|
insert into quadtable values (1, ((3.3,4.4),(5.5,6.6)));
|
||||||
insert into quadtable values (2, ((null,4.4),(5.5,6.6)));
|
insert into quadtable values (2, ((null,4.4),(5.5,6.6)));
|
||||||
|
@ -113,6 +113,12 @@ SELECT a FROM arrtest WHERE a[2] IS NULL;
|
|||||||
DELETE FROM arrtest WHERE a[2] IS NULL AND b IS NULL;
|
DELETE FROM arrtest WHERE a[2] IS NULL AND b IS NULL;
|
||||||
SELECT a,b,c FROM arrtest;
|
SELECT a,b,c FROM arrtest;
|
||||||
|
|
||||||
|
-- test non-error-throwing API
|
||||||
|
SELECT pg_input_is_valid('{1,2,3}', 'integer[]');
|
||||||
|
SELECT pg_input_is_valid('{1,2', 'integer[]');
|
||||||
|
SELECT pg_input_is_valid('{1,zed}', 'integer[]');
|
||||||
|
SELECT pg_input_error_message('{1,zed}', 'integer[]');
|
||||||
|
|
||||||
-- test mixed slice/scalar subscripting
|
-- test mixed slice/scalar subscripting
|
||||||
select '{{1,2,3},{4,5,6},{7,8,9}}'::int[];
|
select '{{1,2,3},{4,5,6},{7,8,9}}'::int[];
|
||||||
select ('{{1,2,3},{4,5,6},{7,8,9}}'::int[])[1:2][2];
|
select ('{{1,2,3},{4,5,6},{7,8,9}}'::int[])[1:2][2];
|
||||||
|
@ -62,6 +62,11 @@ SELECT bool '000' AS error;
|
|||||||
|
|
||||||
SELECT bool '' AS error;
|
SELECT bool '' AS error;
|
||||||
|
|
||||||
|
-- Also try it with non-error-throwing API
|
||||||
|
SELECT pg_input_is_valid('true', 'bool');
|
||||||
|
SELECT pg_input_is_valid('asdf', 'bool');
|
||||||
|
SELECT pg_input_error_message('junk', 'bool');
|
||||||
|
|
||||||
-- and, or, not in qualifications
|
-- and, or, not in qualifications
|
||||||
|
|
||||||
SELECT bool 't' or bool 'f' AS true;
|
SELECT bool 't' or bool 'f' AS true;
|
||||||
|
@ -36,6 +36,12 @@ INSERT INTO FLOAT4_TBL(f1) VALUES ('5. 0');
|
|||||||
INSERT INTO FLOAT4_TBL(f1) VALUES (' - 3.0');
|
INSERT INTO FLOAT4_TBL(f1) VALUES (' - 3.0');
|
||||||
INSERT INTO FLOAT4_TBL(f1) VALUES ('123 5');
|
INSERT INTO FLOAT4_TBL(f1) VALUES ('123 5');
|
||||||
|
|
||||||
|
-- Also try it with non-error-throwing API
|
||||||
|
SELECT pg_input_is_valid('34.5', 'float4');
|
||||||
|
SELECT pg_input_is_valid('xyz', 'float4');
|
||||||
|
SELECT pg_input_is_valid('1e400', 'float4');
|
||||||
|
SELECT pg_input_error_message('1e400', 'float4');
|
||||||
|
|
||||||
-- special inputs
|
-- special inputs
|
||||||
SELECT 'NaN'::float4;
|
SELECT 'NaN'::float4;
|
||||||
SELECT 'nan'::float4;
|
SELECT 'nan'::float4;
|
||||||
|
@ -34,6 +34,12 @@ INSERT INTO FLOAT8_TBL(f1) VALUES ('5. 0');
|
|||||||
INSERT INTO FLOAT8_TBL(f1) VALUES (' - 3');
|
INSERT INTO FLOAT8_TBL(f1) VALUES (' - 3');
|
||||||
INSERT INTO FLOAT8_TBL(f1) VALUES ('123 5');
|
INSERT INTO FLOAT8_TBL(f1) VALUES ('123 5');
|
||||||
|
|
||||||
|
-- Also try it with non-error-throwing API
|
||||||
|
SELECT pg_input_is_valid('34.5', 'float8');
|
||||||
|
SELECT pg_input_is_valid('xyz', 'float8');
|
||||||
|
SELECT pg_input_is_valid('1e4000', 'float8');
|
||||||
|
SELECT pg_input_error_message('1e4000', 'float8');
|
||||||
|
|
||||||
-- special inputs
|
-- special inputs
|
||||||
SELECT 'NaN'::float8;
|
SELECT 'NaN'::float8;
|
||||||
SELECT 'nan'::float8;
|
SELECT 'nan'::float8;
|
||||||
|
@ -17,6 +17,12 @@ INSERT INTO INT2_TBL(f1) VALUES ('');
|
|||||||
|
|
||||||
SELECT * FROM INT2_TBL;
|
SELECT * FROM INT2_TBL;
|
||||||
|
|
||||||
|
-- Also try it with non-error-throwing API
|
||||||
|
SELECT pg_input_is_valid('34', 'int2');
|
||||||
|
SELECT pg_input_is_valid('asdf', 'int2');
|
||||||
|
SELECT pg_input_is_valid('50000', 'int2');
|
||||||
|
SELECT pg_input_error_message('50000', 'int2');
|
||||||
|
|
||||||
SELECT * FROM INT2_TBL AS f(a, b);
|
SELECT * FROM INT2_TBL AS f(a, b);
|
||||||
|
|
||||||
SELECT * FROM (TABLE int2_tbl) AS s (a, b);
|
SELECT * FROM (TABLE int2_tbl) AS s (a, b);
|
||||||
|
@ -17,6 +17,12 @@ INSERT INTO INT4_TBL(f1) VALUES ('');
|
|||||||
|
|
||||||
SELECT * FROM INT4_TBL;
|
SELECT * FROM INT4_TBL;
|
||||||
|
|
||||||
|
-- Also try it with non-error-throwing API
|
||||||
|
SELECT pg_input_is_valid('34', 'int4');
|
||||||
|
SELECT pg_input_is_valid('asdf', 'int4');
|
||||||
|
SELECT pg_input_is_valid('1000000000000', 'int4');
|
||||||
|
SELECT pg_input_error_message('1000000000000', 'int4');
|
||||||
|
|
||||||
SELECT i.* FROM INT4_TBL i WHERE i.f1 <> int2 '0';
|
SELECT i.* FROM INT4_TBL i WHERE i.f1 <> int2 '0';
|
||||||
|
|
||||||
SELECT i.* FROM INT4_TBL i WHERE i.f1 <> int4 '0';
|
SELECT i.* FROM INT4_TBL i WHERE i.f1 <> int4 '0';
|
||||||
|
@ -16,6 +16,12 @@ INSERT INTO INT8_TBL(q1) VALUES ('');
|
|||||||
|
|
||||||
SELECT * FROM INT8_TBL;
|
SELECT * FROM INT8_TBL;
|
||||||
|
|
||||||
|
-- Also try it with non-error-throwing API
|
||||||
|
SELECT pg_input_is_valid('34', 'int8');
|
||||||
|
SELECT pg_input_is_valid('asdf', 'int8');
|
||||||
|
SELECT pg_input_is_valid('10000000000000000000', 'int8');
|
||||||
|
SELECT pg_input_error_message('10000000000000000000', 'int8');
|
||||||
|
|
||||||
-- int8/int8 cmp
|
-- int8/int8 cmp
|
||||||
SELECT * FROM INT8_TBL WHERE q2 = 4567890123456789;
|
SELECT * FROM INT8_TBL WHERE q2 = 4567890123456789;
|
||||||
SELECT * FROM INT8_TBL WHERE q2 <> 4567890123456789;
|
SELECT * FROM INT8_TBL WHERE q2 <> 4567890123456789;
|
||||||
|
@ -1053,6 +1053,15 @@ INSERT INTO num_input_test(n1) VALUES ('+ infinity');
|
|||||||
|
|
||||||
SELECT * FROM num_input_test;
|
SELECT * FROM num_input_test;
|
||||||
|
|
||||||
|
-- Also try it with non-error-throwing API
|
||||||
|
SELECT pg_input_is_valid('34.5', 'numeric');
|
||||||
|
SELECT pg_input_is_valid('34xyz', 'numeric');
|
||||||
|
SELECT pg_input_is_valid('1e400000', 'numeric');
|
||||||
|
SELECT pg_input_error_message('1e400000', 'numeric');
|
||||||
|
SELECT pg_input_is_valid('1234.567', 'numeric(8,4)');
|
||||||
|
SELECT pg_input_is_valid('1234.567', 'numeric(7,4)');
|
||||||
|
SELECT pg_input_error_message('1234.567', 'numeric(7,4)');
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Test precision and scale typemods
|
-- Test precision and scale typemods
|
||||||
--
|
--
|
||||||
|
@ -31,6 +31,13 @@ select '[]'::fullname; -- bad
|
|||||||
select ' (Joe,Blow) '::fullname; -- ok, extra whitespace
|
select ' (Joe,Blow) '::fullname; -- ok, extra whitespace
|
||||||
select '(Joe,Blow) /'::fullname; -- bad
|
select '(Joe,Blow) /'::fullname; -- bad
|
||||||
|
|
||||||
|
-- test non-error-throwing API
|
||||||
|
SELECT pg_input_is_valid('(1,2)', 'complex');
|
||||||
|
SELECT pg_input_is_valid('(1,2', 'complex');
|
||||||
|
SELECT pg_input_is_valid('(1,zed)', 'complex');
|
||||||
|
SELECT pg_input_error_message('(1,zed)', 'complex');
|
||||||
|
SELECT pg_input_error_message('(1,1e400)', 'complex');
|
||||||
|
|
||||||
create temp table quadtable(f1 int, q quad);
|
create temp table quadtable(f1 int, q quad);
|
||||||
|
|
||||||
insert into quadtable values (1, ((3.3,4.4),(5.5,6.6)));
|
insert into quadtable values (1, ((3.3,4.4),(5.5,6.6)));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user