diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 8e46c2fde105ba7b356941aa654886531f56e2eb..6f9b5bfaa956b647ac85b8ce90c9bb78d6744d57 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -8,7 +8,7 @@ * * * 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) typioparam = my_extra->typioparam; /* Make a modifiable copy of the input */ - /* XXX why are we allocating an extra 2 bytes here? */ - string_save = (char *) palloc(strlen(string) + 3); - strcpy(string_save, string); + string_save = pstrdup(string); /* * If the input string starts with dimension info, read and use that. @@ -375,6 +373,7 @@ ArrayCount(char *str, int *dim, char typdelim) nelems_last[MAXDIM]; bool scanning_string = false; bool eoArray = false; + bool empty_array = true; char *ptr; ArrayParseState parse_state = ARRAY_NO_LEVEL; @@ -385,7 +384,7 @@ ArrayCount(char *str, int *dim, char typdelim) } /* special case for an empty array */ - if (strncmp(str, "{}", 2) == 0) + if (strcmp(str, "{}") == 0) return 0; ptr = str; @@ -395,6 +394,10 @@ ArrayCount(char *str, int *dim, char typdelim) while (!itemdone) { + if (parse_state == ARRAY_ELEM_STARTED || + parse_state == ARRAY_QUOTED_ELEM_STARTED) + empty_array = false; + switch (*ptr) { case '\0': @@ -481,7 +484,8 @@ ArrayCount(char *str, int *dim, char typdelim) if (parse_state != ARRAY_ELEM_STARTED && parse_state != ARRAY_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, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed array literal: \"%s\"", str))); @@ -562,6 +566,20 @@ ArrayCount(char *str, int *dim, char typdelim) temp[ndim - 1]++; 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) dim[i] = temp[i]; diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out index ea8e2b6e8f9b38bd2006d0959d1f4a7469e2e085..083693ffa947bfa29ce6388c68e7ab60db3c7a80 100644 --- a/src/test/regress/expected/arrays.out +++ b/src/test/regress/expected/arrays.out @@ -425,3 +425,61 @@ select 'foo' ilike all (array['F%', '%O']); -- t t (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 diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql index 97cb5bbc075f455ec597ed8d966643d6ee9a8a8a..d9a3252d316025af1df7248a1d735131f092721b 100644 --- a/src/test/regress/sql/arrays.sql +++ b/src/test/regress/sql/arrays.sql @@ -192,3 +192,28 @@ select 'foo' not like any (array['%a', '%b']); -- t select 'foo' not like all (array['%a', '%o']); -- f select 'foo' ilike any (array['%A', '%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