Skip to content

Commit 3b9d2de

Browse files
committed
Convert a few more datatype input functions to report errors softly.
Convert the remaining string-category input functions (bpcharin, varcharin, byteain) to the new style. Discussion: https://postgr.es/m/3038346.1671060258@sss.pgh.pa.us
1 parent 90161da commit 3b9d2de

File tree

14 files changed

+203
-30
lines changed

14 files changed

+203
-30
lines changed

src/backend/utils/adt/encode.c

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -171,26 +171,28 @@ hex_encode(const char *src, size_t len, char *dst)
171171
return (uint64) len * 2;
172172
}
173173

174-
static inline char
175-
get_hex(const char *cp)
174+
static inline bool
175+
get_hex(const char *cp, char *out)
176176
{
177177
unsigned char c = (unsigned char) *cp;
178178
int res = -1;
179179

180180
if (c < 127)
181181
res = hexlookup[c];
182182

183-
if (res < 0)
184-
ereport(ERROR,
185-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
186-
errmsg("invalid hexadecimal digit: \"%.*s\"",
187-
pg_mblen(cp), cp)));
183+
*out = (char) res;
188184

189-
return (char) res;
185+
return (res >= 0);
190186
}
191187

192188
uint64
193189
hex_decode(const char *src, size_t len, char *dst)
190+
{
191+
return hex_decode_safe(src, len, dst, NULL);
192+
}
193+
194+
uint64
195+
hex_decode_safe(const char *src, size_t len, char *dst, Node *escontext)
194196
{
195197
const char *s,
196198
*srcend;
@@ -208,16 +210,23 @@ hex_decode(const char *src, size_t len, char *dst)
208210
s++;
209211
continue;
210212
}
211-
v1 = get_hex(s) << 4;
213+
if (!get_hex(s, &v1))
214+
ereturn(escontext, 0,
215+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
216+
errmsg("invalid hexadecimal digit: \"%.*s\"",
217+
pg_mblen(s), s)));
212218
s++;
213219
if (s >= srcend)
214-
ereport(ERROR,
220+
ereturn(escontext, 0,
215221
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
216222
errmsg("invalid hexadecimal data: odd number of digits")));
217-
218-
v2 = get_hex(s);
223+
if (!get_hex(s, &v2))
224+
ereturn(escontext, 0,
225+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
226+
errmsg("invalid hexadecimal digit: \"%.*s\"",
227+
pg_mblen(s), s)));
219228
s++;
220-
*p++ = v1 | v2;
229+
*p++ = (v1 << 4) | v2;
221230
}
222231

223232
return p - dst;

