From 827f6d75a97a065374a368f5ba772f14c53b72b1 Mon Sep 17 00:00:00 2001 From: pgaddict Date: Mon, 11 Sep 2023 12:31:39 +0800 Subject: [PATCH v6 7/7] refactor ReadArrayStr. array ending error can happen in any of cases(quoted_element, unquoted_element, with backslash, non-backslash). conslidate it, using a goto ending_errror. add more tests. expect_delim state is not enought for case like '{{},}'. You need tracking current token and previous token to solve cases where a delimiter followed by a closing brace. --- src/backend/utils/adt/arrayfuncs.c | 55 ++++++++++------------------ src/test/regress/expected/arrays.out | 28 ++++++++++++++ src/test/regress/sql/arrays.sql | 7 ++++ 3 files changed, 54 insertions(+), 36 deletions(-) diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 79f4e1b4..b8f5d59c 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -625,7 +625,7 @@ ReadArrayStr(char **srcptr, do { ArrayToken tok; - + ArrayToken prev_tok; tok = ReadArrayToken(srcptr, elembuf, typdelim, origStr, escontext); switch (tok) @@ -655,7 +655,8 @@ ReadArrayStr(char **srcptr, } break; case ATOK_LEVEL_END: - if (nest_level == 0) + /* cannot precede with a delim. nest_level should larger than 0 */ + if (prev_tok == ATOK_DELIM || nest_level == 0) ereturn(escontext, false, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed array literal: \"%s\"", origStr), @@ -739,6 +740,7 @@ ReadArrayStr(char **srcptr, case ATOK_ERROR: return false; } + prev_tok = tok; } while (nest_level > 0); pfree(elembuf); @@ -788,12 +790,7 @@ ReadArrayToken(char **srcptr, char *elembuf, char typdelim, switch (*p) { case '\0': - errsave(escontext, - (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("malformed array literal: \"%s\"", - origStr))); - *srcptr = p; - return ATOK_ERROR; + goto ending_error; case '{': *srcptr = p + 1; return ATOK_LEVEL_START; @@ -825,24 +822,12 @@ quoted_element: switch (*p) { case '\0': - errsave(escontext, - (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("malformed array literal: \"%s\"", - origStr))); - *srcptr = p; - return ATOK_ERROR; + goto ending_error; case '\\': /* Skip backslash, copy next character as-is. */ p++; if (*p == '\0') - { - errsave(escontext, - (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("malformed array literal: \"%s\"", - origStr))); - *srcptr = p; - return ATOK_ERROR; - } + goto ending_error; *dst++ = *p++; break; case '"': @@ -863,25 +848,14 @@ unquoted_element: { case '\0': case '{': - errsave(escontext, - (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("malformed array literal: \"%s\"", - origStr))); - *srcptr = p; - return ATOK_ERROR; + goto ending_error; case '\\': /* Skip backslash, copy next character as-is. */ p++; if (*p == '\0') - { - errsave(escontext, - (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("malformed array literal: \"%s\"", - origStr))); - *srcptr = p; - return ATOK_ERROR; - } + goto ending_error; *dst++ = *p++; + dstendptr = dst; break; case '"': errsave(escontext, @@ -907,6 +881,15 @@ unquoted_element: p++; } } + +ending_error: + errsave(escontext, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("malformed array literal: \"%s\"", + origStr), + errdetail("Unexpected end of input."))); + *srcptr = p; + return ATOK_ERROR; } /* diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out index bea0d00b..9bb9924f 100644 --- a/src/test/regress/expected/arrays.out +++ b/src/test/regress/expected/arrays.out @@ -1544,6 +1544,34 @@ ERROR: cannot determine type of empty array LINE 1: select array[]; ^ HINT: Explicitly cast to the desired type, for example ARRAY[]::integer[]. +select '{{1,},{1},}'::text[]; +ERROR: malformed array literal: "{{1,},{1},}" +LINE 1: select '{{1,},{1},}'::text[]; + ^ +DETAIL: Unexpected "}" character. +select '{{1,},{1}}'::text[]; +ERROR: malformed array literal: "{{1,},{1}}" +LINE 1: select '{{1,},{1}}'::text[]; + ^ +DETAIL: Unexpected "}" character. +select '{{1,}}'::text[]; +ERROR: malformed array literal: "{{1,}}" +LINE 1: select '{{1,}}'::text[]; + ^ +DETAIL: Unexpected "}" character. +select '{1,}'::text[]; +ERROR: malformed array literal: "{1,}" +LINE 1: select '{1,}'::text[]; + ^ +DETAIL: Unexpected "}" character. +select '[21474836488:21474836489]={1,2}'::int[]; +ERROR: array bound is out of range +LINE 1: select '[21474836488:21474836489]={1,2}'::int[]; + ^ +select '[-2147483649:-2147483648]={1,2}'::int[]; +ERROR: array bound is out of range +LINE 1: select '[-2147483649:-2147483648]={1,2}'::int[]; + ^ -- none of the above should be accepted -- all of the following should be accepted select '{}'::text[]; diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql index 5eacb351..6bf18b7d 100644 --- a/src/test/regress/sql/arrays.sql +++ b/src/test/regress/sql/arrays.sql @@ -468,6 +468,13 @@ select '[2147483646:2147483647]={1,2}'::int[]; select '[1:-1]={}'::int[]; select '[1:0]={1}'::int[]; select array[]; +select '{{1,},{1},}'::text[]; +select '{{1,},{1}}'::text[]; +select '{{1,}}'::text[]; +select '{1,}'::text[]; +select '[21474836488:21474836489]={1,2}'::int[]; +select '[-2147483649:-2147483648]={1,2}'::int[]; + -- none of the above should be accepted -- all of the following should be accepted -- 2.34.1