From 0f2fbbbac167818496ab59fdc11b9660cff2e747 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 16 Mar 2002 22:47:13 +0000 Subject: [PATCH] Try to make array_in's behavior a tad less bizarre. Leading whitespace before a data item is now always skipped, rather than only sometimes. Backslashes not within double-quoted text are treated reasonably, as are multiple sequences of quoted text in a single data item. But it still seems rather prone to misbehavior if the input is not completely syntactically correct --- in particular, garbage following a right brace will be ignored. --- src/backend/utils/adt/arrayfuncs.c | 171 ++++++++++++++++------------- 1 file changed, 95 insertions(+), 76 deletions(-) diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 8a65749328..4458f71af7 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.75 2002/03/02 00:34:24 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.76 2002/03/16 22:47:13 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -51,7 +51,7 @@ #define RETURN_NULL(type) do { *isNull = true; return (type) 0; } while (0) -static int ArrayCount(char *str, int *dim, int typdelim); +static int ArrayCount(char *str, int *dim, char typdelim); static Datum *ReadArrayStr(char *arrayStr, int nitems, int ndim, int *dim, FmgrInfo *inputproc, Oid typelem, int32 typmod, char typdelim, int typlen, bool typbyval, @@ -245,7 +245,7 @@ array_in(PG_FUNCTION_ARGS) *----------------------------------------------------------------------------- */ static int -ArrayCount(char *str, int *dim, int typdelim) +ArrayCount(char *str, int *dim, char typdelim) { int nest_level = 0, i; @@ -253,7 +253,7 @@ ArrayCount(char *str, int *dim, int typdelim) temp[MAXDIM]; bool scanning_string = false; bool eoArray = false; - char *q; + char *ptr; for (i = 0; i < MAXDIM; ++i) temp[i] = dim[i] = 0; @@ -261,65 +261,68 @@ ArrayCount(char *str, int *dim, int typdelim) if (strncmp(str, "{}", 2) == 0) return 0; - q = str; - while (eoArray != true) + ptr = str; + while (!eoArray) { - bool done = false; + bool itemdone = false; - while (!done) + while (!itemdone) { - switch (*q) + switch (*ptr) { - case '\\': - /* skip escaped characters (\ and ") inside strings */ - if (scanning_string && *(q + 1)) - q++; - break; case '\0': - - /* - * Signal a premature end of the string. DZ - - * 2-9-1996 - */ + /* Signal a premature end of the string */ elog(ERROR, "malformed array constant: %s", str); break; + case '\\': + /* skip the escaped character */ + if (*(ptr + 1)) + ptr++; + else + elog(ERROR, "malformed array constant: %s", str); + break; case '\"': scanning_string = !scanning_string; break; case '{': if (!scanning_string) { + if (nest_level >= MAXDIM) + elog(ERROR, "array_in: illformed array constant"); temp[nest_level] = 0; nest_level++; + if (ndim < nest_level) + ndim = nest_level; } break; case '}': if (!scanning_string) { - if (!ndim) - ndim = nest_level; + if (nest_level == 0) + elog(ERROR, "array_in: illformed array constant"); nest_level--; - if (nest_level) - temp[nest_level - 1]++; if (nest_level == 0) - eoArray = done = true; + eoArray = itemdone = true; + else + { + /* + * We don't set itemdone here; see comments in + * ReadArrayStr + */ + temp[nest_level - 1]++; + } } break; default: - if (!ndim) - ndim = nest_level; - if (*q == typdelim && !scanning_string) - done = true; + if (*ptr == typdelim && !scanning_string) + itemdone = true; break; } - if (!done) - q++; + if (!itemdone) + ptr++; } temp[ndim - 1]++; - q++; - if (!eoArray) - while (isspace((unsigned char) *q)) - q++; + ptr++; } for (i = 0; i < ndim; ++i) dim[i] = temp[i]; @@ -359,103 +362,119 @@ ReadArrayStr(char *arrayStr, int i, nest_level = 0; Datum *values; - char *p, - *q, - *r; + char *ptr; bool scanning_string = false; + bool eoArray = false; int indx[MAXDIM], prod[MAXDIM]; - bool eoArray = false; mda_get_prod(ndim, dim, prod); values = (Datum *) palloc(nitems * sizeof(Datum)); MemSet(values, 0, nitems * sizeof(Datum)); MemSet(indx, 0, sizeof(indx)); - q = p = arrayStr; /* read array enclosed within {} */ + ptr = arrayStr; while (!eoArray) { - bool done = false; + bool itemdone = false; int i = -1; + char *itemstart; + + /* skip leading whitespace */ + while (isspace((unsigned char) *ptr)) + ptr++; + itemstart = ptr; - while (!done) + while (!itemdone) { - switch (*q) + switch (*ptr) { + case '\0': + /* Signal a premature end of the string */ + elog(ERROR, "malformed array constant: %s", arrayStr); + break; case '\\': + { + char *cptr; + /* Crunch the string on top of the backslash. */ - for (r = q; *r != '\0'; r++) - *r = *(r + 1); + for (cptr = ptr; *cptr != '\0'; cptr++) + *cptr = *(cptr + 1); + if (*ptr == '\0') + elog(ERROR, "malformed array constant: %s", arrayStr); break; + } case '\"': - if (!scanning_string) - { - while (p != q) - p++; - p++; /* get p past first doublequote */ - } - else - *q = '\0'; + { + 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--; break; + } case '{': if (!scanning_string) { - p++; - nest_level++; - if (nest_level > ndim) + if (nest_level >= ndim) elog(ERROR, "array_in: illformed array constant"); + nest_level++; indx[nest_level - 1] = 0; - indx[ndim - 1] = 0; + /* skip leading whitespace */ + while (isspace((unsigned char) *(ptr+1))) + ptr++; + itemstart = ptr+1; } break; case '}': if (!scanning_string) { + if (nest_level == 0) + elog(ERROR, "array_in: illformed array constant"); if (i == -1) i = ArrayGetOffset0(ndim, indx, prod); + indx[nest_level - 1] = 0; nest_level--; if (nest_level == 0) - eoArray = done = true; + eoArray = itemdone = true; else { - *q = '\0'; + /* + * tricky coding: terminate item value string at + * first '}', but don't process it till we see + * a typdelim char or end of array. This handles + * case where several '}'s appear successively + * in a multidimensional array. + */ + *ptr = '\0'; indx[nest_level - 1]++; } } break; default: - if (*q == typdelim && !scanning_string) + if (*ptr == typdelim && !scanning_string) { if (i == -1) i = ArrayGetOffset0(ndim, indx, prod); - done = true; + itemdone = true; indx[ndim - 1]++; } break; } - if (!done) - q++; + if (!itemdone) + ptr++; } - *q = '\0'; - if (i >= nitems) + *ptr++ = '\0'; + if (i < 0 || i >= nitems) elog(ERROR, "array_in: illformed array constant"); values[i] = FunctionCall3(inputproc, - CStringGetDatum(p), + CStringGetDatum(itemstart), ObjectIdGetDatum(typelem), Int32GetDatum(typmod)); - p = ++q; - - /* - * if not at the end of the array skip white space - */ - if (!eoArray) - while (isspace((unsigned char) *q)) - { - p++; - q++; - } } /* -- 2.40.0