Re: [BUGS] BUG #1671: Long interval string representation rejected

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

Re: [BUGS] BUG #1671: Long interval string representation rejected

Neil Conway-2
Neil Conway wrote:
> I think we _can_ do it that way, it's just a question of whether that is
> the best approach. I think the solution I outlined before would work
> fine: pass the length of the working buffer to ParseDateTime(), and
> reject the input only if the parsing process actually requires more
> working space than was provided. [...]

> Or we could rewrite how we do parsing, which seems to be what you're
> suggesting.

Any thoughts on this, Tom? If you're planning on doing the rewrite you
described, that's fine; alternatively I'm happy to implement the fix
that I described above.

-Neil

---------------------------(end of broadcast)---------------------------
TIP 3: if posting/reading through Usenet, please send an appropriate
      subscribe-nomail command to [hidden email] so that your
      message can get through to the mailing list cleanly
Reply | Threaded
Open this post in threaded view
|

Re: [BUGS] BUG #1671: Long interval string representation rejected

Tom Lane-2
Neil Conway <[hidden email]> writes:
> Any thoughts on this, Tom? If you're planning on doing the rewrite you
> described, that's fine; alternatively I'm happy to implement the fix
> that I described above.

I'm not set on it --- fix it as you suggested.

                        regards, tom lane

---------------------------(end of broadcast)---------------------------
TIP 2: you can get off all lists at once with the unregister command
    (send "unregister YourEmailAddressHere" to [hidden email])
Reply | Threaded
Open this post in threaded view
|

Re: [BUGS] BUG #1671: Long interval string representation rejected

Neil Conway-2
Tom Lane wrote:
> I'm not set on it --- fix it as you suggested.

Attached is a patch that implements this. I'm not especially happy about
the implementation: defining _two_ local macros (that both
doubly-evaluate one of their arguments) is pretty ugly, but I didn't see
a cleaner alternative -- suggestions welcome.

This patch fixes the stack overrun. Since we now pass the length of the
working space into ParseDateTime(), it is also easy to fix Mark's bug: I
just increased the size of the interval_in() working buffer to 256
bytes. I didn't touch any of the other input buffer sizes, although that
shouldn't be taken as a vote of confidence that they are correct :) At
least the consequence of an insufficiently-large buffer is limited to
rejecting otherwise valid input, rather than potentially scribbling on
the stack.

-Neil

Index: src/backend/utils/adt/date.c
===================================================================
RCS file: /var/lib/cvs/pgsql/src/backend/utils/adt/date.c,v
retrieving revision 1.108
diff -c -r1.108 date.c
*** src/backend/utils/adt/date.c 24 May 2005 02:09:45 -0000 1.108
--- src/backend/utils/adt/date.c 24 May 2005 06:24:54 -0000
***************
*** 65,76 ****
  int dterr;
  char   *field[MAXDATEFIELDS];
  int ftype[MAXDATEFIELDS];
! char lowstr[MAXDATELEN + 1];
 
! if (strlen(str) >= sizeof(lowstr))
! dterr = DTERR_BAD_FORMAT;
! else
! dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp);
  if (dterr != 0)
--- 65,74 ----
  int dterr;
  char   *field[MAXDATEFIELDS];
  int ftype[MAXDATEFIELDS];
! char workbuf[MAXDATELEN + 1];
 
! dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
!  field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp);
  if (dterr != 0)
***************
*** 894,908 ****
  int tz;
  int nf;
  int dterr;
! char lowstr[MAXDATELEN + 1];
  char   *field[MAXDATEFIELDS];
  int dtype;
  int ftype[MAXDATEFIELDS];
 
! if (strlen(str) >= sizeof(lowstr))
! dterr = DTERR_BAD_FORMAT;
! else
! dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
  if (dterr != 0)
--- 892,904 ----
  int tz;
  int nf;
  int dterr;
! char workbuf[MAXDATELEN + 1];
  char   *field[MAXDATEFIELDS];
  int dtype;
  int ftype[MAXDATEFIELDS];
 
! dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
!  field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
  if (dterr != 0)
***************
*** 1733,1747 ****
  int tz;
  int nf;
  int dterr;
! char lowstr[MAXDATELEN + 1];
  char   *field[MAXDATEFIELDS];
  int dtype;
  int ftype[MAXDATEFIELDS];
 
! if (strlen(str) >= sizeof(lowstr))
! dterr = DTERR_BAD_FORMAT;
! else
! dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
  if (dterr != 0)
--- 1729,1741 ----
  int tz;
  int nf;
  int dterr;
! char workbuf[MAXDATELEN + 1];
  char   *field[MAXDATEFIELDS];
  int dtype;
  int ftype[MAXDATEFIELDS];
 
! dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
!  field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
  if (dterr != 0)
Index: src/backend/utils/adt/datetime.c
===================================================================
RCS file: /var/lib/cvs/pgsql/src/backend/utils/adt/datetime.c,v
retrieving revision 1.144
diff -c -r1.144 datetime.c
*** src/backend/utils/adt/datetime.c 24 May 2005 02:09:45 -0000 1.144
--- src/backend/utils/adt/datetime.c 24 May 2005 06:40:01 -0000
***************
*** 699,719 ****
  }
  }
 
-
  /* ParseDateTime()
   * Break string into tokens based on a date/time context.
   * Returns 0 if successful, DTERR code 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
--- 699,721 ----
  }
  }
 
  /* ParseDateTime()
   * Break string into tokens based on a date/time context.
   * Returns 0 if successful, DTERR code if bogus input detected.
   *
   * timestr - the input string
!  * workbuf - workspace for field string storage. This must be
!  *   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
   * 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 workbuf. Any text is
!  * converted to lower case.
   *
   * Several field types are assigned:
   * DTK_NUMBER - digits and (possibly) a decimal point
***************
*** 729,740 ****
   * DTK_DATE can hold Posix time zones (GMT-8)
   */
  int
! ParseDateTime(const char *timestr, char *lowstr,
   char **field, int *ftype, int maxfields, int *numfields)
  {
  int nf = 0;
  const char *cp = timestr;
! char   *lp = lowstr;
 
  /* outer loop through fields */
  while (*cp != '\0')
--- 731,765 ----
   * DTK_DATE can hold Posix time zones (GMT-8)
   */
  int
! ParseDateTime(const char *timestr, char *workbuf, size_t buflen,
   char **field, int *ftype, int maxfields, int *numfields)
  {
  int nf = 0;
  const char *cp = timestr;
! char   *bufp = workbuf;
! const char *bufend = workbuf + buflen;
!
! /*
! * Append the character at "inptr" to the current position
! * "bufptr", and increment both pointers. Returns an error if
! * there is no space left in bufptr ("end" marks the last element
! * of the buffer). Beware of the double evaluation of "bufptr".
! */
! #define APPEND_CHAR(bufptr, inptr, end) \
! do \
! { \
! if (((bufptr) + 1) >= (end)) \
! return DTERR_BAD_FORMAT; \
! *(bufptr)++ = *(inptr)++; \
! } while (0);
!
! #define APPEND_LOWER_CHAR(bufptr, inptr, end) \
! do \
! { \
! if (((bufptr) + 1) >= (end)) \
! return DTERR_BAD_FORMAT; \
! *(bufptr)++ = pg_tolower((unsigned char) *(inptr)++); \
! } while (0);
 
  /* outer loop through fields */
  while (*cp != '\0')
***************
*** 749,771 ****
  /* Record start of current field */
  if (nf >= maxfields)
  return DTERR_BAD_FORMAT;
! field[nf] = lp;
 
  /* leading digit? then date or time */
  if (isdigit((unsigned char) *cp))
  {
! *lp++ = *cp++;
  while (isdigit((unsigned char) *cp))
! *lp++ = *cp++;
 
  /* time field? */
  if (*cp == ':')
  {
  ftype[nf] = DTK_TIME;
! *lp++ = *cp++;
  while (isdigit((unsigned char) *cp) ||
    (*cp == ':') || (*cp == '.'))
! *lp++ = *cp++;
  }
  /* date field? allow embedded text month */
  else if (*cp == '-' || *cp == '/' || *cp == '.')
--- 774,796 ----
  /* Record start of current field */
  if (nf >= maxfields)
  return DTERR_BAD_FORMAT;
! field[nf] = bufp;
 
  /* leading digit? then date or time */
  if (isdigit((unsigned char) *cp))
  {
! APPEND_CHAR(bufp, cp, bufend);
  while (isdigit((unsigned char) *cp))
! APPEND_CHAR(bufp, cp, bufend);
 
  /* time field? */
  if (*cp == ':')
  {
  ftype[nf] = DTK_TIME;
! APPEND_CHAR(bufp, cp, bufend);
  while (isdigit((unsigned char) *cp) ||
    (*cp == ':') || (*cp == '.'))
! APPEND_CHAR(bufp, cp, bufend);
  }
  /* date field? allow embedded text month */
  else if (*cp == '-' || *cp == '/' || *cp == '.')
***************
*** 773,785 ****
  /* save delimiting character to use later */
  char delim = *cp;
 
! *lp++ = *cp++;
  /* second field is all digits? then no embedded text month */
  if (isdigit((unsigned char) *cp))
  {
  ftype[nf] = ((delim == '.') ? DTK_NUMBER : DTK_DATE);
  while (isdigit((unsigned char) *cp))
! *lp++ = *cp++;
 
  /*
  * insist that the delimiters match to get a
--- 798,810 ----
  /* save delimiting character to use later */
  char delim = *cp;
 
! APPEND_CHAR(bufp, cp, bufend);
  /* second field is all digits? then no embedded text month */
  if (isdigit((unsigned char) *cp))
  {
  ftype[nf] = ((delim == '.') ? DTK_NUMBER : DTK_DATE);
  while (isdigit((unsigned char) *cp))
! APPEND_CHAR(bufp, cp, bufend);
 
  /*
  * insist that the delimiters match to get a
***************
*** 788,803 ****
  if (*cp == delim)
  {
  ftype[nf] = DTK_DATE;
! *lp++ = *cp++;
  while (isdigit((unsigned char) *cp) || *cp == delim)
! *lp++ = *cp++;
  }
  }
  else
  {
  ftype[nf] = DTK_DATE;
  while (isalnum((unsigned char) *cp) || *cp == delim)
! *lp++ = pg_tolower((unsigned char) *cp++);
  }
  }
 
--- 813,828 ----
  if (*cp == delim)
  {
  ftype[nf] = DTK_DATE;
! APPEND_CHAR(bufp, cp, bufend);
  while (isdigit((unsigned char) *cp) || *cp == delim)
! APPEND_LOWER_CHAR(bufp, cp, bufend);
  }
  }
  else
  {
  ftype[nf] = DTK_DATE;
  while (isalnum((unsigned char) *cp) || *cp == delim)
! APPEND_LOWER_CHAR(bufp, cp, bufend);
  }
  }
 
***************
*** 811,819 ****
  /* Leading decimal point? Then fractional seconds... */
  else if (*cp == '.')
  {
! *lp++ = *cp++;
  while (isdigit((unsigned char) *cp))
! *lp++ = *cp++;
 
  ftype[nf] = DTK_NUMBER;
  }
--- 836,844 ----
  /* Leading decimal point? Then fractional seconds... */
  else if (*cp == '.')
  {
! APPEND_CHAR(bufp, cp, bufend);
  while (isdigit((unsigned char) *cp))
! APPEND_CHAR(bufp, cp, bufend);
 
  ftype[nf] = DTK_NUMBER;
  }
***************
*** 825,833 ****
  else if (isalpha((unsigned char) *cp))
  {
  ftype[nf] = DTK_STRING;
! *lp++ = pg_tolower((unsigned char) *cp++);
  while (isalpha((unsigned char) *cp))
! *lp++ = pg_tolower((unsigned char) *cp++);
 
  /*
  * Full date string with leading text month? Could also be a
--- 850,858 ----
  else if (isalpha((unsigned char) *cp))
  {
  ftype[nf] = DTK_STRING;
! APPEND_LOWER_CHAR(bufp, cp, bufend);
  while (isalpha((unsigned char) *cp))
! APPEND_LOWER_CHAR(bufp, cp, bufend);
 
  /*
  * Full date string with leading text month? Could also be a
***************
*** 838,852 ****
  char delim = *cp;
 
  ftype[nf] = DTK_DATE;
! *lp++ = *cp++;
  while (isdigit((unsigned char) *cp) || *cp == delim)
! *lp++ = *cp++;
  }
  }
  /* sign? then special or numeric timezone */
  else if (*cp == '+' || *cp == '-')
  {
! *lp++ = *cp++;
  /* soak up leading whitespace */
  while (isspace((unsigned char) *cp))
  cp++;
--- 863,877 ----
  char delim = *cp;
 
  ftype[nf] = DTK_DATE;
! APPEND_CHAR(bufp, cp, bufend);
  while (isdigit((unsigned char) *cp) || *cp == delim)
! APPEND_CHAR(bufp, cp, bufend);
  }
  }
  /* sign? then special or numeric timezone */
  else if (*cp == '+' || *cp == '-')
  {
! APPEND_CHAR(bufp, cp, bufend);
  /* soak up leading whitespace */
  while (isspace((unsigned char) *cp))
  cp++;
***************
*** 854,871 ****
  if (isdigit((unsigned char) *cp))
  {
  ftype[nf] = DTK_TZ;
! *lp++ = *cp++;
  while (isdigit((unsigned char) *cp) ||
    *cp == ':' || *cp == '.')
! *lp++ = *cp++;
  }
  /* special? */
  else if (isalpha((unsigned char) *cp))
  {
  ftype[nf] = DTK_SPECIAL;
! *lp++ = pg_tolower((unsigned char) *cp++);
  while (isalpha((unsigned char) *cp))
! *lp++ = pg_tolower((unsigned char) *cp++);
  }
  /* otherwise something wrong... */
  else
--- 879,896 ----
  if (isdigit((unsigned char) *cp))
  {
  ftype[nf] = DTK_TZ;
! APPEND_CHAR(bufp, cp, bufend);
  while (isdigit((unsigned char) *cp) ||
    *cp == ':' || *cp == '.')
! APPEND_CHAR(bufp, cp, bufend);
  }
  /* special? */
  else if (isalpha((unsigned char) *cp))
  {
  ftype[nf] = DTK_SPECIAL;
! APPEND_LOWER_CHAR(bufp, cp, bufend);
  while (isalpha((unsigned char) *cp))
! APPEND_LOWER_CHAR(bufp, cp, bufend);
  }
  /* otherwise something wrong... */
  else
***************
*** 882,888 ****
  return DTERR_BAD_FORMAT;
 
  /* force in a delimiter after each field */
! *lp++ = '\0';
  nf++;
  }
 
--- 907,913 ----
  return DTERR_BAD_FORMAT;
 
  /* force in a delimiter after each field */
! *bufp++ = '\0';
  nf++;
  }
 
Index: src/backend/utils/adt/nabstime.c
===================================================================
RCS file: /var/lib/cvs/pgsql/src/backend/utils/adt/nabstime.c,v
retrieving revision 1.131
diff -c -r1.131 nabstime.c
*** src/backend/utils/adt/nabstime.c 24 May 2005 02:09:45 -0000 1.131
--- src/backend/utils/adt/nabstime.c 24 May 2005 06:24:54 -0000
***************
*** 306,320 ****
    *tm = &date;
  int dterr;
  char   *field[MAXDATEFIELDS];
! char lowstr[MAXDATELEN + 1];
  int dtype;
  int nf,
  ftype[MAXDATEFIELDS];
 
! if (strlen(str) >= sizeof(lowstr))
! dterr = DTERR_BAD_FORMAT;
! else
! dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
  if (dterr != 0)
--- 306,318 ----
    *tm = &date;
  int dterr;
  char   *field[MAXDATEFIELDS];
! char workbuf[MAXDATELEN + 1];
  int dtype;
  int nf,
  ftype[MAXDATEFIELDS];
 
! dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
!  field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
  if (dterr != 0)
***************
*** 711,722 ****
  char   *field[MAXDATEFIELDS];
  int nf,
  ftype[MAXDATEFIELDS];
! char lowstr[MAXDATELEN + 1];
 
! if (strlen(str) >= sizeof(lowstr))
! dterr = DTERR_BAD_FORMAT;
! else
! dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeInterval(field, ftype, nf, &dtype, tm, &fsec);
  if (dterr != 0)
--- 709,718 ----
  char   *field[MAXDATEFIELDS];
  int nf,
  ftype[MAXDATEFIELDS];
! char workbuf[MAXDATELEN + 1];
 
! dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
!  field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeInterval(field, ftype, nf, &dtype, tm, &fsec);
  if (dterr != 0)
Index: src/backend/utils/adt/timestamp.c
===================================================================
RCS file: /var/lib/cvs/pgsql/src/backend/utils/adt/timestamp.c,v
retrieving revision 1.123
diff -c -r1.123 timestamp.c
*** src/backend/utils/adt/timestamp.c 24 May 2005 02:09:45 -0000 1.123
--- src/backend/utils/adt/timestamp.c 24 May 2005 06:24:54 -0000
***************
*** 77,88 ****
  int dterr;
  char   *field[MAXDATEFIELDS];
  int ftype[MAXDATEFIELDS];
! char lowstr[MAXDATELEN + MAXDATEFIELDS];
 
! if (strlen(str) >= sizeof(lowstr))
! dterr = DTERR_BAD_FORMAT;
! else
! dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
  if (dterr != 0)
--- 77,86 ----
  int dterr;
  char   *field[MAXDATEFIELDS];
  int ftype[MAXDATEFIELDS];
! char workbuf[MAXDATELEN + MAXDATEFIELDS];
 
! dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
!  field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
  if (dterr != 0)
***************
*** 317,328 ****
  int dterr;
  char   *field[MAXDATEFIELDS];
  int ftype[MAXDATEFIELDS];
! char lowstr[MAXDATELEN + MAXDATEFIELDS];
 
! if (strlen(str) >= sizeof(lowstr))
! dterr = DTERR_BAD_FORMAT;
! else
! dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
  if (dterr != 0)
--- 315,324 ----
  int dterr;
  char   *field[MAXDATEFIELDS];
  int ftype[MAXDATEFIELDS];
! char workbuf[MAXDATELEN + MAXDATEFIELDS];
 
! dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
!  field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
  if (dterr != 0)
***************
*** 493,499 ****
  int dterr;
  char   *field[MAXDATEFIELDS];
  int ftype[MAXDATEFIELDS];
! char lowstr[MAXDATELEN + MAXDATEFIELDS];
 
  tm->tm_year = 0;
  tm->tm_mon = 0;
--- 489,495 ----
  int dterr;
  char   *field[MAXDATEFIELDS];
  int ftype[MAXDATEFIELDS];
! char workbuf[256];
 
  tm->tm_year = 0;
  tm->tm_mon = 0;
***************
*** 503,512 ****
  tm->tm_sec = 0;
  fsec = 0;
 
! if (strlen(str) >= sizeof(lowstr))
! dterr = DTERR_BAD_FORMAT;
! else
! dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeInterval(field, ftype, nf, &dtype, tm, &fsec);
  if (dterr != 0)
--- 499,506 ----
  tm->tm_sec = 0;
  fsec = 0;
 
! dterr = ParseDateTime(str, workbuf, sizeof(workbuf), field,
!  ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeInterval(field, ftype, nf, &dtype, tm, &fsec);
  if (dterr != 0)
Index: src/include/utils/datetime.h
===================================================================
RCS file: /var/lib/cvs/pgsql/src/include/utils/datetime.h,v
retrieving revision 1.53
diff -c -r1.53 datetime.h
*** src/include/utils/datetime.h 24 May 2005 04:03:01 -0000 1.53
--- src/include/utils/datetime.h 24 May 2005 06:24:54 -0000
***************
*** 276,282 ****
  extern void j2date(int jd, int *year, int *month, int *day);
  extern int date2j(int year, int month, int day);
 
! extern int ParseDateTime(const char *timestr, char *lowstr,
   char **field, int *ftype,
   int maxfields, int *numfields);
  extern int DecodeDateTime(char **field, int *ftype,
--- 276,282 ----
  extern void j2date(int jd, int *year, int *month, int *day);
  extern int date2j(int year, int month, int day);
 
! extern int ParseDateTime(const char *timestr, char *workbuf, size_t buflen,
   char **field, int *ftype,
   int maxfields, int *numfields);
  extern int DecodeDateTime(char **field, int *ftype,
Index: src/test/regress/expected/interval.out
===================================================================
RCS file: /var/lib/cvs/pgsql/src/test/regress/expected/interval.out,v
retrieving revision 1.10
diff -c -r1.10 interval.out
*** src/test/regress/expected/interval.out 7 Apr 2005 01:51:40 -0000 1.10
--- src/test/regress/expected/interval.out 24 May 2005 06:24:54 -0000
***************
*** 221,223 ****
--- 221,230 ----
   @ 4 years 1 mon 10 days 4 hours 18 mins 23 secs
  (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)
+
Index: src/test/regress/sql/interval.sql
===================================================================
RCS file: /var/lib/cvs/pgsql/src/test/regress/sql/interval.sql,v
retrieving revision 1.6
diff -c -r1.6 interval.sql
*** src/test/regress/sql/interval.sql 7 Apr 2005 01:51:41 -0000 1.6
--- src/test/regress/sql/interval.sql 24 May 2005 06:24:54 -0000
***************
*** 66,68 ****
--- 66,71 ----
  -- updating pg_aggregate.agginitval
 
  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;


---------------------------(end of broadcast)---------------------------
TIP 9: the planner will ignore your desire to choose an index scan if your
      joining column's datatypes do not match
Reply | Threaded
Open this post in threaded view
|

Re: [BUGS] BUG #1671: Long interval string representation rejected

Tom Lane-2
Neil Conway <[hidden email]> writes:
> Attached is a patch that implements this. I'm not especially happy about
> the implementation: defining _two_ local macros (that both
> doubly-evaluate one of their arguments) is pretty ugly, but I didn't see
> a cleaner alternative -- suggestions welcome.

Considering that you're incrementing bufptr inside the macro, it hardly
seems that double-evaluation is a problem: the argument pretty much has
to be a variable.  OTOH there is no reason for the input argument to be
treated that way.  I'd suggest just one macro

#define APPEND_CHAR(bufptr, end, newchar) \
        do \
        { \
                if (((bufptr) + 1) >= (end)) \
                        return DTERR_BAD_FORMAT; \
                *(bufptr)++ = (newchar); \
        } while (0);

used as

        APPEND_CHAR(bufp, bufend, *cp++);
        APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));

respectively.

                        regards, tom lane

---------------------------(end of broadcast)---------------------------
TIP 1: subscribe and unsubscribe commands go to [hidden email]
Reply | Threaded
Open this post in threaded view
|

Re: [BUGS] BUG #1671: Long interval string representation rejected

Tom Lane-2
I wrote:
> #define APPEND_CHAR(bufptr, end, newchar) \
> do \
> { \
> if (((bufptr) + 1) >= (end)) \
> return DTERR_BAD_FORMAT; \
> *(bufptr)++ = (newchar); \
> } while (0);

Oh BTW, there definitely should not be a semicolon at the end
of that macro ...

                        regards, tom lane

---------------------------(end of broadcast)---------------------------
TIP 3: if posting/reading through Usenet, please send an appropriate
      subscribe-nomail command to [hidden email] so that your
      message can get through to the mailing list cleanly
Reply | Threaded
Open this post in threaded view
|

Re: [BUGS] BUG #1671: Long interval string representation rejected

Neil Conway-2
In reply to this post by Tom Lane-2
Tom Lane wrote:
> Considering that you're incrementing bufptr inside the macro, it hardly
> seems that double-evaluation is a problem: the argument pretty much has
> to be a variable.  OTOH there is no reason for the input argument to be
> treated that way.  I'd suggest just one macro [...]

Ah, yeah, that works. Attached is a revised patch -- I'll apply it
tomorrow barring any objections. I also fixed the semi-colon -- thanks
for the review.

-Neil

Index: src/backend/utils/adt/date.c
===================================================================
RCS file: /var/lib/cvs/pgsql/src/backend/utils/adt/date.c,v
retrieving revision 1.108
diff -c -r1.108 date.c
*** src/backend/utils/adt/date.c 24 May 2005 02:09:45 -0000 1.108
--- src/backend/utils/adt/date.c 25 May 2005 01:06:27 -0000
***************
*** 65,76 ****
  int dterr;
  char   *field[MAXDATEFIELDS];
  int ftype[MAXDATEFIELDS];
! char lowstr[MAXDATELEN + 1];
 
! if (strlen(str) >= sizeof(lowstr))
! dterr = DTERR_BAD_FORMAT;
! else
! dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp);
  if (dterr != 0)
--- 65,74 ----
  int dterr;
  char   *field[MAXDATEFIELDS];
  int ftype[MAXDATEFIELDS];
! char workbuf[MAXDATELEN + 1];
 
! dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
!  field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp);
  if (dterr != 0)
***************
*** 894,908 ****
  int tz;
  int nf;
  int dterr;
! char lowstr[MAXDATELEN + 1];
  char   *field[MAXDATEFIELDS];
  int dtype;
  int ftype[MAXDATEFIELDS];
 
! if (strlen(str) >= sizeof(lowstr))
! dterr = DTERR_BAD_FORMAT;
! else
! dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
  if (dterr != 0)
--- 892,904 ----
  int tz;
  int nf;
  int dterr;
! char workbuf[MAXDATELEN + 1];
  char   *field[MAXDATEFIELDS];
  int dtype;
  int ftype[MAXDATEFIELDS];
 
! dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
!  field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
  if (dterr != 0)
***************
*** 1733,1747 ****
  int tz;
  int nf;
  int dterr;
! char lowstr[MAXDATELEN + 1];
  char   *field[MAXDATEFIELDS];
  int dtype;
  int ftype[MAXDATEFIELDS];
 
! if (strlen(str) >= sizeof(lowstr))
! dterr = DTERR_BAD_FORMAT;
! else
! dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
  if (dterr != 0)
--- 1729,1741 ----
  int tz;
  int nf;
  int dterr;
! char workbuf[MAXDATELEN + 1];
  char   *field[MAXDATEFIELDS];
  int dtype;
  int ftype[MAXDATEFIELDS];
 
! dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
!  field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
  if (dterr != 0)
Index: src/backend/utils/adt/datetime.c
===================================================================
RCS file: /var/lib/cvs/pgsql/src/backend/utils/adt/datetime.c,v
retrieving revision 1.144
diff -c -r1.144 datetime.c
*** src/backend/utils/adt/datetime.c 24 May 2005 02:09:45 -0000 1.144
--- src/backend/utils/adt/datetime.c 25 May 2005 01:43:50 -0000
***************
*** 699,719 ****
  }
  }
 
-
  /* ParseDateTime()
   * Break string into tokens based on a date/time context.
   * Returns 0 if successful, DTERR code 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
--- 699,721 ----
  }
  }
 
  /* ParseDateTime()
   * Break string into tokens based on a date/time context.
   * Returns 0 if successful, DTERR code if bogus input detected.
   *
   * timestr - the input string
!  * workbuf - workspace for field string storage. This must be
!  *   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
   * 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 workbuf. Any text is
!  * converted to lower case.
   *
   * Several field types are assigned:
   * DTK_NUMBER - digits and (possibly) a decimal point
***************
*** 729,740 ****
   * DTK_DATE can hold Posix time zones (GMT-8)
   */
  int
! ParseDateTime(const char *timestr, char *lowstr,
   char **field, int *ftype, int maxfields, int *numfields)
  {
  int nf = 0;
  const char *cp = timestr;
! char   *lp = lowstr;
 
  /* outer loop through fields */
  while (*cp != '\0')
--- 731,757 ----
   * DTK_DATE can hold Posix time zones (GMT-8)
   */
  int
! ParseDateTime(const char *timestr, char *workbuf, size_t buflen,
   char **field, int *ftype, int maxfields, int *numfields)
  {
  int nf = 0;
  const char *cp = timestr;
! 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 --
! * returns an error if there is no space left to append a
! * character.
! */
! #define APPEND_CHAR(bufptr, end, newchar) \
! do \
! { \
! if (((bufptr) + 1) >= (end)) \
! return DTERR_BAD_FORMAT; \
! *(bufptr)++ = newchar; \
! } while (0)
 
  /* outer loop through fields */
  while (*cp != '\0')
***************
*** 749,771 ****
  /* Record start of current field */
  if (nf >= maxfields)
  return DTERR_BAD_FORMAT;
! field[nf] = lp;
 
  /* leading digit? then date or time */
  if (isdigit((unsigned char) *cp))
  {
! *lp++ = *cp++;
  while (isdigit((unsigned char) *cp))
! *lp++ = *cp++;
 
  /* time field? */
  if (*cp == ':')
  {
  ftype[nf] = DTK_TIME;
! *lp++ = *cp++;
  while (isdigit((unsigned char) *cp) ||
    (*cp == ':') || (*cp == '.'))
! *lp++ = *cp++;
  }
  /* date field? allow embedded text month */
  else if (*cp == '-' || *cp == '/' || *cp == '.')
--- 766,788 ----
  /* Record start of current field */
  if (nf >= maxfields)
  return DTERR_BAD_FORMAT;
! field[nf] = bufp;
 
  /* leading digit? then date or time */
  if (isdigit((unsigned char) *cp))
  {
! APPEND_CHAR(bufp, bufend, *cp++);
  while (isdigit((unsigned char) *cp))
! APPEND_CHAR(bufp, bufend, *cp++);
 
  /* time field? */
  if (*cp == ':')
  {
  ftype[nf] = DTK_TIME;
! APPEND_CHAR(bufp, bufend, *cp++);
  while (isdigit((unsigned char) *cp) ||
    (*cp == ':') || (*cp == '.'))
! APPEND_CHAR(bufp, bufend, *cp++);
  }
  /* date field? allow embedded text month */
  else if (*cp == '-' || *cp == '/' || *cp == '.')
***************
*** 773,785 ****
  /* save delimiting character to use later */
  char delim = *cp;
 
! *lp++ = *cp++;
  /* second field is all digits? then no embedded text month */
  if (isdigit((unsigned char) *cp))
  {
  ftype[nf] = ((delim == '.') ? DTK_NUMBER : DTK_DATE);
  while (isdigit((unsigned char) *cp))
! *lp++ = *cp++;
 
  /*
  * insist that the delimiters match to get a
--- 790,802 ----
  /* save delimiting character to use later */
  char delim = *cp;
 
! APPEND_CHAR(bufp, bufend, *cp++);
  /* second field is all digits? then no embedded text month */
  if (isdigit((unsigned char) *cp))
  {
  ftype[nf] = ((delim == '.') ? DTK_NUMBER : DTK_DATE);
  while (isdigit((unsigned char) *cp))
! APPEND_CHAR(bufp, bufend, *cp++);
 
  /*
  * insist that the delimiters match to get a
***************
*** 788,803 ****
  if (*cp == delim)
  {
  ftype[nf] = DTK_DATE;
! *lp++ = *cp++;
  while (isdigit((unsigned char) *cp) || *cp == delim)
! *lp++ = *cp++;
  }
  }
  else
  {
  ftype[nf] = DTK_DATE;
  while (isalnum((unsigned char) *cp) || *cp == delim)
! *lp++ = pg_tolower((unsigned char) *cp++);
  }
  }
 
--- 805,820 ----
  if (*cp == delim)
  {
  ftype[nf] = DTK_DATE;
! APPEND_CHAR(bufp, bufend, *cp++);
  while (isdigit((unsigned char) *cp) || *cp == delim)
! APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
  }
  }
  else
  {
  ftype[nf] = DTK_DATE;
  while (isalnum((unsigned char) *cp) || *cp == delim)
! APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
  }
  }
 
***************
*** 811,819 ****
  /* Leading decimal point? Then fractional seconds... */
  else if (*cp == '.')
  {
! *lp++ = *cp++;
  while (isdigit((unsigned char) *cp))
! *lp++ = *cp++;
 
  ftype[nf] = DTK_NUMBER;
  }
--- 828,836 ----
  /* Leading decimal point? Then fractional seconds... */
  else if (*cp == '.')
  {
! APPEND_CHAR(bufp, bufend, *cp++);
  while (isdigit((unsigned char) *cp))
! APPEND_CHAR(bufp, bufend, *cp++);
 
  ftype[nf] = DTK_NUMBER;
  }
***************
*** 825,833 ****
  else if (isalpha((unsigned char) *cp))
  {
  ftype[nf] = DTK_STRING;
! *lp++ = pg_tolower((unsigned char) *cp++);
  while (isalpha((unsigned char) *cp))
! *lp++ = pg_tolower((unsigned char) *cp++);
 
  /*
  * Full date string with leading text month? Could also be a
--- 842,850 ----
  else if (isalpha((unsigned char) *cp))
  {
  ftype[nf] = DTK_STRING;
! APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
  while (isalpha((unsigned char) *cp))
! APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
 
  /*
  * Full date string with leading text month? Could also be a
***************
*** 838,852 ****
  char delim = *cp;
 
  ftype[nf] = DTK_DATE;
! *lp++ = *cp++;
  while (isdigit((unsigned char) *cp) || *cp == delim)
! *lp++ = *cp++;
  }
  }
  /* sign? then special or numeric timezone */
  else if (*cp == '+' || *cp == '-')
  {
! *lp++ = *cp++;
  /* soak up leading whitespace */
  while (isspace((unsigned char) *cp))
  cp++;
--- 855,869 ----
  char delim = *cp;
 
  ftype[nf] = DTK_DATE;
! APPEND_CHAR(bufp, bufend, *cp++);
  while (isdigit((unsigned char) *cp) || *cp == delim)
! APPEND_CHAR(bufp, bufend, *cp++);
  }
  }
  /* sign? then special or numeric timezone */
  else if (*cp == '+' || *cp == '-')
  {
! APPEND_CHAR(bufp, bufend, *cp++);
  /* soak up leading whitespace */
  while (isspace((unsigned char) *cp))
  cp++;
***************
*** 854,871 ****
  if (isdigit((unsigned char) *cp))
  {
  ftype[nf] = DTK_TZ;
! *lp++ = *cp++;
  while (isdigit((unsigned char) *cp) ||
    *cp == ':' || *cp == '.')
! *lp++ = *cp++;
  }
  /* special? */
  else if (isalpha((unsigned char) *cp))
  {
  ftype[nf] = DTK_SPECIAL;
! *lp++ = pg_tolower((unsigned char) *cp++);
  while (isalpha((unsigned char) *cp))
! *lp++ = pg_tolower((unsigned char) *cp++);
  }
  /* otherwise something wrong... */
  else
--- 871,888 ----
  if (isdigit((unsigned char) *cp))
  {
  ftype[nf] = DTK_TZ;
! APPEND_CHAR(bufp, bufend, *cp++);
  while (isdigit((unsigned char) *cp) ||
    *cp == ':' || *cp == '.')
! APPEND_CHAR(bufp, bufend, *cp++);
  }
  /* special? */
  else if (isalpha((unsigned char) *cp))
  {
  ftype[nf] = DTK_SPECIAL;
! APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
  while (isalpha((unsigned char) *cp))
! APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
  }
  /* otherwise something wrong... */
  else
***************
*** 882,888 ****
  return DTERR_BAD_FORMAT;
 
  /* force in a delimiter after each field */
! *lp++ = '\0';
  nf++;
  }
 
--- 899,905 ----
  return DTERR_BAD_FORMAT;
 
  /* force in a delimiter after each field */
! *bufp++ = '\0';
  nf++;
  }
 
Index: src/backend/utils/adt/nabstime.c
===================================================================
RCS file: /var/lib/cvs/pgsql/src/backend/utils/adt/nabstime.c,v
retrieving revision 1.131
diff -c -r1.131 nabstime.c
*** src/backend/utils/adt/nabstime.c 24 May 2005 02:09:45 -0000 1.131
--- src/backend/utils/adt/nabstime.c 25 May 2005 01:06:27 -0000
***************
*** 306,320 ****
    *tm = &date;
  int dterr;
  char   *field[MAXDATEFIELDS];
! char lowstr[MAXDATELEN + 1];
  int dtype;
  int nf,
  ftype[MAXDATEFIELDS];
 
! if (strlen(str) >= sizeof(lowstr))
! dterr = DTERR_BAD_FORMAT;
! else
! dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
  if (dterr != 0)
--- 306,318 ----
    *tm = &date;
  int dterr;
  char   *field[MAXDATEFIELDS];
! char workbuf[MAXDATELEN + 1];
  int dtype;
  int nf,
  ftype[MAXDATEFIELDS];
 
! dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
!  field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
  if (dterr != 0)
***************
*** 711,722 ****
  char   *field[MAXDATEFIELDS];
  int nf,
  ftype[MAXDATEFIELDS];
! char lowstr[MAXDATELEN + 1];
 
! if (strlen(str) >= sizeof(lowstr))
! dterr = DTERR_BAD_FORMAT;
! else
! dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeInterval(field, ftype, nf, &dtype, tm, &fsec);
  if (dterr != 0)
--- 709,718 ----
  char   *field[MAXDATEFIELDS];
  int nf,
  ftype[MAXDATEFIELDS];
! char workbuf[MAXDATELEN + 1];
 
! dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
!  field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeInterval(field, ftype, nf, &dtype, tm, &fsec);
  if (dterr != 0)
Index: src/backend/utils/adt/timestamp.c
===================================================================
RCS file: /var/lib/cvs/pgsql/src/backend/utils/adt/timestamp.c,v
retrieving revision 1.123
diff -c -r1.123 timestamp.c
*** src/backend/utils/adt/timestamp.c 24 May 2005 02:09:45 -0000 1.123
--- src/backend/utils/adt/timestamp.c 25 May 2005 01:06:27 -0000
***************
*** 77,88 ****
  int dterr;
  char   *field[MAXDATEFIELDS];
  int ftype[MAXDATEFIELDS];
! char lowstr[MAXDATELEN + MAXDATEFIELDS];
 
! if (strlen(str) >= sizeof(lowstr))
! dterr = DTERR_BAD_FORMAT;
! else
! dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
  if (dterr != 0)
--- 77,86 ----
  int dterr;
  char   *field[MAXDATEFIELDS];
  int ftype[MAXDATEFIELDS];
! char workbuf[MAXDATELEN + MAXDATEFIELDS];
 
! dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
!  field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
  if (dterr != 0)
***************
*** 317,328 ****
  int dterr;
  char   *field[MAXDATEFIELDS];
  int ftype[MAXDATEFIELDS];
! char lowstr[MAXDATELEN + MAXDATEFIELDS];
 
! if (strlen(str) >= sizeof(lowstr))
! dterr = DTERR_BAD_FORMAT;
! else
! dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
  if (dterr != 0)
--- 315,324 ----
  int dterr;
  char   *field[MAXDATEFIELDS];
  int ftype[MAXDATEFIELDS];
! char workbuf[MAXDATELEN + MAXDATEFIELDS];
 
! dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
!  field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
  if (dterr != 0)
***************
*** 493,499 ****
  int dterr;
  char   *field[MAXDATEFIELDS];
  int ftype[MAXDATEFIELDS];
! char lowstr[MAXDATELEN + MAXDATEFIELDS];
 
  tm->tm_year = 0;
  tm->tm_mon = 0;
--- 489,495 ----
  int dterr;
  char   *field[MAXDATEFIELDS];
  int ftype[MAXDATEFIELDS];
! char workbuf[256];
 
  tm->tm_year = 0;
  tm->tm_mon = 0;
***************
*** 503,512 ****
  tm->tm_sec = 0;
  fsec = 0;
 
! if (strlen(str) >= sizeof(lowstr))
! dterr = DTERR_BAD_FORMAT;
! else
! dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeInterval(field, ftype, nf, &dtype, tm, &fsec);
  if (dterr != 0)
--- 499,506 ----
  tm->tm_sec = 0;
  fsec = 0;
 
! dterr = ParseDateTime(str, workbuf, sizeof(workbuf), field,
!  ftype, MAXDATEFIELDS, &nf);
  if (dterr == 0)
  dterr = DecodeInterval(field, ftype, nf, &dtype, tm, &fsec);
  if (dterr != 0)
Index: src/include/utils/datetime.h
===================================================================
RCS file: /var/lib/cvs/pgsql/src/include/utils/datetime.h,v
retrieving revision 1.53
diff -c -r1.53 datetime.h
*** src/include/utils/datetime.h 24 May 2005 04:03:01 -0000 1.53
--- src/include/utils/datetime.h 25 May 2005 01:06:27 -0000
***************
*** 276,282 ****
  extern void j2date(int jd, int *year, int *month, int *day);
  extern int date2j(int year, int month, int day);
 
! extern int ParseDateTime(const char *timestr, char *lowstr,
   char **field, int *ftype,
   int maxfields, int *numfields);
  extern int DecodeDateTime(char **field, int *ftype,
--- 276,282 ----
  extern void j2date(int jd, int *year, int *month, int *day);
  extern int date2j(int year, int month, int day);
 
! extern int ParseDateTime(const char *timestr, char *workbuf, size_t buflen,
   char **field, int *ftype,
   int maxfields, int *numfields);
  extern int DecodeDateTime(char **field, int *ftype,
Index: src/test/regress/expected/interval.out
===================================================================
RCS file: /var/lib/cvs/pgsql/src/test/regress/expected/interval.out,v
retrieving revision 1.10
diff -c -r1.10 interval.out
*** src/test/regress/expected/interval.out 7 Apr 2005 01:51:40 -0000 1.10
--- src/test/regress/expected/interval.out 25 May 2005 01:06:27 -0000
***************
*** 221,223 ****
--- 221,230 ----
   @ 4 years 1 mon 10 days 4 hours 18 mins 23 secs
  (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)
+
Index: src/test/regress/sql/interval.sql
===================================================================
RCS file: /var/lib/cvs/pgsql/src/test/regress/sql/interval.sql,v
retrieving revision 1.6
diff -c -r1.6 interval.sql
*** src/test/regress/sql/interval.sql 7 Apr 2005 01:51:41 -0000 1.6
--- src/test/regress/sql/interval.sql 25 May 2005 01:06:27 -0000
***************
*** 66,68 ****
--- 66,71 ----
  -- updating pg_aggregate.agginitval
 
  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;


---------------------------(end of broadcast)---------------------------
TIP 9: the planner will ignore your desire to choose an index scan if your
      joining column's datatypes do not match
Reply | Threaded
Open this post in threaded view
|

Re: [BUGS] BUG #1671: Long interval string representation rejected

Neil Conway-2
Neil Conway wrote:
> Ah, yeah, that works. Attached is a revised patch -- I'll apply it
> tomorrow barring any objections. I also fixed the semi-colon -- thanks
> for the review.

Patch applied to HEAD, REL8_0_STABLE, and REL7_4_STABLE. Thanks for the
report, Mark.

-Neil

---------------------------(end of broadcast)---------------------------
TIP 2: you can get off all lists at once with the unregister command
    (send "unregister YourEmailAddressHere" to [hidden email])