]> granicus.if.org Git - postgresql/commitdiff
Improve documentation of ParseDateTime(). Reorder tests to prevent
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 5 Aug 2003 18:30:21 +0000 (18:30 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 5 Aug 2003 18:30:21 +0000 (18:30 +0000)
writing one more value into return arrays than will fit.  This is
potentially a stack smash, though I do not think it is a problem in
current uses of the routine, since a failure return causes elog anyway.

src/backend/utils/adt/datetime.c
src/include/utils/datetime.h

index 7baa751895cef43387b3b4c8a28362c975c421ff..c94f9bf6f97696754e51887aa50ad3a6f82eb00f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.111 2003/08/05 17:39:19 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.112 2003/08/05 18:30:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -699,7 +699,20 @@ TrimTrailingZeros(char *str)
 
 
 /* ParseDateTime()
- * Break string into tokens based on a date/time context.
+ *     Break string into tokens based on a date/time context.
+ *     Returns 0 if successful, -1 if bogus input detected.
+ *
+ * timestr - the input string
+ * lowstr - workspace for field string storage (must be large enough for
+ *             a copy of the input string, including trailing null)
+ * field[] - pointers to field strings are returned in this array
+ * ftype[] - field type indicators are returned in this array
+ * maxfields - dimensions of the above two arrays
+ * *numfields - set to the actual number of fields detected
+ *
+ * The fields extracted from the input are stored as separate, null-terminated
+ * strings in the workspace at lowstr.  Any text is converted to lower case.
+ *
  * Several field types are assigned:
  *     DTK_NUMBER - digits and (possibly) a decimal point
  *     DTK_DATE - digits and two delimiters, or digits and text
@@ -707,22 +720,33 @@ TrimTrailingZeros(char *str)
  *     DTK_STRING - text (no digits)
  *     DTK_SPECIAL - leading "+" or "-" followed by text
  *     DTK_TZ - leading "+" or "-" followed by digits
+ *
  * Note that some field types can hold unexpected items:
  *     DTK_NUMBER can hold date fields (yy.ddd)
  *     DTK_STRING can hold months (January) and time zones (PST)
  *     DTK_DATE can hold Posix time zones (GMT-8)
  */
 int
-ParseDateTime(char *timestr, char *lowstr,
+ParseDateTime(const char *timestr, char *lowstr,
                          char **field, int *ftype, int maxfields, int *numfields)
 {
        int                     nf = 0;
-       char       *cp = timestr;
+       const char *cp = timestr;
        char       *lp = lowstr;
 
        /* outer loop through fields */
        while (*cp != '\0')
        {
+               /* Ignore spaces between fields */
+               if (isspace((unsigned char) *cp))
+               {
+                       cp++;
+                       continue;
+               }
+
+               /* Record start of current field */
+               if (nf >= maxfields)
+                       return -1;
                field[nf] = lp;
 
                /* leading digit? then date or time */
@@ -745,13 +769,13 @@ ParseDateTime(char *timestr, char *lowstr,
                        else if ((*cp == '-') || (*cp == '/') || (*cp == '.'))
                        {
                                /* save delimiting character to use later */
-                               char       *dp = cp;
+                               char    delim = *cp;
 
                                *lp++ = *cp++;
                                /* second field is all digits? then no embedded text month */
                                if (isdigit((unsigned char) *cp))
                                {
-                                       ftype[nf] = ((*dp == '.') ? DTK_NUMBER : DTK_DATE);
+                                       ftype[nf] = ((delim == '.') ? DTK_NUMBER : DTK_DATE);
                                        while (isdigit((unsigned char) *cp))
                                                *lp++ = *cp++;
 
@@ -759,18 +783,18 @@ ParseDateTime(char *timestr, char *lowstr,
                                         * insist that the delimiters match to get a
                                         * three-field date.
                                         */
-                                       if (*cp == *dp)
+                                       if (*cp == delim)
                                        {
                                                ftype[nf] = DTK_DATE;
                                                *lp++ = *cp++;
-                                               while (isdigit((unsigned char) *cp) || (*cp == *dp))
+                                               while (isdigit((unsigned char) *cp) || (*cp == delim))
                                                        *lp++ = *cp++;
                                        }
                                }
                                else
                                {
                                        ftype[nf] = DTK_DATE;
-                                       while (isalnum((unsigned char) *cp) || (*cp == *dp))
+                                       while (isalnum((unsigned char) *cp) || (*cp == delim))
                                                *lp++ = tolower((unsigned char) *cp++);
                                }
                        }
@@ -809,20 +833,14 @@ ParseDateTime(char *timestr, char *lowstr,
                         */
                        if ((*cp == '-') || (*cp == '/') || (*cp == '.'))
                        {
-                               char       *dp = cp;
+                               char    delim = *cp;
 
                                ftype[nf] = DTK_DATE;
                                *lp++ = *cp++;
-                               while (isdigit((unsigned char) *cp) || (*cp == *dp))
+                               while (isdigit((unsigned char) *cp) || (*cp == delim))
                                        *lp++ = *cp++;
                        }
                }
-               /* skip leading spaces */
-               else if (isspace((unsigned char) *cp))
-               {
-                       cp++;
-                       continue;
-               }
                /* sign? then special or numeric timezone */
                else if ((*cp == '+') || (*cp == '-'))
                {
@@ -851,12 +869,11 @@ ParseDateTime(char *timestr, char *lowstr,
                        else
                                return -1;
                }
-               /* ignore punctuation but use as delimiter */
+               /* ignore other punctuation but use as delimiter */
                else if (ispunct((unsigned char) *cp))
                {
                        cp++;
                        continue;
-
                }
                /* otherwise, something is not right... */
                else
@@ -865,14 +882,12 @@ ParseDateTime(char *timestr, char *lowstr,
                /* force in a delimiter after each field */
                *lp++ = '\0';
                nf++;
-               if (nf > MAXDATEFIELDS)
-                       return -1;
        }
 
        *numfields = nf;
 
        return 0;
-}      /* ParseDateTime() */
+}
 
 
 /* DecodeDateTime()
index f81f5f8e9c1e05b6f8b7f6a0950966750b80d99f..d5facdd8e00f11e97dce8e6bb8c852e8085b7182 100644 (file)
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: datetime.h,v 1.43 2003/08/04 02:40:15 momjian Exp $
+ * $Id: datetime.h,v 1.44 2003/08/05 18:30:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -277,7 +277,7 @@ extern void GetCurrentTimeUsec(struct tm * tm, fsec_t *fsec, int *tzp);
 extern void j2date(int jd, int *year, int *month, int *day);
 extern int     date2j(int year, int month, int day);
 
-extern int ParseDateTime(char *timestr, char *lowstr,
+extern int ParseDateTime(const char *timestr, char *lowstr,
                          char **field, int *ftype,
                          int maxfields, int *numfields);
 extern int DecodeDateTime(char **field, int *ftype,