88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.106 2004/08/05 03:29:37 joe Exp $
11+ * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.107 2004/08/08 05:01:55 joe Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -351,25 +351,40 @@ array_in(PG_FUNCTION_ARGS)
351351 * The syntax for array input is C-like nested curly braces
352352 *-----------------------------------------------------------------------------
353353 */
354+ typedef enum
355+ {
356+ ARRAY_NO_LEVEL ,
357+ ARRAY_LEVEL_STARTED ,
358+ ARRAY_ELEM_STARTED ,
359+ ARRAY_ELEM_COMPLETED ,
360+ ARRAY_QUOTED_ELEM_STARTED ,
361+ ARRAY_QUOTED_ELEM_COMPLETED ,
362+ ARRAY_ELEM_DELIMITED ,
363+ ARRAY_LEVEL_COMPLETED ,
364+ ARRAY_LEVEL_DELIMITED
365+ }ArrayParseState ;
366+
354367static int
355368ArrayCount (char * str ,int * dim ,char typdelim )
356369{
357- int nest_level = 0 ,
358- i ;
359- int ndim = 1 ,
360- temp [MAXDIM ],
361- nelems [MAXDIM ],
362- nelems_last [MAXDIM ];
363- bool scanning_string = false;
364- bool eoArray = false;
365- char * ptr ;
370+ int nest_level = 0 ,
371+ i ;
372+ int ndim = 1 ,
373+ temp [MAXDIM ],
374+ nelems [MAXDIM ],
375+ nelems_last [MAXDIM ];
376+ bool scanning_string = false;
377+ bool eoArray = false;
378+ char * ptr ;
379+ ArrayParseState parse_state = ARRAY_NO_LEVEL ;
366380
367381for (i = 0 ;i < MAXDIM ;++ i )
368382{
369383temp [i ]= dim [i ]= 0 ;
370384nelems_last [i ]= nelems [i ]= 1 ;
371385}
372386
387+ /* special case for an empty array */
373388if (strncmp (str ,"{}" ,2 )== 0 )
374389return 0 ;
375390
@@ -389,6 +404,20 @@ ArrayCount(char *str, int *dim, char typdelim)
389404errmsg ("malformed array literal: \"%s\"" ,str )));
390405break ;
391406case '\\' :
407+ /*
408+ * An escape must be after a level start, after an
409+ * element start, or after an element delimiter. In any
410+ * case we now must be past an element start.
411+ */
412+ if (parse_state != ARRAY_LEVEL_STARTED &&
413+ parse_state != ARRAY_ELEM_STARTED &&
414+ parse_state != ARRAY_QUOTED_ELEM_STARTED &&
415+ parse_state != ARRAY_ELEM_DELIMITED )
416+ ereport (ERROR ,
417+ (errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
418+ errmsg ("malformed array literal: \"%s\"" ,str )));
419+ if (parse_state != ARRAY_QUOTED_ELEM_STARTED )
420+ parse_state = ARRAY_ELEM_STARTED ;
392421/* skip the escaped character */
393422if (* (ptr + 1 ))
394423ptr ++ ;
@@ -398,11 +427,38 @@ ArrayCount(char *str, int *dim, char typdelim)
398427errmsg ("malformed array literal: \"%s\"" ,str )));
399428break ;
400429case '\"' :
430+ /*
431+ * A quote must be after a level start, after a quoted
432+ * element start, or after an element delimiter. In any
433+ * case we now must be past an element start.
434+ */
435+ if (parse_state != ARRAY_LEVEL_STARTED &&
436+ parse_state != ARRAY_QUOTED_ELEM_STARTED &&
437+ parse_state != ARRAY_ELEM_DELIMITED )
438+ ereport (ERROR ,
439+ (errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
440+ errmsg ("malformed array literal: \"%s\"" ,str )));
401441scanning_string = !scanning_string ;
442+ if (scanning_string )
443+ parse_state = ARRAY_QUOTED_ELEM_STARTED ;
444+ else
445+ parse_state = ARRAY_QUOTED_ELEM_COMPLETED ;
402446break ;
403447case '{' :
404448if (!scanning_string )
405449{
450+ /*
451+ * A left brace can occur if no nesting has
452+ * occurred yet, after a level start, or
453+ * after a level delimiter.
454+ */
455+ if (parse_state != ARRAY_NO_LEVEL &&
456+ parse_state != ARRAY_LEVEL_STARTED &&
457+ parse_state != ARRAY_LEVEL_DELIMITED )
458+ ereport (ERROR ,
459+ (errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
460+ errmsg ("malformed array literal: \"%s\"" ,str )));
461+ parse_state = ARRAY_LEVEL_STARTED ;
406462if (nest_level >=MAXDIM )
407463ereport (ERROR ,
408464(errcode (ERRCODE_PROGRAM_LIMIT_EXCEEDED ),
@@ -417,6 +473,19 @@ ArrayCount(char *str, int *dim, char typdelim)
417473case '}' :
418474if (!scanning_string )
419475{
476+ /*
477+ * A right brace can occur after an element start,
478+ * an element completion, a quoted element completion,
479+ * or a level completion.
480+ */
481+ if (parse_state != ARRAY_ELEM_STARTED &&
482+ parse_state != ARRAY_ELEM_COMPLETED &&
483+ parse_state != ARRAY_QUOTED_ELEM_COMPLETED &&
484+ parse_state != ARRAY_LEVEL_COMPLETED )
485+ ereport (ERROR ,
486+ (errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
487+ errmsg ("malformed array literal: \"%s\"" ,str )));
488+ parse_state = ARRAY_LEVEL_COMPLETED ;
420489if (nest_level == 0 )
421490ereport (ERROR ,
422491(errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
@@ -445,10 +514,45 @@ ArrayCount(char *str, int *dim, char typdelim)
445514}
446515break ;
447516default :
448- if (* ptr == typdelim && !scanning_string )
517+ if (!scanning_string )
449518{
450- itemdone = true;
451- nelems [nest_level - 1 ]++ ;
519+ if (* ptr == typdelim )
520+ {
521+ /*
522+ * Delimiters can occur after an element start,
523+ * an element completion, a quoted element
524+ * completion, or a level completion.
525+ */
526+ if (parse_state != ARRAY_ELEM_STARTED &&
527+ parse_state != ARRAY_ELEM_COMPLETED &&
528+ parse_state != ARRAY_QUOTED_ELEM_COMPLETED &&
529+ parse_state != ARRAY_LEVEL_COMPLETED )
530+ ereport (ERROR ,
531+ (errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
532+ errmsg ("malformed array literal: \"%s\"" ,str )));
533+ if (parse_state == ARRAY_LEVEL_COMPLETED )
534+ parse_state = ARRAY_LEVEL_DELIMITED ;
535+ else
536+ parse_state = ARRAY_ELEM_DELIMITED ;
537+ itemdone = true;
538+ nelems [nest_level - 1 ]++ ;
539+ }
540+ else if (!isspace (* ptr ))
541+ {
542+ /*
543+ * Other non-space characters must be after a level
544+ * start, after an element start, or after an element
545+ * delimiter. In any case we now must be past an
546+ * element start.
547+ */
548+ if (parse_state != ARRAY_LEVEL_STARTED &&
549+ parse_state != ARRAY_ELEM_STARTED &&
550+ parse_state != ARRAY_ELEM_DELIMITED )
551+ ereport (ERROR ,
552+ (errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
553+ errmsg ("malformed array literal: \"%s\"" ,str )));
554+ parse_state = ARRAY_ELEM_STARTED ;
555+ }
452556}
453557break ;
454558}
@@ -511,12 +615,15 @@ ReadArrayStr(char *arrayStr,
511615while (!eoArray )
512616{
513617bool itemdone = false;
618+ bool itemquoted = false;
514619int i = -1 ;
515620char * itemstart ;
621+ char * eptr ;
516622
517623/* skip leading whitespace */
518624while (isspace ((unsignedchar )* ptr ))
519625ptr ++ ;
626+
520627itemstart = ptr ;
521628
522629while (!itemdone )
@@ -547,11 +654,15 @@ ReadArrayStr(char *arrayStr,
547654char * cptr ;
548655
549656scanning_string = !scanning_string ;
550- /* Crunch the string on top of the quote. */
551- for (cptr = ptr ;* cptr != '\0' ;cptr ++ )
552- * cptr = * (cptr + 1 );
553- /* Back up to not miss following character. */
554- ptr -- ;
657+ if (scanning_string )
658+ {
659+ itemquoted = true;
660+ /* Crunch the string on top of the first quote. */
661+ for (cptr = ptr ;* cptr != '\0' ;cptr ++ )
662+ * cptr = * (cptr + 1 );
663+ /* Back up to not miss following character. */
664+ ptr -- ;
665+ }
555666break ;
556667}
557668case '{' :
@@ -615,6 +726,25 @@ ReadArrayStr(char *arrayStr,
615726(errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
616727errmsg ("malformed array literal: \"%s\"" ,arrayStr )));
617728
729+ /*
730+ * skip trailing whitespace
731+ */
732+ eptr = ptr - 1 ;
733+ if (!itemquoted )
734+ {
735+ /* skip to last non-NULL, non-space, character */
736+ while ((* eptr == '\0' )|| (isspace ((unsignedchar )* eptr )))
737+ eptr -- ;
738+ * (++ eptr )= '\0' ;
739+ }
740+ else
741+ {
742+ /* skip to last quote character */
743+ while (* eptr != '"' )
744+ eptr -- ;
745+ * eptr = '\0' ;
746+ }
747+
618748values [i ]= FunctionCall3 (inputproc ,
619749CStringGetDatum (itemstart ),
620750ObjectIdGetDatum (typioparam ),