]> granicus.if.org Git - postgresql/commitdiff
Try to make array_in's behavior a tad less bizarre. Leading whitespace
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 16 Mar 2002 22:47:13 +0000 (22:47 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 16 Mar 2002 22:47:13 +0000 (22:47 +0000)
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

index 8a65749328412306c6057529e1a551d0aebd41b4..4458f71af782c2411ad2069526267c729dd28617 100644 (file)
@@ -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++;
-                       }
        }
 
        /*