src/backend/utils/adt/varchar.c

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,13 @@ anychar_typmodout(int32 typmod)
122122
*
123123
* If the input string is too long, raise an error, unless the extra
124124
* characters are spaces, in which case they're truncated. (per SQL)
125+
*
126+
* If escontext points to an ErrorSaveContext node, that is filled instead
127+
* of throwing an error; the caller must check SOFT_ERROR_OCCURRED()
128+
* to detect errors.
125129
*/
126130
static BpChar *
127-
bpchar_input(const char *s, size_t len, int32 atttypmod)
131+
bpchar_input(const char *s, size_t len, int32 atttypmod, Node *escontext)
128132
{
129133
BpChar *result;
130134
char *r;
@@ -153,7 +157,7 @@ bpchar_input(const char *s, size_t len, int32 atttypmod)
153157
for (j = mbmaxlen; j < len; j++)
154158
{
155159
if (s[j] != ' ')
156-
ereport(ERROR,
160+
ereturn(escontext, NULL,
157161
(errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
158162
errmsg("value too long for type character(%d)",
159163
(int) maxlen)));
@@ -195,14 +199,13 @@ Datum
195199
bpcharin(PG_FUNCTION_ARGS)
196200
{
197201
char *s = PG_GETARG_CSTRING(0);
198-
199202
#ifdef NOT_USED
200203
Oid typelem = PG_GETARG_OID(1);
201204
#endif
202205
int32 atttypmod = PG_GETARG_INT32(2);
203206
BpChar *result;
204207

205-
result = bpchar_input(s, strlen(s), atttypmod);
208+
result = bpchar_input(s, strlen(s), atttypmod, fcinfo->context);
206209
PG_RETURN_BPCHAR_P(result);
207210
}
208211

@@ -228,7 +231,6 @@ Datum
228231
bpcharrecv(PG_FUNCTION_ARGS)
229232
{
230233
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
231-
232234
#ifdef NOT_USED
233235
Oid typelem = PG_GETARG_OID(1);
234236
#endif
@@ -238,7 +240,7 @@ bpcharrecv(PG_FUNCTION_ARGS)
238240
int nbytes;
239241

240242
str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
241-
result = bpchar_input(str, nbytes, atttypmod);
243+
result = bpchar_input(str, nbytes, atttypmod, NULL);
242244
pfree(str);
243245
PG_RETURN_BPCHAR_P(result);
244246
}
@@ -448,11 +450,12 @@ bpchartypmodout(PG_FUNCTION_ARGS)
448450
* If the input string is too long, raise an error, unless the extra
449451
* characters are spaces, in which case they're truncated. (per SQL)
450452
*
451-
* Uses the C string to text conversion function, which is only appropriate
452-
* if VarChar and text are equivalent types.
453+
* If escontext points to an ErrorSaveContext node, that is filled instead
454+
* of throwing an error; the caller must check SOFT_ERROR_OCCURRED()
455+
* to detect errors.
453456
*/
454457
static VarChar *
455-
varchar_input(const char *s, size_t len, int32 atttypmod)
458+
varchar_input(const char *s, size_t len, int32 atttypmod, Node *escontext)
456459
{
457460
VarChar *result;
458461
size_t maxlen;
@@ -468,7 +471,7 @@ varchar_input(const char *s, size_t len, int32 atttypmod)
468471
for (j = mbmaxlen; j < len; j++)
469472
{
470473
if (s[j] != ' ')
471-
ereport(ERROR,
474+
ereturn(escontext, NULL,
472475
(errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
473476
errmsg("value too long for type character varying(%d)",
474477
(int) maxlen)));
@@ -477,6 +480,10 @@ varchar_input(const char *s, size_t len, int32 atttypmod)
477480
len = mbmaxlen;
478481
}
479482

483+
/*
484+
* We can use cstring_to_text_with_len because VarChar and text are
485+
* binary-compatible types.
486+
*/
480487
result = (VarChar *) cstring_to_text_with_len(s, len);
481488
return result;
482489
}
@@ -489,14 +496,13 @@ Datum
489496
varcharin(PG_FUNCTION_ARGS)
490497
{
491498
char *s = PG_GETARG_CSTRING(0);
492-
493499
#ifdef NOT_USED
494500
Oid typelem = PG_GETARG_OID(1);
495501
#endif
496502
int32 atttypmod = PG_GETARG_INT32(2);
497503
VarChar *result;
498504

499-
result = varchar_input(s, strlen(s), atttypmod);
505+
result = varchar_input(s, strlen(s), atttypmod, fcinfo->context);
500506
PG_RETURN_VARCHAR_P(result);
501507
}
502508

@@ -522,7 +528,6 @@ Datum
522528
varcharrecv(PG_FUNCTION_ARGS)
523529
{
524530
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
525-
526531
#ifdef NOT_USED
527532
Oid typelem = PG_GETARG_OID(1);
528533
#endif
@@ -532,7 +537,7 @@ varcharrecv(PG_FUNCTION_ARGS)
532537
int nbytes;
533538

534539
str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
535-
result = varchar_input(str, nbytes, atttypmod);
540+
result = varchar_input(str, nbytes, atttypmod, NULL);
536541
pfree(str);
537542
PG_RETURN_VARCHAR_P(result);
538543
}

src/backend/utils/adt/varlena.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ Datum
295295
byteain(PG_FUNCTION_ARGS)
296296
{
297297
char *inputText = PG_GETARG_CSTRING(0);
298+
Node *escontext = fcinfo->context;
298299
char *tp;
299300
char *rp;
300301
int bc;
@@ -307,7 +308,8 @@ byteain(PG_FUNCTION_ARGS)
307308

308309
bc = (len - 2) / 2 + VARHDRSZ; /* maximum possible length */
309310
result = palloc(bc);
310-
bc = hex_decode(inputText + 2, len - 2, VARDATA(result));
311+
bc = hex_decode_safe(inputText + 2, len - 2, VARDATA(result),
312+
escontext);
311313
SET_VARSIZE(result, bc + VARHDRSZ); /* actual length */
312314

313315
PG_RETURN_BYTEA_P(result);
@@ -331,7 +333,7 @@ byteain(PG_FUNCTION_ARGS)
331333
/*
332334
* one backslash, not followed by another or ### valid octal
333335
*/
334-
ereport(ERROR,
336+
ereturn(escontext, (Datum) 0,
335337
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
336338
errmsg("invalid input syntax for type %s", "bytea")));
337339
}
@@ -372,7 +374,7 @@ byteain(PG_FUNCTION_ARGS)
372374
/*
373375
* We should never get here. The first pass should not allow it.
374376
*/
375-
ereport(ERROR,
377+
ereturn(escontext, (Datum) 0,
376378
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
377379
errmsg("invalid input syntax for type %s", "bytea")));
378380
}

src/include/utils/builtins.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ extern int errdomainconstraint(Oid datatypeOid, const char *conname);
3434
/* encode.c */
3535
extern uint64 hex_encode(const char *src, size_t len, char *dst);
3636
extern uint64 hex_decode(const char *src, size_t len, char *dst);
37+
extern uint64 hex_decode_safe(const char *src, size_t len, char *dst,
38+
Node *escontext);
3739

3840
/* int.c */
3941
extern int2vector *buildint2vector(const int16 *int2s, int n);

src/test/regress/expected/char.out

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,25 @@ SELECT * FROM CHAR_TBL;
119119
abcd
120120
(4 rows)
121121

122+
-- Also try it with non-error-throwing API
123+
SELECT pg_input_is_valid('abcd ', 'char(4)');
124+
pg_input_is_valid
125+
-------------------
126+
t
127+
(1 row)
128+
129+
SELECT pg_input_is_valid('abcde', 'char(4)');
130+
pg_input_is_valid
131+
-------------------
132+
f
133+
(1 row)
134+
135+
SELECT pg_input_error_message('abcde', 'char(4)');
136+
pg_input_error_message
137+
--------------------------------------
138+
value too long for type character(4)
139+
(1 row)
140+
122141
--
123142
-- Also test "char", which is an ad-hoc one-byte type. It can only
124143
-- really store ASCII characters, but we allow high-bit-set characters

src/test/regress/expected/char_1.out

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,25 @@ SELECT * FROM CHAR_TBL;
119119
abcd
120120
(4 rows)
121121

122+
-- Also try it with non-error-throwing API
123+
SELECT pg_input_is_valid('abcd ', 'char(4)');
124+
pg_input_is_valid
125+
-------------------
126+
t
127+
(1 row)
128+
129+
SELECT pg_input_is_valid('abcde', 'char(4)');
130+
pg_input_is_valid
131+
-------------------
132+
f
133+
(1 row)
134+
135+
SELECT pg_input_error_message('abcde', 'char(4)');
136+
pg_input_error_message
137+
--------------------------------------
138+
value too long for type character(4)
139+
(1 row)
140+
122141
--
123142
-- Also test "char", which is an ad-hoc one-byte type. It can only
124143
-- really store ASCII characters, but we allow high-bit-set characters

src/test/regress/expected/char_2.out

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,25 @@ SELECT * FROM CHAR_TBL;
119119
abcd
120120
(4 rows)
121121

122+
-- Also try it with non-error-throwing API
123+
SELECT pg_input_is_valid('abcd ', 'char(4)');
124+
pg_input_is_valid
125+
-------------------
126+
t
127+
(1 row)
128+
129+
SELECT pg_input_is_valid('abcde', 'char(4)');
130+
pg_input_is_valid
131+
-------------------
132+
f
133+
(1 row)
134+
135+
SELECT pg_input_error_message('abcde', 'char(4)');
136+
pg_input_error_message
137+
--------------------------------------
138+
value too long for type character(4)
139+
(1 row)
140+
122141
--
123142
-- Also test "char", which is an ad-hoc one-byte type. It can only
124143
-- really store ASCII characters, but we allow high-bit-set characters

src/test/regress/expected/strings.out

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,31 @@ SELECT E'De\\123dBeEf'::bytea;
273273
DeSdBeEf
274274
(1 row)
275275

276+
-- Test non-error-throwing API too
277+
SELECT pg_input_is_valid(E'\\xDeAdBeE', 'bytea');
278+
pg_input_is_valid
279+
-------------------
280+
f
281+
(1 row)
282+
283+
SELECT pg_input_error_message(E'\\xDeAdBeE', 'bytea');
284+
pg_input_error_message
285+
------------------------------------------------
286+
invalid hexadecimal data: odd number of digits
287+
(1 row)
288+
289+
SELECT pg_input_error_message(E'\\xDeAdBeEx', 'bytea');
290+
pg_input_error_message
291+
--------------------------------
292+
invalid hexadecimal digit: "x"
293+
(1 row)
294+
295+
SELECT pg_input_error_message(E'foo\\99bar', 'bytea');
296+
pg_input_error_message
297+
-------------------------------------
298+
invalid input syntax for type bytea
299+
(1 row)
300+
276301
--
277302
-- test conversions between various string types
278303
-- E021-10 implicit casting among the character data types

src/test/regress/expected/varchar.out

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,22 @@ SELECT * FROM VARCHAR_TBL;
111111
abcd
112112
(4 rows)
113113

114+
-- Also try it with non-error-throwing API
115+
SELECT pg_input_is_valid('abcd ', 'varchar(4)');
116+
pg_input_is_valid
117+
-------------------
118+
t
119+
(1 row)
120+
121+
SELECT pg_input_is_valid('abcde', 'varchar(4)');
122+
pg_input_is_valid
123+
-------------------
124+
f
125+
(1 row)
126+
127+
SELECT pg_input_error_message('abcde', 'varchar(4)');
128+
pg_input_error_message
129+
----------------------------------------------
130+
value too long for type character varying(4)
131+
(1 row)
132+

src/test/regress/expected/varchar_1.out

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,22 @@ SELECT * FROM VARCHAR_TBL;
111111
abcd
112112
(4 rows)
113113

114+
-- Also try it with non-error-throwing API
115+
SELECT pg_input_is_valid('abcd ', 'varchar(4)');
116+
pg_input_is_valid
117+
-------------------
118+
t
119+
(1 row)
120+
121+
SELECT pg_input_is_valid('abcde', 'varchar(4)');
122+
pg_input_is_valid
123+
-------------------
124+
f
125+
(1 row)
126+
127+
SELECT pg_input_error_message('abcde', 'varchar(4)');
128+
pg_input_error_message
129+
----------------------------------------------
130+
value too long for type character varying(4)
131+
(1 row)
132+

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy