Commit f900af79 authored by Joe Conway's avatar Joe Conway

Further tightening of the array literal parser. Prevent junk

from being accepted after the outer right brace. Per report from
Markus Bertheau.

Also add regression test cases for this change, and for previous
recent array literal parser changes.
parent f444dafa
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.107 2004/08/08 05:01:55 joe Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.108 2004/08/28 19:31:28 joe Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -183,9 +183,7 @@ array_in(PG_FUNCTION_ARGS) ...@@ -183,9 +183,7 @@ array_in(PG_FUNCTION_ARGS)
typioparam = my_extra->typioparam; typioparam = my_extra->typioparam;
/* Make a modifiable copy of the input */ /* Make a modifiable copy of the input */
/* XXX why are we allocating an extra 2 bytes here? */ string_save = pstrdup(string);
string_save = (char *) palloc(strlen(string) + 3);
strcpy(string_save, string);
/* /*
* If the input string starts with dimension info, read and use that. * If the input string starts with dimension info, read and use that.
...@@ -375,6 +373,7 @@ ArrayCount(char *str, int *dim, char typdelim) ...@@ -375,6 +373,7 @@ ArrayCount(char *str, int *dim, char typdelim)
nelems_last[MAXDIM]; nelems_last[MAXDIM];
bool scanning_string = false; bool scanning_string = false;
bool eoArray = false; bool eoArray = false;
bool empty_array = true;
char *ptr; char *ptr;
ArrayParseState parse_state = ARRAY_NO_LEVEL; ArrayParseState parse_state = ARRAY_NO_LEVEL;
...@@ -385,7 +384,7 @@ ArrayCount(char *str, int *dim, char typdelim) ...@@ -385,7 +384,7 @@ ArrayCount(char *str, int *dim, char typdelim)
} }
/* special case for an empty array */ /* special case for an empty array */
if (strncmp(str, "{}", 2) == 0) if (strcmp(str, "{}") == 0)
return 0; return 0;
ptr = str; ptr = str;
...@@ -395,6 +394,10 @@ ArrayCount(char *str, int *dim, char typdelim) ...@@ -395,6 +394,10 @@ ArrayCount(char *str, int *dim, char typdelim)
while (!itemdone) while (!itemdone)
{ {
if (parse_state == ARRAY_ELEM_STARTED ||
parse_state == ARRAY_QUOTED_ELEM_STARTED)
empty_array = false;
switch (*ptr) switch (*ptr)
{ {
case '\0': case '\0':
...@@ -481,7 +484,8 @@ ArrayCount(char *str, int *dim, char typdelim) ...@@ -481,7 +484,8 @@ ArrayCount(char *str, int *dim, char typdelim)
if (parse_state != ARRAY_ELEM_STARTED && if (parse_state != ARRAY_ELEM_STARTED &&
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 &&
!(nest_level == 1 && parse_state == ARRAY_LEVEL_STARTED))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("malformed array literal: \"%s\"", str))); errmsg("malformed array literal: \"%s\"", str)));
...@@ -562,6 +566,20 @@ ArrayCount(char *str, int *dim, char typdelim) ...@@ -562,6 +566,20 @@ ArrayCount(char *str, int *dim, char typdelim)
temp[ndim - 1]++; temp[ndim - 1]++;
ptr++; ptr++;
} }
/* only whitespace is allowed after the closing brace */
while (*ptr)
{
if (!isspace(*ptr++))
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("malformed array literal: \"%s\"", str)));
}
/* special case for an empty array */
if (empty_array)
return 0;
for (i = 0; i < ndim; ++i) for (i = 0; i < ndim; ++i)
dim[i] = temp[i]; dim[i] = temp[i];
......
...@@ -425,3 +425,61 @@ select 'foo' ilike all (array['F%', '%O']); -- t ...@@ -425,3 +425,61 @@ select 'foo' ilike all (array['F%', '%O']); -- t
t t
(1 row) (1 row)
--
-- General array parser tests
--
-- none of the following should be accepted
select '{{1,{2}},{2,3}}'::text[];
ERROR: malformed array literal: "{{1,{2}},{2,3}}"
select '{{},{}}'::text[];
ERROR: malformed array literal: "{{},{}}"
select '{{1,2},\\{2,3}}'::text[];
ERROR: malformed array literal: "{{1,2},\{2,3}}"
select '{{"1 2" x},{3}}'::text[];
ERROR: malformed array literal: "{{"1 2" x},{3}}"
select '{}}'::text[];
ERROR: malformed array literal: "{}}"
select '{ }}'::text[];
ERROR: malformed array literal: "{ }}"
-- none of the above should be accepted
-- all of the following should be accepted
select '{}'::text[];
text
------
{}
(1 row)
select '{{{1,2,3,4},{2,3,4,5}},{{3,4,5,6},{4,5,6,7}}}'::text[];
text
-----------------------------------------------
{{{1,2,3,4},{2,3,4,5}},{{3,4,5,6},{4,5,6,7}}}
(1 row)
select '{0 second ,0 second}'::interval[];
interval
---------------
{"@ 0","@ 0"}
(1 row)
select '{ { "," } , { 3 } }'::text[];
text
-------------
{{","},{3}}
(1 row)
select ' { { " 0 second " , 0 second } }'::text[];
text
-------------------------------
{{" 0 second ","0 second"}}
(1 row)
select '{
0 second,
@ 1 hour @ 42 minutes @ 20 seconds
}'::interval[];
interval
------------------------------------
{"@ 0","@ 1 hour 42 mins 20 secs"}
(1 row)
-- all of the above should be accepted
...@@ -192,3 +192,28 @@ select 'foo' not like any (array['%a', '%b']); -- t ...@@ -192,3 +192,28 @@ select 'foo' not like any (array['%a', '%b']); -- t
select 'foo' not like all (array['%a', '%o']); -- f select 'foo' not like all (array['%a', '%o']); -- f
select 'foo' ilike any (array['%A', '%O']); -- t select 'foo' ilike any (array['%A', '%O']); -- t
select 'foo' ilike all (array['F%', '%O']); -- t select 'foo' ilike all (array['F%', '%O']); -- t
--
-- General array parser tests
--
-- none of the following should be accepted
select '{{1,{2}},{2,3}}'::text[];
select '{{},{}}'::text[];
select '{{1,2},\\{2,3}}'::text[];
select '{{"1 2" x},{3}}'::text[];
select '{}}'::text[];
select '{ }}'::text[];
-- none of the above should be accepted
-- all of the following should be accepted
select '{}'::text[];
select '{{{1,2,3,4},{2,3,4,5}},{{3,4,5,6},{4,5,6,7}}}'::text[];
select '{0 second ,0 second}'::interval[];
select '{ { "," } , { 3 } }'::text[];
select ' { { " 0 second " , 0 second } }'::text[];
select '{
0 second,
@ 1 hour @ 42 minutes @ 20 seconds
}'::interval[];
-- all of the above should be accepted
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment