v9-0007-refactor-ReadArrayStr.patch
text/x-patch
Filename: v9-0007-refactor-ReadArrayStr.patch
Type: text/x-patch
Part: 6
Message:
Re: Cleaning up array_in()
Patch
Format: format-patch
Series: patch v9-0007
Subject: refactor ReadArrayStr.
| File | + | − |
|---|---|---|
| src/backend/utils/adt/arrayfuncs.c | 31 | 42 |
| src/test/regress/expected/arrays.out | 38 | 0 |
| src/test/regress/sql/arrays.sql | 9 | 0 |
From 3e2b9ef2b6b43fb06efa2ad7ab42466e2731096e Mon Sep 17 00:00:00 2001
From: pgaddict <jian.universality@gmail.com>
Date: Thu, 14 Sep 2023 15:47:52 +0800
Subject: [PATCH v9 7/7] refactor ReadArrayStr.
array ending errors(unnessary junk) can happen in many cases, like
inside double or not, with backslash or not.
so conslidate it, using a goto ending_errror.
add more tests, also cover doule quote cases.
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 | 73 ++++++++++++----------------
src/test/regress/expected/arrays.out | 38 +++++++++++++++
src/test/regress/sql/arrays.sql | 9 ++++
3 files changed, 78 insertions(+), 42 deletions(-)
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index 95a3d5f6..ab685caa 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -299,20 +299,25 @@ array_in(PG_FUNCTION_ARGS)
errdetail("Junk after closing right brace.")));
}
+/* ----------
+ * Uncomment the following to get a dump of a array's ndim, dim, lBound.
+ * ----------
+#define ARRAYDEBUG
+ */
#ifdef ARRAYDEBUG
{
StringInfoData buf;
initStringInfo(&buf);
- appendStringInfo(&buf, "array_in- ndim %d (", ndim);
+ appendStringInfo(&buf, "array_in- ndim %d, dim info(", ndim);
for (int i = 0; i < MAXDIM; i++)
appendStringInfo(&buf, " %d", dim[i]);
- appendStringInfo(&buf, "lBound info");
+ 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);
+ appendStringInfo(&buf, ") for %s", string);
+ elog(DEBUG1, "%s", buf.data);
pfree(buf.data);
}
#endif
@@ -596,7 +601,7 @@ ReadArrayStr(char **srcptr,
bool dimensions_specified = ndim != 0;
bool ndim_frozen;
int nelems[MAXDIM];
-
+ ArrayToken prev_tok;
/* The caller already checked this */
Assert(**srcptr == '{');
@@ -622,6 +627,7 @@ ReadArrayStr(char **srcptr,
expect_delim = false;
nest_level = 0;
nitems = 0;
+ prev_tok = ATOK_LEVEL_START; /* initialize it */
do
{
ArrayToken tok;
@@ -655,7 +661,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 +746,7 @@ ReadArrayStr(char **srcptr,
case ATOK_ERROR:
return false;
}
+ prev_tok = tok;
} while (nest_level > 0);
pfree(elembuf);
@@ -788,12 +796,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 +828,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,31 +854,20 @@ 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,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
- errmsg("malformed array literal: \"%s\"",
- origStr)));
+ errmsg("malformed array literal: \"%s\"",origStr),
+ errdetail("Unexpected array element.")));
*srcptr = p;
return ATOK_ERROR;
@@ -907,6 +887,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..0d9fef55 100644
--- a/src/test/regress/expected/arrays.out
+++ b/src/test/regress/expected/arrays.out
@@ -1481,6 +1481,16 @@ ERROR: malformed array literal: "{{1,2},\{2,3}}"
LINE 1: select E'{{1,2},\\{2,3}}'::text[];
^
DETAIL: Multidimensional arrays must have sub-arrays with matching dimensions.
+select E'{"a"a}'::text[];
+ERROR: malformed array literal: "{"a"a}"
+LINE 1: select E'{"a"a}'::text[];
+ ^
+DETAIL: Unexpected array element.
+select E'{a"a"}'::text[];
+ERROR: malformed array literal: "{a"a"}"
+LINE 1: select E'{a"a"}'::text[];
+ ^
+DETAIL: Unexpected array element.
select '{{"1 2" x},{3}}'::text[];
ERROR: malformed array literal: "{{"1 2" x},{3}}"
LINE 1: select '{{"1 2" x},{3}}'::text[];
@@ -1544,6 +1554,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..47667ea3 100644
--- a/src/test/regress/sql/arrays.sql
+++ b/src/test/regress/sql/arrays.sql
@@ -455,6 +455,8 @@ select 'foo' ilike all (array['F%', '%O']); -- t
-- none of the following should be accepted
select '{{1,{2}},{2,3}}'::text[];
select E'{{1,2},\\{2,3}}'::text[];
+select E'{"a"a}'::text[];
+select E'{a"a"}'::text[];
select '{{"1 2" x},{3}}'::text[];
select '{}}'::text[];
select '{ }}'::text[];
@@ -468,6 +470,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