Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 7a0be67

Browse files
committed
Improve error messages for malformed array input strings.
Make the error messages issued by array_in() uniformly follow the style ERROR: malformed array literal: "actual input string" DETAIL: specific complaint here and rewrite many of the specific complaints to be clearer. The immediate motivation for doing this is a complaint from Josh Berkus that json_to_record() produced an unintelligible error message when dealing with an array item, because it tries to feed the JSON-format array value to array_in(). Really it ought to be smart enough to perform JSON-to-Postgres array conversion, but that's a future feature not a bug fix. In the meantime, this change is something we agreed we could back-patch into 9.4, and it should help de-confuse things a bit.
1 parent 10f1f93 commit 7a0be67

File tree

3 files changed

+60
-25
lines changed

3 files changed

+60
-25
lines changed

src/backend/utils/adt/arrayfuncs.c

+52-24
Original file line numberDiff line numberDiff line change
@@ -233,23 +233,27 @@ array_in(PG_FUNCTION_ARGS)
233233
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
234234
ndim + 1, MAXDIM)));
235235

236-
for (q = p; isdigit((unsigned char) *q) || (*q == '-') || (*q == '+'); q++);
236+
for (q = p; isdigit((unsigned char) *q) || (*q == '-') || (*q == '+'); q++)
237+
/* skip */ ;
237238
if (q == p) /* no digits? */
238239
ereport(ERROR,
239240
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
240-
errmsg("missing dimension value")));
241+
errmsg("malformed array literal: \"%s\"", string),
242+
errdetail("\"[\" must introduce explicitly-specified array dimensions.")));
241243

242244
if (*q == ':')
243245
{
244246
/* [m:n] format */
245247
*q = '\0';
246248
lBound[ndim] = atoi(p);
247249
p = q + 1;
248-
for (q = p; isdigit((unsigned char) *q) || (*q == '-') || (*q == '+'); q++);
250+
for (q = p; isdigit((unsigned char) *q) || (*q == '-') || (*q == '+'); q++)
251+
/* skip */ ;
249252
if (q == p) /* no digits? */
250253
ereport(ERROR,
251254
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
252-
errmsg("missing dimension value")));
255+
errmsg("malformed array literal: \"%s\"", string),
256+
errdetail("Missing array dimension value.")));
253257
}
254258
else
255259
{
@@ -259,7 +263,9 @@ array_in(PG_FUNCTION_ARGS)
259263
if (*q != ']')
260264
ereport(ERROR,
261265
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
262-
errmsg("missing \"]\" in array dimensions")));
266+
errmsg("malformed array literal: \"%s\"", string),
267+
errdetail("Missing \"%s\" after array dimensions.",
268+
"]")));
263269

264270
*q = '\0';
265271
ub = atoi(p);
@@ -279,7 +285,8 @@ array_in(PG_FUNCTION_ARGS)
279285
if (*p != '{')
280286
ereport(ERROR,
281287
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
282-
errmsg("array value must start with \"{\" or dimension information")));
288+
errmsg("malformed array literal: \"%s\"", string),
289+
errdetail("Array value must start with \"{\" or dimension information.")));
283290
ndim = ArrayCount(p, dim, typdelim);
284291
for (i = 0; i < ndim; i++)
285292
lBound[i] = 1;
@@ -293,7 +300,9 @@ array_in(PG_FUNCTION_ARGS)
293300
if (strncmp(p, ASSGN, strlen(ASSGN)) != 0)
294301
ereport(ERROR,
295302
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
296-
errmsg("missing assignment operator")));
303+
errmsg("malformed array literal: \"%s\"", string),
304+
errdetail("Missing \"%s\" after array dimensions.",
305+
ASSGN)));
297306
p += strlen(ASSGN);
298307
while (array_isspace(*p))
299308
p++;
@@ -305,18 +314,21 @@ array_in(PG_FUNCTION_ARGS)
305314
if (*p != '{')
306315
ereport(ERROR,
307316
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
308-
errmsg("array value must start with \"{\" or dimension information")));
317+
errmsg("malformed array literal: \"%s\"", string),
318+
errdetail("Array contents must start with \"{\".")));
309319
ndim_braces = ArrayCount(p, dim_braces, typdelim);
310320
if (ndim_braces != ndim)
311321
ereport(ERROR,
312322
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
313-
errmsg("array dimensions incompatible with array literal")));
323+
errmsg("malformed array literal: \"%s\"", string),
324+
errdetail("Specified array dimensions do not match array contents.")));
314325
for (i = 0; i < ndim; ++i)
315326
{
316327
if (dim[i] != dim_braces[i])
317328
ereport(ERROR,
318329
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
319-
errmsg("array dimensions incompatible with array literal")));
330+
errmsg("malformed array literal: \"%s\"", string),
331+
errdetail("Specified array dimensions do not match array contents.")));
320332
}
321333
}
322334

