Skip to content

Commit 47f3f97

Browse files
committed
Convert a few more datatype input functions to report errors softly.
Convert assorted internal-ish datatypes, namely aclitemin, int2vectorin, oidin, oidvectorin, pg_lsn_in, pg_snapshot_in, and tidin to the new style. (Some others you might expect to find in this group, such as cidin and xidin, need no changes because they never throw errors at all. That seems a little cheesy ... but it is not in the charter of this patch series to add new error conditions.) Amul Sul, minor mods by me Discussion: https://postgr.es/m/CAAJ_b97KeDWUdpTKGOaFYPv0OicjOu6EW+QYWj-Ywrgj_aEy1g@mail.gmail.com
1 parent 332741e commit 47f3f97

File tree

18 files changed

+323
-41
lines changed

18 files changed

+323
-41
lines changed

src/backend/utils/adt/acl.c

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,11 @@ static List *cached_roles[] = {NIL, NIL, NIL};
8181
static uint32 cached_db_hash;
8282

8383

84-
static const char *getid(const char *s, char *n);
84+
static const char *getid(const char *s, char *n, Node *escontext);
8585
static void putid(char *p, const char *s);
8686
static Acl *allocacl(int n);
8787
static void check_acl(const Acl *acl);
88-
static const char *aclparse(const char *s, AclItem *aip);
88+
static const char *aclparse(const char *s, AclItem *aip, Node *escontext);
8989
static bool aclitem_match(const AclItem *a1, const AclItem *a2);
9090
static int aclitemComparator(const void *arg1, const void *arg2);
9191
static void check_circularity(const Acl *old_acl, const AclItem *mod_aip,
@@ -135,9 +135,12 @@ static void RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue
135135
* in 's', after any quotes. Also:
136136
* - loads the identifier into 'n'. (If no identifier is found, 'n'
137137
* contains an empty string.) 'n' must be NAMEDATALEN bytes.
138+
*
139+
* Errors are reported via ereport, unless escontext is an ErrorSaveData node,
140+
* in which case we log the error there and return NULL.
138141
*/
139142
static const char *
140-
getid(const char *s, char *n)
143+
getid(const char *s, char *n, Node *escontext)
141144
{
142145
int len = 0;
143146
bool in_quotes = false;
@@ -169,7 +172,7 @@ getid(const char *s, char *n)
169172

170173
/* Add the character to the string */
171174
if (len >= NAMEDATALEN - 1)
172-
ereport(ERROR,
175+
ereturn(escontext, NULL,
173176
(errcode(ERRCODE_NAME_TOO_LONG),
174177
errmsg("identifier too long"),
175178
errdetail("Identifier must be less than %d characters.",
@@ -236,9 +239,12 @@ putid(char *p, const char *s)
236239
* specification. Also:
237240
* - loads the structure pointed to by 'aip' with the appropriate
238241
* UID/GID, id type identifier and mode type values.
242+
*
243+
* Errors are reported via ereport, unless escontext is an ErrorSaveData node,
244+
* in which case we log the error there and return NULL.
239245
*/
240246
static const char *
241-
aclparse(const char *s, AclItem *aip)
247+
aclparse(const char *s, AclItem *aip, Node *escontext)
242248
{
243249
AclMode privs,
244250
goption,
@@ -248,25 +254,30 @@ aclparse(const char *s, AclItem *aip)
248254

249255
Assert(s && aip);
250256

251-
s = getid(s, name);
257+
s = getid(s, name, escontext);
258+
if (s == NULL)
259+
return NULL;
252260
if (*s != '=')
253261
{
254262
/* we just read a keyword, not a name */
255263
if (strcmp(name, "group") != 0 && strcmp(name, "user") != 0)
256-
ereport(ERROR,
264+
ereturn(escontext, NULL,
257265
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
258266
errmsg("unrecognized key word: \"%s\"", name),
259267
errhint("ACL key word must be \"group\" or \"user\".")));
260-
s = getid(s, name); /* move s to the name beyond the keyword */
268+
/* move s to the name beyond the keyword */
269+
s = getid(s, name, escontext);
270+
if (s == NULL)
271+
return NULL;
261272
if (name[0] == '\0')
262-
ereport(ERROR,
273+
ereturn(escontext, NULL,
263274
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
264275
errmsg("missing name"),
265276
errhint("A name must follow the \"group\" or \"user\" key word.")));
266277
}
267278

268279
if (*s != '=')
269-
ereport(ERROR,
280+
ereturn(escontext, NULL,
270281
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
271282
errmsg("missing \"=\" sign")));
272283

@@ -328,7 +339,7 @@ aclparse(const char *s, AclItem *aip)
328339
read = 0;
329340
break;
330341
default:
331-
ereport(ERROR,
342+
ereturn(escontext, NULL,
332343
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
333344
errmsg("invalid mode character: must be one of \"%s\"",
334345
ACL_ALL_RIGHTS_STR)));
@@ -340,20 +351,32 @@ aclparse(const char *s, AclItem *aip)
340351
if (name[0] == '\0')
341352
aip->ai_grantee = ACL_ID_PUBLIC;
342353
else
343-
aip->ai_grantee = get_role_oid(name, false);
354+
{
355+
aip->ai_grantee = get_role_oid(name, true);
356+
if (!OidIsValid(aip->ai_grantee))
357+
ereturn(escontext, NULL,
358+
(errcode(ERRCODE_UNDEFINED_OBJECT),
359+
errmsg("role \"%s\" does not exist", name)));
360+
}
344361

345362
/*
346363
* XXX Allow a degree of backward compatibility by defaulting the grantor
347364
* to the superuser.
348365
*/
349366
if (*s == '/')
350367
{
351-
s = getid(s + 1, name2);
368+
s = getid(s + 1, name2, escontext);
369+
if (s == NULL)
370+
return NULL;
352371
if (name2[0] == '\0')
353-
ereport(ERROR,
372+
ereturn(escontext, NULL,
354373
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
355374
errmsg("a name must follow the \"/\" sign")));
356-
aip->ai_grantor = get_role_oid(name2, false);
375+
aip->ai_grantor = get_role_oid(name2, true);
376+
if (!OidIsValid(aip->ai_grantor))
377+
ereturn(escontext, NULL,
378+
(errcode(ERRCODE_UNDEFINED_OBJECT),
379+
errmsg("role \"%s\" does not exist", name2)));
357380
}
358381
else
359382
{
@@ -569,14 +592,19 @@ Datum
569592
aclitemin(PG_FUNCTION_ARGS)
570593
{
571594
const char *s = PG_GETARG_CSTRING(0);
595+
Node *escontext = fcinfo->context;
572596
AclItem *aip;
573597

574598
aip = (AclItem *) palloc(sizeof(AclItem));
575-
s = aclparse(s, aip);
599+
600+
s = aclparse(s, aip, escontext);
601+
if (s == NULL)
602+
PG_RETURN_NULL();
603+
576604
while (isspace((unsigned char) *s))
577605
++s;
578606
if (*s)
579-
ereport(ERROR,
607+
ereturn(escontext, (Datum) 0,
580608
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
581609
errmsg("extra garbage at the end of the ACL specification")));
582610

src/backend/utils/adt/int.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ Datum
141141
int2vectorin(PG_FUNCTION_ARGS)
142142
{
143143
char *intString = PG_GETARG_CSTRING(0);
144+
Node *escontext = fcinfo->context;
144145
int2vector *result;
145146
int n;
146147

@@ -160,19 +161,19 @@ int2vectorin(PG_FUNCTION_ARGS)
160161
l = strtol(intString, &endp, 10);
161162

162163
if (intString == endp)
163-
ereport(ERROR,
164+
ereturn(escontext, (Datum) 0,
164165
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
165166
errmsg("invalid input syntax for type %s: \"%s\"",
166167
"smallint", intString)));
167168

168169
if (errno == ERANGE || l < SHRT_MIN || l > SHRT_MAX)
169-
ereport(ERROR,
170+
ereturn(escontext, (Datum) 0,
170171
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
171172
errmsg("value \"%s\" is out of range for type %s", intString,
172173
"smallint")));
173174

174175
if (*endp && *endp != ' ')
175-
ereport(ERROR,
176+
ereturn(escontext, (Datum) 0,
176177
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
177178
errmsg("invalid input syntax for type %s: \"%s\"",
178179
"integer", intString)));
@@ -183,7 +184,7 @@ int2vectorin(PG_FUNCTION_ARGS)
183184
while (*intString && isspace((unsigned char) *intString))
184185
intString++;
185186
if (*intString)
186-
ereport(ERROR,
187+
ereturn(escontext, (Datum) 0,
187188
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
188189
errmsg("int2vector has too many elements")));
189190

src/backend/utils/adt/oid.c

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "catalog/pg_type.h"
2121
#include "libpq/pqformat.h"
22+
#include "nodes/miscnodes.h"
2223
#include "nodes/value.h"
2324
#include "utils/array.h"
2425
#include "utils/builtins.h"
@@ -31,15 +32,26 @@
3132
* USER I/O ROUTINES *
3233
*****************************************************************************/
3334

35+
/*
36+
* Parse a single OID and return its value.
37+
*
38+
* If endloc isn't NULL, store a pointer to the rest of the string there,
39+
* so that caller can parse the rest. Otherwise, it's an error if anything
40+
* but whitespace follows.
41+
*
42+
* If escontext points to an ErrorSaveContext node, that is filled instead
43+
* of throwing an error; the caller must check SOFT_ERROR_OCCURRED()
44+
* to detect errors.
45+
*/
3446
static Oid
35-
oidin_subr(const char *s, char **endloc)
47+
oidin_subr(const char *s, char **endloc, Node *escontext)
3648
{
3749
unsigned long cvt;
3850
char *endptr;
3951
Oid result;
4052

4153
if (*s == '\0')
42-
ereport(ERROR,
54+
ereturn(escontext, InvalidOid,
4355
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
4456
errmsg("invalid input syntax for type %s: \"%s\"",
4557
"oid", s)));
@@ -53,19 +65,19 @@ oidin_subr(const char *s, char **endloc)
5365
* handled by the second "if" consistent across platforms.
5466
*/
5567
if (errno && errno != ERANGE && errno != EINVAL)
56-
ereport(ERROR,
68+
ereturn(escontext, InvalidOid,
5769
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
5870
errmsg("invalid input syntax for type %s: \"%s\"",
5971
"oid", s)));
6072

6173
if (endptr == s && *s != '\0')
62-
ereport(ERROR,
74+
ereturn(escontext, InvalidOid,
6375
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
6476
errmsg("invalid input syntax for type %s: \"%s\"",
6577
"oid", s)));
6678

6779
if (errno == ERANGE)
68-
ereport(ERROR,
80+
ereturn(escontext, InvalidOid,
6981
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
7082
errmsg("value \"%s\" is out of range for type %s",
7183
s, "oid")));
@@ -81,7 +93,7 @@ oidin_subr(const char *s, char **endloc)
8193
while (*endptr && isspace((unsigned char) *endptr))
8294
endptr++;
8395
if (*endptr)
84-
ereport(ERROR,
96+
ereturn(escontext, InvalidOid,
8597
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
8698
errmsg("invalid input syntax for type %s: \"%s\"",
8799
"oid", s)));
@@ -104,7 +116,7 @@ oidin_subr(const char *s, char **endloc)
104116
#if OID_MAX != ULONG_MAX
105117
if (cvt != (unsigned long) result &&
106118
cvt != (unsigned long) ((int) result))
107-
ereport(ERROR,
119+
ereturn(escontext, InvalidOid,
108120
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
109121
errmsg("value \"%s\" is out of range for type %s",
110122
s, "oid")));
@@ -119,7 +131,7 @@ oidin(PG_FUNCTION_ARGS)
119131
char *s = PG_GETARG_CSTRING(0);
120132
Oid result;
121133

122-
result = oidin_subr(s, NULL);
134+
result = oidin_subr(s, NULL, fcinfo->context);
123135
PG_RETURN_OID(result);
124136
}
125137

@@ -194,6 +206,7 @@ Datum
194206
oidvectorin(PG_FUNCTION_ARGS)
195207
{
196208
char *oidString = PG_GETARG_CSTRING(0);
209+
Node *escontext = fcinfo->context;
197210
oidvector *result;
198211
int n;
199212

@@ -205,12 +218,14 @@ oidvectorin(PG_FUNCTION_ARGS)
205218
oidString++;
206219
if (*oidString == '\0')
207220
break;
208-
result->values[n] = oidin_subr(oidString, &oidString);
221+
result->values[n] = oidin_subr(oidString, &oidString, escontext);
222+
if (SOFT_ERROR_OCCURRED(escontext))
223+
PG_RETURN_NULL();
209224
}
210225
while (*oidString && isspace((unsigned char) *oidString))
211226
oidString++;
212227
if (*oidString)
213-
ereport(ERROR,
228+
ereturn(escontext, (Datum) 0,
214229
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
215230
errmsg("oidvector has too many elements")));
216231

@@ -324,7 +339,7 @@ oidparse(Node *node)
324339
* constants by the lexer. Accept these if they are valid OID
325340
* strings.
326341
*/
327-
return oidin_subr(castNode(Float, node)->fval, NULL);
342+
return oidin_subr(castNode(Float, node)->fval, NULL, NULL);
328343
default:
329344
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
330345
}

src/backend/utils/adt/pg_lsn.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ pg_lsn_in(PG_FUNCTION_ARGS)
6969

7070
result = pg_lsn_in_internal(str, &have_error);
7171
if (have_error)
72-
ereport(ERROR,
72+
ereturn(fcinfo->context, (Datum) 0,
7373
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
7474
errmsg("invalid input syntax for type %s: \"%s\"",
7575
"pg_lsn", str)));

src/backend/utils/adt/tid.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ Datum
5757
tidin(PG_FUNCTION_ARGS)
5858
{
5959
char *str = PG_GETARG_CSTRING(0);
60+
Node *escontext = fcinfo->context;
6061
char *p,
6162
*coord[NTIDARGS];
6263
int i;
@@ -71,15 +72,15 @@ tidin(PG_FUNCTION_ARGS)
7172
coord[i++] = p + 1;
7273

7374
if (i < NTIDARGS)
74-
ereport(ERROR,
75+
ereturn(escontext, (Datum) 0,
7576
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
7677
errmsg("invalid input syntax for type %s: \"%s\"",
7778
"tid", str)));
7879

7980
errno = 0;
8081
cvt = strtoul(coord[0], &badp, 10);
8182
if (errno || *badp != DELIM)
82-
ereport(ERROR,
83+
ereturn(escontext, (Datum) 0,
8384
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
8485
errmsg("invalid input syntax for type %s: \"%s\"",
8586
"tid", str)));
@@ -93,7 +94,7 @@ tidin(PG_FUNCTION_ARGS)
9394
#if SIZEOF_LONG > 4
9495
if (cvt != (unsigned long) blockNumber &&
9596
cvt != (unsigned long) ((int32) blockNumber))
96-
ereport(ERROR,
97+
ereturn(escontext, (Datum) 0,
9798
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
9899
errmsg("invalid input syntax for type %s: \"%s\"",
99100
"tid", str)));
@@ -102,7 +103,7 @@ tidin(PG_FUNCTION_ARGS)
102103
cvt = strtoul(coord[1], &badp, 10);
103104
if (errno || *badp != RDELIM ||
104105
cvt > USHRT_MAX)
105-
ereport(ERROR,
106+
ereturn(escontext, (Datum) 0,
106107
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
107108
errmsg("invalid input syntax for type %s: \"%s\"",
108109
"tid", str)));

src/backend/utils/adt/xid8funcs.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ buf_finalize(StringInfo buf)
285285
* parse snapshot from cstring
286286
*/
287287
static pg_snapshot *
288-
parse_snapshot(const char *str)
288+
parse_snapshot(const char *str, Node *escontext)
289289
{
290290
FullTransactionId xmin;
291291
FullTransactionId xmax;
@@ -341,11 +341,10 @@ parse_snapshot(const char *str)
341341
return buf_finalize(buf);
342342

343343
bad_format:
344-
ereport(ERROR,
344+
ereturn(escontext, NULL,
345345
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
346346
errmsg("invalid input syntax for type %s: \"%s\"",
347347
"pg_snapshot", str_start)));
348-
return NULL; /* keep compiler quiet */
349348
}
350349

351350
/*
@@ -447,7 +446,7 @@ pg_snapshot_in(PG_FUNCTION_ARGS)
447446
char *str = PG_GETARG_CSTRING(0);
448447
pg_snapshot *snap;
449448

450-
snap = parse_snapshot(str);
449+
snap = parse_snapshot(str, fcinfo->context);
451450

452451
PG_RETURN_POINTER(snap);
453452
}

0 commit comments

Comments
 (0)