aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/arrayfuncs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/arrayfuncs.c')
-rw-r--r--src/backend/utils/adt/arrayfuncs.c166
1 files changed, 148 insertions, 18 deletions
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index a8b1b636e08..8e46c2fde10 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.106 2004/08/05 03:29:37 joe Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.107 2004/08/08 05:01:55 joe Exp $
*
*-------------------------------------------------------------------------
*/
@@ -351,18 +351,32 @@ array_in(PG_FUNCTION_ARGS)
* The syntax for array input is C-like nested curly braces
*-----------------------------------------------------------------------------
*/
+typedef enum
+{
+ ARRAY_NO_LEVEL,
+ ARRAY_LEVEL_STARTED,
+ ARRAY_ELEM_STARTED,
+ ARRAY_ELEM_COMPLETED,
+ ARRAY_QUOTED_ELEM_STARTED,
+ ARRAY_QUOTED_ELEM_COMPLETED,
+ ARRAY_ELEM_DELIMITED,
+ ARRAY_LEVEL_COMPLETED,
+ ARRAY_LEVEL_DELIMITED
+} ArrayParseState;
+
static int
ArrayCount(char *str, int *dim, char typdelim)
{
- int nest_level = 0,
- i;
- int ndim = 1,
- temp[MAXDIM],
- nelems[MAXDIM],
- nelems_last[MAXDIM];
- bool scanning_string = false;
- bool eoArray = false;
- char *ptr;
+ int nest_level = 0,
+ i;
+ int ndim = 1,
+ temp[MAXDIM],
+ nelems[MAXDIM],
+ nelems_last[MAXDIM];
+ bool scanning_string = false;
+ bool eoArray = false;
+ char *ptr;
+ ArrayParseState parse_state = ARRAY_NO_LEVEL;
for (i = 0; i < MAXDIM; ++i)
{
@@ -370,6 +384,7 @@ ArrayCount(char *str, int *dim, char typdelim)
nelems_last[i] = nelems[i] = 1;
}
+ /* special case for an empty array */
if (strncmp(str, "{}", 2) == 0)
return 0;
@@ -389,6 +404,20 @@ ArrayCount(char *str, int *dim, char typdelim)
errmsg("malformed array literal: \"%s\"", str)));
break;
case '\\':
+ /*
+ * An escape must be after a level start, after an
+ * element start, or after an element delimiter. In any
+ * case we now must be past an element start.
+ */
+ if (parse_state != ARRAY_LEVEL_STARTED &&
+ parse_state != ARRAY_ELEM_STARTED &&
+ parse_state != ARRAY_QUOTED_ELEM_STARTED &&
+ parse_state != ARRAY_ELEM_DELIMITED)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("malformed array literal: \"%s\"", str)));
+ if (parse_state != ARRAY_QUOTED_ELEM_STARTED)
+ parse_state = ARRAY_ELEM_STARTED;
/* skip the escaped character */
if (*(ptr + 1))
ptr++;
@@ -398,11 +427,38 @@ ArrayCount(char *str, int *dim, char typdelim)
errmsg("malformed array literal: \"%s\"", str)));
break;
case '\"':
+ /*
+ * A quote must be after a level start, after a quoted
+ * element start, or after an element delimiter. In any
+ * case we now must be past an element start.
+ */
+ if (parse_state != ARRAY_LEVEL_STARTED &&
+ parse_state != ARRAY_QUOTED_ELEM_STARTED &&
+ parse_state != ARRAY_ELEM_DELIMITED)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("malformed array literal: \"%s\"", str)));
scanning_string = !scanning_string;
+ if (scanning_string)
+ parse_state = ARRAY_QUOTED_ELEM_STARTED;
+ else
+ parse_state = ARRAY_QUOTED_ELEM_COMPLETED;
break;
case '{':
if (!scanning_string)
{
+ /*
+ * A left brace can occur if no nesting has
+ * occurred yet, after a level start, or
+ * after a level delimiter.
+ */
+ if (parse_state != ARRAY_NO_LEVEL &&
+ parse_state != ARRAY_LEVEL_STARTED &&
+ parse_state != ARRAY_LEVEL_DELIMITED)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("malformed array literal: \"%s\"", str)));
+ parse_state = ARRAY_LEVEL_STARTED;
if (nest_level >= MAXDIM)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
@@ -417,6 +473,19 @@ ArrayCount(char *str, int *dim, char typdelim)
case '}':
if (!scanning_string)
{
+ /*
+ * A right brace can occur after an element start,
+ * an element completion, a quoted element completion,
+ * or a level completion.
+ */
+ if (parse_state != ARRAY_ELEM_STARTED &&
+ parse_state != ARRAY_ELEM_COMPLETED &&
+ parse_state != ARRAY_QUOTED_ELEM_COMPLETED &&
+ parse_state != ARRAY_LEVEL_COMPLETED)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("malformed array literal: \"%s\"", str)));
+ parse_state = ARRAY_LEVEL_COMPLETED;
if (nest_level == 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
@@ -445,10 +514,45 @@ ArrayCount(char *str, int *dim, char typdelim)
}
break;
default:
- if (*ptr == typdelim && !scanning_string)
+ if (!scanning_string)
{
- itemdone = true;
- nelems[nest_level - 1]++;
+ if (*ptr == typdelim)
+ {
+ /*
+ * Delimiters can occur after an element start,
+ * an element completion, a quoted element
+ * completion, or a level completion.
+ */
+ if (parse_state != ARRAY_ELEM_STARTED &&
+ parse_state != ARRAY_ELEM_COMPLETED &&
+ parse_state != ARRAY_QUOTED_ELEM_COMPLETED &&
+ parse_state != ARRAY_LEVEL_COMPLETED)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("malformed array literal: \"%s\"", str)));
+ if (parse_state == ARRAY_LEVEL_COMPLETED)
+ parse_state = ARRAY_LEVEL_DELIMITED;
+ else
+ parse_state = ARRAY_ELEM_DELIMITED;
+ itemdone = true;
+ nelems[nest_level - 1]++;
+ }
+ else if (!isspace(*ptr))
+ {
+ /*
+ * Other non-space characters must be after a level
+ * start, after an element start, or after an element
+ * delimiter. In any case we now must be past an
+ * element start.
+ */
+ if (parse_state != ARRAY_LEVEL_STARTED &&
+ parse_state != ARRAY_ELEM_STARTED &&
+ parse_state != ARRAY_ELEM_DELIMITED)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("malformed array literal: \"%s\"", str)));
+ parse_state = ARRAY_ELEM_STARTED;
+ }
}
break;
}
@@ -511,12 +615,15 @@ ReadArrayStr(char *arrayStr,
while (!eoArray)
{
bool itemdone = false;
+ bool itemquoted = false;
int i = -1;
char *itemstart;
+ char *eptr;
/* skip leading whitespace */
while (isspace((unsigned char) *ptr))
ptr++;
+
itemstart = ptr;
while (!itemdone)
@@ -547,11 +654,15 @@ ReadArrayStr(char *arrayStr,
char *cptr;
scanning_string = !scanning_string;
- /* Crunch the string on top of the quote. */
- for (cptr = ptr; *cptr != '\0'; cptr++)
- *cptr = *(cptr + 1);
- /* Back up to not miss following character. */
- ptr--;
+ if (scanning_string)
+ {
+ itemquoted = true;
+ /* Crunch the string on top of the first quote. */
+ for (cptr = ptr; *cptr != '\0'; cptr++)
+ *cptr = *(cptr + 1);
+ /* Back up to not miss following character. */
+ ptr--;
+ }
break;
}
case '{':
@@ -615,6 +726,25 @@ ReadArrayStr(char *arrayStr,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("malformed array literal: \"%s\"", arrayStr)));
+ /*
+ * skip trailing whitespace
+ */
+ eptr = ptr - 1;
+ if (!itemquoted)
+ {
+ /* skip to last non-NULL, non-space, character */
+ while ((*eptr == '\0') || (isspace((unsigned char) *eptr)))
+ eptr--;
+ *(++eptr) = '\0';
+ }
+ else
+ {
+ /* skip to last quote character */
+ while (*eptr != '"')
+ eptr--;
+ *eptr = '\0';
+ }
+
values[i] = FunctionCall3(inputproc,
CStringGetDatum(itemstart),
ObjectIdGetDatum(typioparam),