@@ -446,7 +458,8 @@ ArrayCount(const char *str, int *dim, char typdelim)
446458
/* Signal a premature end of the string */
447459
ereport(ERROR,
448460
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
449-
errmsg("malformed array literal: \"%s\"", str)));
461+
errmsg("malformed array literal: \"%s\"", str),
462+
errdetail("Unexpected end of input.")));
450463
break;
451464
case '\\':
452465

@@ -461,7 +474,9 @@ ArrayCount(const char *str, int *dim, char typdelim)
461474
parse_state != ARRAY_ELEM_DELIMITED)
462475
ereport(ERROR,
463476
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
464-
errmsg("malformed array literal: \"%s\"", str)));
477+
errmsg("malformed array literal: \"%s\"", str),
478+
errdetail("Unexpected \"%c\" character.",
479+
'\\')));
465480
if (parse_state != ARRAY_QUOTED_ELEM_STARTED)
466481
parse_state = ARRAY_ELEM_STARTED;
467482
/* skip the escaped character */
@@ -470,7 +485,8 @@ ArrayCount(const char *str, int *dim, char typdelim)
470485
else
471486
ereport(ERROR,
472487
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
473-
errmsg("malformed array literal: \"%s\"", str)));
488+
errmsg("malformed array literal: \"%s\"", str),
489+
errdetail("Unexpected end of input.")));
474490
break;
475491
case '\"':
476492

@@ -484,7 +500,8 @@ ArrayCount(const char *str, int *dim, char typdelim)
484500
parse_state != ARRAY_ELEM_DELIMITED)
485501
ereport(ERROR,
486502
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
487-
errmsg("malformed array literal: \"%s\"", str)));
503+
errmsg("malformed array literal: \"%s\"", str),
504+
errdetail("Unexpected array element.")));
488505
in_quotes = !in_quotes;
489506
if (in_quotes)
490507
parse_state = ARRAY_QUOTED_ELEM_STARTED;
@@ -504,7 +521,9 @@ ArrayCount(const char *str, int *dim, char typdelim)
504521
parse_state != ARRAY_LEVEL_DELIMITED)
505522
ereport(ERROR,
506523
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
507-
errmsg("malformed array literal: \"%s\"", str)));
524+
errmsg("malformed array literal: \"%s\"", str),
525+
errdetail("Unexpected \"%c\" character.",
526+
'{')));
508527
parse_state = ARRAY_LEVEL_STARTED;
509528
if (nest_level >= MAXDIM)
510529
ereport(ERROR,
@@ -532,21 +551,25 @@ ArrayCount(const char *str, int *dim, char typdelim)
532551
!(nest_level == 1 && parse_state == ARRAY_LEVEL_STARTED))
533552
ereport(ERROR,
534553
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
535-
errmsg("malformed array literal: \"%s\"", str)));
554+
errmsg("malformed array literal: \"%s\"", str),
555+
errdetail("Unexpected \"%c\" character.",
556+
'}')));
536557
parse_state = ARRAY_LEVEL_COMPLETED;
537558
if (nest_level == 0)
538559
ereport(ERROR,
539560
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
540-
errmsg("malformed array literal: \"%s\"", str)));
561+
errmsg("malformed array literal: \"%s\"", str),
562+
errdetail("Unmatched \"%c\" character.", '}')));
541563
nest_level--;
542564

543565
if (nelems_last[nest_level] != 0 &&
544566
nelems[nest_level] != nelems_last[nest_level])
545567
ereport(ERROR,
546568
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
547-
errmsg("multidimensional arrays must have "
548-
"array expressions with matching "
549-
"dimensions")));
569+
errmsg("malformed array literal: \"%s\"", str),
570+
errdetail("Multidimensional arrays must have "
571+
"sub-arrays with matching "
572+
"dimensions.")));
550573
nelems_last[nest_level] = nelems[nest_level];
551574
nelems[nest_level] = 1;
552575
if (nest_level == 0)
@@ -577,7 +600,9 @@ ArrayCount(const char *str, int *dim, char typdelim)
577600
parse_state != ARRAY_LEVEL_COMPLETED)
578601
ereport(ERROR,
579602
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
580-
errmsg("malformed array literal: \"%s\"", str)));
603+
errmsg("malformed array literal: \"%s\"", str),
604+
errdetail("Unexpected \"%c\" character.",
605+
typdelim)));
581606
if (parse_state == ARRAY_LEVEL_COMPLETED)
582607
parse_state = ARRAY_LEVEL_DELIMITED;
583608
else
@@ -598,7 +623,8 @@ ArrayCount(const char *str, int *dim, char typdelim)
598623
parse_state != ARRAY_ELEM_DELIMITED)
599624
ereport(ERROR,
600625
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
601-
errmsg("malformed array literal: \"%s\"", str)));
626+
errmsg("malformed array literal: \"%s\"", str),
627+
errdetail("Unexpected array element.")));
602628
parse_state = ARRAY_ELEM_STARTED;
603629
}
604630
}
@@ -617,7 +643,8 @@ ArrayCount(const char *str, int *dim, char typdelim)
617643
if (!array_isspace(*ptr++))
618644
ereport(ERROR,
619645
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
620-
errmsg("malformed array literal: \"%s\"", str)));
646+
errmsg("malformed array literal: \"%s\"", str),
647+
errdetail("Junk after closing right brace.")));
621648
}
622649

623650
/* special case for an empty array */
@@ -704,7 +731,8 @@ ReadArrayStr(char *arrayStr,
704731
* character.
705732
*
706733
* The error checking in this routine is mostly pro-forma, since we expect
707-
* that ArrayCount() already validated the string.
734+
* that ArrayCount() already validated the string. So we don't bother
735+
* with errdetail messages.
708736
*/
709737
srcptr = arrayStr;
710738
while (!eoArray)

src/pl/plperl/expected/plperl_array.out

+2-1
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,10 @@ ERROR: number of array dimensions (7) exceeds the maximum allowed (6)
6565
LINE 1: select plperl_sum_array('{{{{{{{1,2},{3,4}},{{5,6},{7,8}}},{...
6666
^
6767
select plperl_sum_array('{{{1,2,3}, {4,5,6,7}}, {{7,8,9}, {10, 11, 12}}}');
68-
ERROR: multidimensional arrays must have array expressions with matching dimensions
68+
ERROR: malformed array literal: "{{{1,2,3}, {4,5,6,7}}, {{7,8,9}, {10, 11, 12}}}"
6969
LINE 1: select plperl_sum_array('{{{1,2,3}, {4,5,6,7}}, {{7,8,9}, {1...
7070
^
71+
DETAIL: Multidimensional arrays must have sub-arrays with matching dimensions.
7172
CREATE OR REPLACE FUNCTION plperl_concat(TEXT[]) RETURNS TEXT AS $$
7273
my $array_arg = shift;
7374
my $result = "";

src/test/regress/expected/arrays.out

+6
Original file line numberDiff line numberDiff line change
@@ -1065,26 +1065,32 @@ select '{{1,{2}},{2,3}}'::text[];
10651065
ERROR: malformed array literal: "{{1,{2}},{2,3}}"
10661066
LINE 1: select '{{1,{2}},{2,3}}'::text[];
10671067
^
1068+
DETAIL: Unexpected "{" character.
10681069
select '{{},{}}'::text[];
10691070
ERROR: malformed array literal: "{{},{}}"
10701071
LINE 1: select '{{},{}}'::text[];
10711072
^
1073+
DETAIL: Unexpected "}" character.
10721074
select E'{{1,2},\\{2,3}}'::text[];
10731075
ERROR: malformed array literal: "{{1,2},\{2,3}}"
10741076
LINE 1: select E'{{1,2},\\{2,3}}'::text[];
10751077
^
1078+
DETAIL: Unexpected "\" character.
10761079
select '{{"1 2" x},{3}}'::text[];
10771080
ERROR: malformed array literal: "{{"1 2" x},{3}}"
10781081
LINE 1: select '{{"1 2" x},{3}}'::text[];
10791082
^
1083+
DETAIL: Unexpected array element.
10801084
select '{}}'::text[];
10811085
ERROR: malformed array literal: "{}}"
10821086
LINE 1: select '{}}'::text[];
10831087
^
1088+
DETAIL: Junk after closing right brace.
10841089
select '{ }}'::text[];
10851090
ERROR: malformed array literal: "{ }}"
10861091
LINE 1: select '{ }}'::text[];
10871092
^
1093+
DETAIL: Junk after closing right brace.
10881094
select array[];
10891095
ERROR: cannot determine type of empty array
10901096
LINE 1: select array[];

0 commit comments

Comments
 (0)