Commit 630684d3 authored by Tom Lane's avatar Tom Lane

Improve documentation of ParseDateTime(). Reorder tests to prevent

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.
parent 9d41073f
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -700,6 +700,19 @@ TrimTrailingZeros(char *str) ...@@ -700,6 +700,19 @@ TrimTrailingZeros(char *str)
/* ParseDateTime() /* 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: * Several field types are assigned:
* DTK_NUMBER - digits and (possibly) a decimal point * DTK_NUMBER - digits and (possibly) a decimal point
* DTK_DATE - digits and two delimiters, or digits and text * DTK_DATE - digits and two delimiters, or digits and text
...@@ -707,22 +720,33 @@ TrimTrailingZeros(char *str) ...@@ -707,22 +720,33 @@ TrimTrailingZeros(char *str)
* DTK_STRING - text (no digits) * DTK_STRING - text (no digits)
* DTK_SPECIAL - leading "+" or "-" followed by text * DTK_SPECIAL - leading "+" or "-" followed by text
* DTK_TZ - leading "+" or "-" followed by digits * DTK_TZ - leading "+" or "-" followed by digits
*
* Note that some field types can hold unexpected items: * Note that some field types can hold unexpected items:
* DTK_NUMBER can hold date fields (yy.ddd) * DTK_NUMBER can hold date fields (yy.ddd)
* DTK_STRING can hold months (January) and time zones (PST) * DTK_STRING can hold months (January) and time zones (PST)
* DTK_DATE can hold Posix time zones (GMT-8) * DTK_DATE can hold Posix time zones (GMT-8)
*/ */
int int
ParseDateTime(char *timestr, char *lowstr, ParseDateTime(const char *timestr, char *lowstr,
char **field, int *ftype, int maxfields, int *numfields) char **field, int *ftype, int maxfields, int *numfields)
{ {
int nf = 0; int nf = 0;
char *cp = timestr; const char *cp = timestr;
char *lp = lowstr; char *lp = lowstr;
/* outer loop through fields */ /* outer loop through fields */
while (*cp != '\0') 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; field[nf] = lp;
/* leading digit? then date or time */ /* leading digit? then date or time */
...@@ -745,13 +769,13 @@ ParseDateTime(char *timestr, char *lowstr, ...@@ -745,13 +769,13 @@ ParseDateTime(char *timestr, char *lowstr,
else if ((*cp == '-') || (*cp == '/') || (*cp == '.')) else if ((*cp == '-') || (*cp == '/') || (*cp == '.'))
{ {
/* save delimiting character to use later */ /* save delimiting character to use later */
char *dp = cp; char delim = *cp;
*lp++ = *cp++; *lp++ = *cp++;
/* second field is all digits? then no embedded text month */ /* second field is all digits? then no embedded text month */
if (isdigit((unsigned char) *cp)) if (isdigit((unsigned char) *cp))
{ {
ftype[nf] = ((*dp == '.') ? DTK_NUMBER : DTK_DATE); ftype[nf] = ((delim == '.') ? DTK_NUMBER : DTK_DATE);
while (isdigit((unsigned char) *cp)) while (isdigit((unsigned char) *cp))
*lp++ = *cp++; *lp++ = *cp++;
...@@ -759,18 +783,18 @@ ParseDateTime(char *timestr, char *lowstr, ...@@ -759,18 +783,18 @@ ParseDateTime(char *timestr, char *lowstr,
* insist that the delimiters match to get a * insist that the delimiters match to get a
* three-field date. * three-field date.
*/ */
if (*cp == *dp) if (*cp == delim)
{ {
ftype[nf] = DTK_DATE; ftype[nf] = DTK_DATE;
*lp++ = *cp++; *lp++ = *cp++;
while (isdigit((unsigned char) *cp) || (*cp == *dp)) while (isdigit((unsigned char) *cp) || (*cp == delim))
*lp++ = *cp++; *lp++ = *cp++;
} }
} }
else else
{ {
ftype[nf] = DTK_DATE; ftype[nf] = DTK_DATE;
while (isalnum((unsigned char) *cp) || (*cp == *dp)) while (isalnum((unsigned char) *cp) || (*cp == delim))
*lp++ = tolower((unsigned char) *cp++); *lp++ = tolower((unsigned char) *cp++);
} }
} }
...@@ -809,20 +833,14 @@ ParseDateTime(char *timestr, char *lowstr, ...@@ -809,20 +833,14 @@ ParseDateTime(char *timestr, char *lowstr,
*/ */
if ((*cp == '-') || (*cp == '/') || (*cp == '.')) if ((*cp == '-') || (*cp == '/') || (*cp == '.'))
{ {
char *dp = cp; char delim = *cp;
ftype[nf] = DTK_DATE; ftype[nf] = DTK_DATE;
*lp++ = *cp++; *lp++ = *cp++;
while (isdigit((unsigned char) *cp) || (*cp == *dp)) while (isdigit((unsigned char) *cp) || (*cp == delim))
*lp++ = *cp++; *lp++ = *cp++;
} }
} }
/* skip leading spaces */
else if (isspace((unsigned char) *cp))
{
cp++;
continue;
}
/* sign? then special or numeric timezone */ /* sign? then special or numeric timezone */
else if ((*cp == '+') || (*cp == '-')) else if ((*cp == '+') || (*cp == '-'))
{ {
...@@ -851,12 +869,11 @@ ParseDateTime(char *timestr, char *lowstr, ...@@ -851,12 +869,11 @@ ParseDateTime(char *timestr, char *lowstr,
else else
return -1; return -1;
} }
/* ignore punctuation but use as delimiter */ /* ignore other punctuation but use as delimiter */
else if (ispunct((unsigned char) *cp)) else if (ispunct((unsigned char) *cp))
{ {
cp++; cp++;
continue; continue;
} }
/* otherwise, something is not right... */ /* otherwise, something is not right... */
else else
...@@ -865,14 +882,12 @@ ParseDateTime(char *timestr, char *lowstr, ...@@ -865,14 +882,12 @@ ParseDateTime(char *timestr, char *lowstr,
/* force in a delimiter after each field */ /* force in a delimiter after each field */
*lp++ = '\0'; *lp++ = '\0';
nf++; nf++;
if (nf > MAXDATEFIELDS)
return -1;
} }
*numfields = nf; *numfields = nf;
return 0; return 0;
} /* ParseDateTime() */ }
/* DecodeDateTime() /* DecodeDateTime()
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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); ...@@ -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 void j2date(int jd, int *year, int *month, int *day);
extern int date2j(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, char **field, int *ftype,
int maxfields, int *numfields); int maxfields, int *numfields);
extern int DecodeDateTime(char **field, int *ftype, extern int DecodeDateTime(char **field, int *ftype,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment