hi. based on Heikki v3. I made some changes: array_in: dim[6] all initialize with -1, lBound[6] all initialize with 1. if ReadArrayDimensions called, then corresponding dimension lBound will replace the initialized default 1 value. ReadArrayStr, since array_in main function initialized dim array, dimensions_specified true or false, I don't need to initialize again, so I deleted that part.
to solve corner cases like '{{1,},{1},}'::text[]. in ReadArrayStr main switch function, like other ArrayToken, first evaluate expect_delim then assign expect_delim. In ATOK_LEVEL_END. if non-empty array, closing bracket either precede with an element or another closing element. In both cases, the previous expect_delim should be true. in * FIXME: Is this still required? I believe all the checks it performs are * redundant with other checks in ReadArrayDimension() and ReadArrayStr() */ I deleted - nitems_according_to_dims = ArrayGetNItemsSafe(ndim, dim, escontext); - if (nitems_according_to_dims < 0) - PG_RETURN_NULL(); - if (nitems != nitems_according_to_dims) - elog(ERROR, "mismatch nitems, %d vs %d", nitems, nitems_according_to_dims); but I am not sure if the following is necessary. if (!ArrayCheckBoundsSafe(ndim, dim, lBound, escontext)) PG_RETURN_NULL(); I added some corner case tests like select '{{1,},{1},}'::text[]; some changes broken: select '{{1},{}}'::text[]; -DETAIL: Multidimensional arrays must have sub-arrays with matching dimensions. +DETAIL: Unexpected "," character. I added some error checks in ATOK_LEVEL_END. The first expect_delim part check will first generate an error, the dimension error part will not be reached.
From e59ccd4fa6dda94c50d5b0a2f9388dd8d859d501 Mon Sep 17 00:00:00 2001 From: pgaddict <jian.universal...@gmail.com> Date: Mon, 7 Aug 2023 12:49:57 +0800 Subject: [PATCH v4] based on Heikki verion3 --- src/backend/utils/adt/arrayfuncs.c | 45 ++++++++++++++++++---------- src/test/regress/expected/arrays.out | 22 +++++++++++++- src/test/regress/sql/arrays.sql | 4 +++ 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 19d7af6d..03b6b56d 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -233,6 +233,11 @@ array_in(PG_FUNCTION_ARGS) typdelim = my_extra->typdelim; typioparam = my_extra->typioparam; + for (int i = 0; i < MAXDIM; i++) + { + dim[i] = -1; + lBound[i] = 1; + } /* * Start processing the input string. * @@ -245,14 +250,12 @@ array_in(PG_FUNCTION_ARGS) if (ndim == 0) { - /* No array dimensions, so intuit dimensions from brace structure */ + /* No array dimensions, so init dimensions from brace structure */ if (*p != '{') ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed array literal: \"%s\"", string), errdetail("Array value must start with \"{\" or dimension information."))); - for (int i = 0; i < MAXDIM; i++) - lBound[i] = 1; } else { @@ -304,8 +307,11 @@ array_in(PG_FUNCTION_ARGS) initStringInfo(&buf); appendStringInfo(&buf, "array_in- ndim %d (", ndim); - for (int i = 0; i < ndim; i++) + for (int i = 0; i < MAXDIM; i++) appendStringInfo(&buf, " %d", dim[i]); + appendStringInfo(&buf, "lBound info"); + for (int i = 0; i < MAXDIM; i++) + appendStringInfo(&buf, " %d", lBound[i]); appendStringInfo(&buf, ") for %s\n", string); elog(NOTICE, "%s", buf.data); pfree(buf.data); @@ -318,11 +324,6 @@ array_in(PG_FUNCTION_ARGS) * FIXME: Is this still required? I believe all the checks it performs are * redundant with other checks in ReadArrayDimension() and ReadArrayStr() */ - nitems_according_to_dims = ArrayGetNItemsSafe(ndim, dim, escontext); - if (nitems_according_to_dims < 0) - PG_RETURN_NULL(); - if (nitems != nitems_according_to_dims) - elog(ERROR, "mismatch nitems, %d vs %d", nitems, nitems_according_to_dims); if (!ArrayCheckBoundsSafe(ndim, dim, lBound, escontext)) PG_RETURN_NULL(); @@ -603,12 +604,6 @@ ReadArrayStr(char **srcptr, /* The caller already checked this */ Assert(**srcptr == '{'); - if (!dimensions_specified) - { - /* Initialize dim[] entries to -1 meaning "unknown" */ - for (int i = 0; i < MAXDIM; ++i) - dim[i] = -1; - } ndim_frozen = dimensions_specified; maxitems = 16; @@ -675,10 +670,30 @@ ReadArrayStr(char **srcptr, { /* Nested sub-arrays count as elements of outer level */ nelems[nest_level - 1]++; + + if (nitems > 0 && expect_delim == false) + { + ereturn(escontext, false, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("malformed array literal: \"%s\"", origStr), + errdetail("Unexpected \"%c\" character.", + typdelim))); + } expect_delim = true; } else + { + /* rightmost should precede with element or bracket */ + if (nitems > 0 && expect_delim == false) + { + ereturn(escontext, false, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("malformed array literal: \"%s\"", origStr), + errdetail("Unexpected \"%c\" character.", + typdelim))); + } expect_delim = false; + } if (dim[nest_level] < 0) { diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out index 93e11068..e57590df 100644 --- a/src/test/regress/expected/arrays.out +++ b/src/test/regress/expected/arrays.out @@ -1520,7 +1520,7 @@ select '{{1},{}}'::text[]; ERROR: malformed array literal: "{{1},{}}" LINE 1: select '{{1},{}}'::text[]; ^ -DETAIL: Multidimensional arrays must have sub-arrays with matching dimensions. +DETAIL: Unexpected "," character. select '{{},{1}}'::text[]; ERROR: malformed array literal: "{{},{1}}" LINE 1: select '{{},{1}}'::text[]; @@ -1544,6 +1544,26 @@ 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. -- 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 b7e2b180..d9805aa1 100644 --- a/src/test/regress/sql/arrays.sql +++ b/src/test/regress/sql/arrays.sql @@ -468,6 +468,10 @@ 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[]; -- none of the above should be accepted -- all of the following should be accepted -- 2.34.1