mirror of
https://github.com/postgres/postgres.git
synced 2025-07-31 22:04:40 +03:00
Adjust datetime parsing to be more robust. We now pass the length of the
working buffer into ParseDateTime() and reject too-long input there, rather than checking the length of the input string before calling ParseDateTime(). The old method was bogus because ParseDateTime() can use a variable amount of working space, depending on the content of the input string (e.g. how many fields need to be NUL terminated). This fixes a minor stack overrun -- I don't _think_ it's exploitable, although I won't claim to be an expert. Along the way, fix a bug reported by Mark Dilger: the working buffer allocated by interval_in() was too short, which resulted in rejecting some perfectly valid interval input values. I added a regression test for this fix.
This commit is contained in:
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.108 2005/05/24 02:09:45 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.109 2005/05/26 02:04:13 neilc Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -65,12 +65,10 @@ date_in(PG_FUNCTION_ARGS)
|
|||||||
int dterr;
|
int dterr;
|
||||||
char *field[MAXDATEFIELDS];
|
char *field[MAXDATEFIELDS];
|
||||||
int ftype[MAXDATEFIELDS];
|
int ftype[MAXDATEFIELDS];
|
||||||
char lowstr[MAXDATELEN + 1];
|
char workbuf[MAXDATELEN + 1];
|
||||||
|
|
||||||
if (strlen(str) >= sizeof(lowstr))
|
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
|
||||||
dterr = DTERR_BAD_FORMAT;
|
field, ftype, MAXDATEFIELDS, &nf);
|
||||||
else
|
|
||||||
dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
|
|
||||||
if (dterr == 0)
|
if (dterr == 0)
|
||||||
dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp);
|
dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp);
|
||||||
if (dterr != 0)
|
if (dterr != 0)
|
||||||
@ -894,15 +892,13 @@ time_in(PG_FUNCTION_ARGS)
|
|||||||
int tz;
|
int tz;
|
||||||
int nf;
|
int nf;
|
||||||
int dterr;
|
int dterr;
|
||||||
char lowstr[MAXDATELEN + 1];
|
char workbuf[MAXDATELEN + 1];
|
||||||
char *field[MAXDATEFIELDS];
|
char *field[MAXDATEFIELDS];
|
||||||
int dtype;
|
int dtype;
|
||||||
int ftype[MAXDATEFIELDS];
|
int ftype[MAXDATEFIELDS];
|
||||||
|
|
||||||
if (strlen(str) >= sizeof(lowstr))
|
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
|
||||||
dterr = DTERR_BAD_FORMAT;
|
field, ftype, MAXDATEFIELDS, &nf);
|
||||||
else
|
|
||||||
dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
|
|
||||||
if (dterr == 0)
|
if (dterr == 0)
|
||||||
dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
|
dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
|
||||||
if (dterr != 0)
|
if (dterr != 0)
|
||||||
@ -1733,15 +1729,13 @@ timetz_in(PG_FUNCTION_ARGS)
|
|||||||
int tz;
|
int tz;
|
||||||
int nf;
|
int nf;
|
||||||
int dterr;
|
int dterr;
|
||||||
char lowstr[MAXDATELEN + 1];
|
char workbuf[MAXDATELEN + 1];
|
||||||
char *field[MAXDATEFIELDS];
|
char *field[MAXDATEFIELDS];
|
||||||
int dtype;
|
int dtype;
|
||||||
int ftype[MAXDATEFIELDS];
|
int ftype[MAXDATEFIELDS];
|
||||||
|
|
||||||
if (strlen(str) >= sizeof(lowstr))
|
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
|
||||||
dterr = DTERR_BAD_FORMAT;
|
field, ftype, MAXDATEFIELDS, &nf);
|
||||||
else
|
|
||||||
dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
|
|
||||||
if (dterr == 0)
|
if (dterr == 0)
|
||||||
dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
|
dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
|
||||||
if (dterr != 0)
|
if (dterr != 0)
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.144 2005/05/24 02:09:45 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.145 2005/05/26 02:04:13 neilc Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -699,21 +699,23 @@ 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, DTERR code if bogus input detected.
|
* Returns 0 if successful, DTERR code if bogus input detected.
|
||||||
*
|
*
|
||||||
* timestr - the input string
|
* timestr - the input string
|
||||||
* lowstr - workspace for field string storage (must be large enough for
|
* workbuf - workspace for field string storage. This must be
|
||||||
* a copy of the input string, including trailing null)
|
* larger than the largest legal input for this datetime type --
|
||||||
|
* some additional space will be needed to NUL terminate fields.
|
||||||
|
* buflen - the size of workbuf
|
||||||
* field[] - pointers to field strings are returned in this array
|
* field[] - pointers to field strings are returned in this array
|
||||||
* ftype[] - field type indicators are returned in this array
|
* ftype[] - field type indicators are returned in this array
|
||||||
* maxfields - dimensions of the above two arrays
|
* maxfields - dimensions of the above two arrays
|
||||||
* *numfields - set to the actual number of fields detected
|
* *numfields - set to the actual number of fields detected
|
||||||
*
|
*
|
||||||
* The fields extracted from the input are stored as separate, null-terminated
|
* The fields extracted from the input are stored as separate,
|
||||||
* strings in the workspace at lowstr. Any text is converted to lower case.
|
* null-terminated strings in the workspace at workbuf. 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
|
||||||
@ -729,12 +731,27 @@ TrimTrailingZeros(char *str)
|
|||||||
* DTK_DATE can hold Posix time zones (GMT-8)
|
* DTK_DATE can hold Posix time zones (GMT-8)
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
ParseDateTime(const char *timestr, char *lowstr,
|
ParseDateTime(const char *timestr, char *workbuf, size_t buflen,
|
||||||
char **field, int *ftype, int maxfields, int *numfields)
|
char **field, int *ftype, int maxfields, int *numfields)
|
||||||
{
|
{
|
||||||
int nf = 0;
|
int nf = 0;
|
||||||
const char *cp = timestr;
|
const char *cp = timestr;
|
||||||
char *lp = lowstr;
|
char *bufp = workbuf;
|
||||||
|
const char *bufend = workbuf + buflen;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the character pointed-to by "bufptr" to "newchar", and
|
||||||
|
* increment "bufptr". "end" gives the end of the buffer -- we
|
||||||
|
* return an error if there is no space left to append a character
|
||||||
|
* to the buffer. Note that "bufptr" is evaluated twice.
|
||||||
|
*/
|
||||||
|
#define APPEND_CHAR(bufptr, end, newchar) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if (((bufptr) + 1) >= (end)) \
|
||||||
|
return DTERR_BAD_FORMAT; \
|
||||||
|
*(bufptr)++ = newchar; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/* outer loop through fields */
|
/* outer loop through fields */
|
||||||
while (*cp != '\0')
|
while (*cp != '\0')
|
||||||
@ -749,23 +766,23 @@ ParseDateTime(const char *timestr, char *lowstr,
|
|||||||
/* Record start of current field */
|
/* Record start of current field */
|
||||||
if (nf >= maxfields)
|
if (nf >= maxfields)
|
||||||
return DTERR_BAD_FORMAT;
|
return DTERR_BAD_FORMAT;
|
||||||
field[nf] = lp;
|
field[nf] = bufp;
|
||||||
|
|
||||||
/* leading digit? then date or time */
|
/* leading digit? then date or time */
|
||||||
if (isdigit((unsigned char) *cp))
|
if (isdigit((unsigned char) *cp))
|
||||||
{
|
{
|
||||||
*lp++ = *cp++;
|
APPEND_CHAR(bufp, bufend, *cp++);
|
||||||
while (isdigit((unsigned char) *cp))
|
while (isdigit((unsigned char) *cp))
|
||||||
*lp++ = *cp++;
|
APPEND_CHAR(bufp, bufend, *cp++);
|
||||||
|
|
||||||
/* time field? */
|
/* time field? */
|
||||||
if (*cp == ':')
|
if (*cp == ':')
|
||||||
{
|
{
|
||||||
ftype[nf] = DTK_TIME;
|
ftype[nf] = DTK_TIME;
|
||||||
*lp++ = *cp++;
|
APPEND_CHAR(bufp, bufend, *cp++);
|
||||||
while (isdigit((unsigned char) *cp) ||
|
while (isdigit((unsigned char) *cp) ||
|
||||||
(*cp == ':') || (*cp == '.'))
|
(*cp == ':') || (*cp == '.'))
|
||||||
*lp++ = *cp++;
|
APPEND_CHAR(bufp, bufend, *cp++);
|
||||||
}
|
}
|
||||||
/* date field? allow embedded text month */
|
/* date field? allow embedded text month */
|
||||||
else if (*cp == '-' || *cp == '/' || *cp == '.')
|
else if (*cp == '-' || *cp == '/' || *cp == '.')
|
||||||
@ -773,13 +790,13 @@ ParseDateTime(const char *timestr, char *lowstr,
|
|||||||
/* save delimiting character to use later */
|
/* save delimiting character to use later */
|
||||||
char delim = *cp;
|
char delim = *cp;
|
||||||
|
|
||||||
*lp++ = *cp++;
|
APPEND_CHAR(bufp, bufend, *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] = ((delim == '.') ? DTK_NUMBER : DTK_DATE);
|
ftype[nf] = ((delim == '.') ? DTK_NUMBER : DTK_DATE);
|
||||||
while (isdigit((unsigned char) *cp))
|
while (isdigit((unsigned char) *cp))
|
||||||
*lp++ = *cp++;
|
APPEND_CHAR(bufp, bufend, *cp++);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* insist that the delimiters match to get a
|
* insist that the delimiters match to get a
|
||||||
@ -788,16 +805,16 @@ ParseDateTime(const char *timestr, char *lowstr,
|
|||||||
if (*cp == delim)
|
if (*cp == delim)
|
||||||
{
|
{
|
||||||
ftype[nf] = DTK_DATE;
|
ftype[nf] = DTK_DATE;
|
||||||
*lp++ = *cp++;
|
APPEND_CHAR(bufp, bufend, *cp++);
|
||||||
while (isdigit((unsigned char) *cp) || *cp == delim)
|
while (isdigit((unsigned char) *cp) || *cp == delim)
|
||||||
*lp++ = *cp++;
|
APPEND_CHAR(bufp, bufend, *cp++);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ftype[nf] = DTK_DATE;
|
ftype[nf] = DTK_DATE;
|
||||||
while (isalnum((unsigned char) *cp) || *cp == delim)
|
while (isalnum((unsigned char) *cp) || *cp == delim)
|
||||||
*lp++ = pg_tolower((unsigned char) *cp++);
|
APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -811,9 +828,9 @@ ParseDateTime(const char *timestr, char *lowstr,
|
|||||||
/* Leading decimal point? Then fractional seconds... */
|
/* Leading decimal point? Then fractional seconds... */
|
||||||
else if (*cp == '.')
|
else if (*cp == '.')
|
||||||
{
|
{
|
||||||
*lp++ = *cp++;
|
APPEND_CHAR(bufp, bufend, *cp++);
|
||||||
while (isdigit((unsigned char) *cp))
|
while (isdigit((unsigned char) *cp))
|
||||||
*lp++ = *cp++;
|
APPEND_CHAR(bufp, bufend, *cp++);
|
||||||
|
|
||||||
ftype[nf] = DTK_NUMBER;
|
ftype[nf] = DTK_NUMBER;
|
||||||
}
|
}
|
||||||
@ -825,9 +842,9 @@ ParseDateTime(const char *timestr, char *lowstr,
|
|||||||
else if (isalpha((unsigned char) *cp))
|
else if (isalpha((unsigned char) *cp))
|
||||||
{
|
{
|
||||||
ftype[nf] = DTK_STRING;
|
ftype[nf] = DTK_STRING;
|
||||||
*lp++ = pg_tolower((unsigned char) *cp++);
|
APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
|
||||||
while (isalpha((unsigned char) *cp))
|
while (isalpha((unsigned char) *cp))
|
||||||
*lp++ = pg_tolower((unsigned char) *cp++);
|
APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Full date string with leading text month? Could also be a
|
* Full date string with leading text month? Could also be a
|
||||||
@ -838,15 +855,15 @@ ParseDateTime(const char *timestr, char *lowstr,
|
|||||||
char delim = *cp;
|
char delim = *cp;
|
||||||
|
|
||||||
ftype[nf] = DTK_DATE;
|
ftype[nf] = DTK_DATE;
|
||||||
*lp++ = *cp++;
|
APPEND_CHAR(bufp, bufend, *cp++);
|
||||||
while (isdigit((unsigned char) *cp) || *cp == delim)
|
while (isdigit((unsigned char) *cp) || *cp == delim)
|
||||||
*lp++ = *cp++;
|
APPEND_CHAR(bufp, bufend, *cp++);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* sign? then special or numeric timezone */
|
/* sign? then special or numeric timezone */
|
||||||
else if (*cp == '+' || *cp == '-')
|
else if (*cp == '+' || *cp == '-')
|
||||||
{
|
{
|
||||||
*lp++ = *cp++;
|
APPEND_CHAR(bufp, bufend, *cp++);
|
||||||
/* soak up leading whitespace */
|
/* soak up leading whitespace */
|
||||||
while (isspace((unsigned char) *cp))
|
while (isspace((unsigned char) *cp))
|
||||||
cp++;
|
cp++;
|
||||||
@ -854,18 +871,18 @@ ParseDateTime(const char *timestr, char *lowstr,
|
|||||||
if (isdigit((unsigned char) *cp))
|
if (isdigit((unsigned char) *cp))
|
||||||
{
|
{
|
||||||
ftype[nf] = DTK_TZ;
|
ftype[nf] = DTK_TZ;
|
||||||
*lp++ = *cp++;
|
APPEND_CHAR(bufp, bufend, *cp++);
|
||||||
while (isdigit((unsigned char) *cp) ||
|
while (isdigit((unsigned char) *cp) ||
|
||||||
*cp == ':' || *cp == '.')
|
*cp == ':' || *cp == '.')
|
||||||
*lp++ = *cp++;
|
APPEND_CHAR(bufp, bufend, *cp++);
|
||||||
}
|
}
|
||||||
/* special? */
|
/* special? */
|
||||||
else if (isalpha((unsigned char) *cp))
|
else if (isalpha((unsigned char) *cp))
|
||||||
{
|
{
|
||||||
ftype[nf] = DTK_SPECIAL;
|
ftype[nf] = DTK_SPECIAL;
|
||||||
*lp++ = pg_tolower((unsigned char) *cp++);
|
APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
|
||||||
while (isalpha((unsigned char) *cp))
|
while (isalpha((unsigned char) *cp))
|
||||||
*lp++ = pg_tolower((unsigned char) *cp++);
|
APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
|
||||||
}
|
}
|
||||||
/* otherwise something wrong... */
|
/* otherwise something wrong... */
|
||||||
else
|
else
|
||||||
@ -882,7 +899,7 @@ ParseDateTime(const char *timestr, char *lowstr,
|
|||||||
return DTERR_BAD_FORMAT;
|
return DTERR_BAD_FORMAT;
|
||||||
|
|
||||||
/* force in a delimiter after each field */
|
/* force in a delimiter after each field */
|
||||||
*lp++ = '\0';
|
*bufp++ = '\0';
|
||||||
nf++;
|
nf++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/adt/nabstime.c,v 1.131 2005/05/24 02:09:45 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/adt/nabstime.c,v 1.132 2005/05/26 02:04:13 neilc Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -306,15 +306,13 @@ abstimein(PG_FUNCTION_ARGS)
|
|||||||
*tm = &date;
|
*tm = &date;
|
||||||
int dterr;
|
int dterr;
|
||||||
char *field[MAXDATEFIELDS];
|
char *field[MAXDATEFIELDS];
|
||||||
char lowstr[MAXDATELEN + 1];
|
char workbuf[MAXDATELEN + 1];
|
||||||
int dtype;
|
int dtype;
|
||||||
int nf,
|
int nf,
|
||||||
ftype[MAXDATEFIELDS];
|
ftype[MAXDATEFIELDS];
|
||||||
|
|
||||||
if (strlen(str) >= sizeof(lowstr))
|
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
|
||||||
dterr = DTERR_BAD_FORMAT;
|
field, ftype, MAXDATEFIELDS, &nf);
|
||||||
else
|
|
||||||
dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
|
|
||||||
if (dterr == 0)
|
if (dterr == 0)
|
||||||
dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
|
dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
|
||||||
if (dterr != 0)
|
if (dterr != 0)
|
||||||
@ -711,12 +709,10 @@ reltimein(PG_FUNCTION_ARGS)
|
|||||||
char *field[MAXDATEFIELDS];
|
char *field[MAXDATEFIELDS];
|
||||||
int nf,
|
int nf,
|
||||||
ftype[MAXDATEFIELDS];
|
ftype[MAXDATEFIELDS];
|
||||||
char lowstr[MAXDATELEN + 1];
|
char workbuf[MAXDATELEN + 1];
|
||||||
|
|
||||||
if (strlen(str) >= sizeof(lowstr))
|
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
|
||||||
dterr = DTERR_BAD_FORMAT;
|
field, ftype, MAXDATEFIELDS, &nf);
|
||||||
else
|
|
||||||
dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
|
|
||||||
if (dterr == 0)
|
if (dterr == 0)
|
||||||
dterr = DecodeInterval(field, ftype, nf, &dtype, tm, &fsec);
|
dterr = DecodeInterval(field, ftype, nf, &dtype, tm, &fsec);
|
||||||
if (dterr != 0)
|
if (dterr != 0)
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.123 2005/05/24 02:09:45 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.124 2005/05/26 02:04:13 neilc Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -77,12 +77,10 @@ timestamp_in(PG_FUNCTION_ARGS)
|
|||||||
int dterr;
|
int dterr;
|
||||||
char *field[MAXDATEFIELDS];
|
char *field[MAXDATEFIELDS];
|
||||||
int ftype[MAXDATEFIELDS];
|
int ftype[MAXDATEFIELDS];
|
||||||
char lowstr[MAXDATELEN + MAXDATEFIELDS];
|
char workbuf[MAXDATELEN + MAXDATEFIELDS];
|
||||||
|
|
||||||
if (strlen(str) >= sizeof(lowstr))
|
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
|
||||||
dterr = DTERR_BAD_FORMAT;
|
field, ftype, MAXDATEFIELDS, &nf);
|
||||||
else
|
|
||||||
dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
|
|
||||||
if (dterr == 0)
|
if (dterr == 0)
|
||||||
dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
|
dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
|
||||||
if (dterr != 0)
|
if (dterr != 0)
|
||||||
@ -317,12 +315,10 @@ timestamptz_in(PG_FUNCTION_ARGS)
|
|||||||
int dterr;
|
int dterr;
|
||||||
char *field[MAXDATEFIELDS];
|
char *field[MAXDATEFIELDS];
|
||||||
int ftype[MAXDATEFIELDS];
|
int ftype[MAXDATEFIELDS];
|
||||||
char lowstr[MAXDATELEN + MAXDATEFIELDS];
|
char workbuf[MAXDATELEN + MAXDATEFIELDS];
|
||||||
|
|
||||||
if (strlen(str) >= sizeof(lowstr))
|
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
|
||||||
dterr = DTERR_BAD_FORMAT;
|
field, ftype, MAXDATEFIELDS, &nf);
|
||||||
else
|
|
||||||
dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
|
|
||||||
if (dterr == 0)
|
if (dterr == 0)
|
||||||
dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
|
dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
|
||||||
if (dterr != 0)
|
if (dterr != 0)
|
||||||
@ -493,7 +489,7 @@ interval_in(PG_FUNCTION_ARGS)
|
|||||||
int dterr;
|
int dterr;
|
||||||
char *field[MAXDATEFIELDS];
|
char *field[MAXDATEFIELDS];
|
||||||
int ftype[MAXDATEFIELDS];
|
int ftype[MAXDATEFIELDS];
|
||||||
char lowstr[MAXDATELEN + MAXDATEFIELDS];
|
char workbuf[256];
|
||||||
|
|
||||||
tm->tm_year = 0;
|
tm->tm_year = 0;
|
||||||
tm->tm_mon = 0;
|
tm->tm_mon = 0;
|
||||||
@ -503,10 +499,8 @@ interval_in(PG_FUNCTION_ARGS)
|
|||||||
tm->tm_sec = 0;
|
tm->tm_sec = 0;
|
||||||
fsec = 0;
|
fsec = 0;
|
||||||
|
|
||||||
if (strlen(str) >= sizeof(lowstr))
|
dterr = ParseDateTime(str, workbuf, sizeof(workbuf), field,
|
||||||
dterr = DTERR_BAD_FORMAT;
|
ftype, MAXDATEFIELDS, &nf);
|
||||||
else
|
|
||||||
dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
|
|
||||||
if (dterr == 0)
|
if (dterr == 0)
|
||||||
dterr = DecodeInterval(field, ftype, nf, &dtype, tm, &fsec);
|
dterr = DecodeInterval(field, ftype, nf, &dtype, tm, &fsec);
|
||||||
if (dterr != 0)
|
if (dterr != 0)
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/utils/datetime.h,v 1.53 2005/05/24 04:03:01 momjian Exp $
|
* $PostgreSQL: pgsql/src/include/utils/datetime.h,v 1.54 2005/05/26 02:04:14 neilc Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -276,7 +276,7 @@ extern void GetCurrentTimeUsec(struct pg_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(const char *timestr, char *lowstr,
|
extern int ParseDateTime(const char *timestr, char *workbuf, size_t buflen,
|
||||||
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,
|
||||||
|
@ -221,3 +221,10 @@ select avg(f1) from interval_tbl;
|
|||||||
@ 4 years 1 mon 10 days 4 hours 18 mins 23 secs
|
@ 4 years 1 mon 10 days 4 hours 18 mins 23 secs
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
-- test long interval input
|
||||||
|
select '4 millenniums 5 centuries 4 decades 1 year 4 months 4 days 17 minutes 31 seconds'::interval;
|
||||||
|
interval
|
||||||
|
--------------------------------------------
|
||||||
|
@ 4541 years 4 mons 4 days 17 mins 31 secs
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
@ -66,3 +66,6 @@ SELECT '' AS ten, * FROM INTERVAL_TBL;
|
|||||||
-- updating pg_aggregate.agginitval
|
-- updating pg_aggregate.agginitval
|
||||||
|
|
||||||
select avg(f1) from interval_tbl;
|
select avg(f1) from interval_tbl;
|
||||||
|
|
||||||
|
-- test long interval input
|
||||||
|
select '4 millenniums 5 centuries 4 decades 1 year 4 months 4 days 17 minutes 31 seconds'::interval;
|
||||||
|
Reference in New Issue
Block a user