Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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)