WDataValue::SetCHAR()

TIMESTAMP Parsing Bug

If the datavalue is set to SQL_C_TIMESTAMP,  SetCHAR fails and returns false, if the fraction has more than 4 digits.

The code further down fixes the bug.

The bug exists in Power 2.5 beta, 2.1 and probably in all previous versions.

BOOL DVFromString( const char * str, DATE_STRUCT * d, TIME_STRUCT * t, TIMESTAMP_STRUCT *ts )
{
  #undef  MAX_VALUES
  #define MAX_VALUES 7

  BOOL         ok = TRUE;
  const char * s;
  const char * e;
  WULong       val;
  WULong       values[MAX_VALUES];
  int          i;
  int          leading = 0, numchars = 0;

  memset( values, 0, sizeof( values ) );

  s = str;
  i = 0;

  val = strtoul( s, (char**)&e, 10 );
  if( s != e )
  {
    while( i < MAX_VALUES && *s != '\0' )
    {
      values[i++] = val;
      while( isspace( *e ) )
        ++e;
      if( *e == '\0' )
        break;
      if( !isdigit( *e ) )
        ++e;
      while( isspace( *e ) )
        ++e;
      if( *e == '\0' )
        break;

      s = e;

      // Special case: for timestamps the last bit is a
      // fractional number so we need to count # of leading
      // zeros...

      if( i == ( MAX_VALUES - 1 ) )
      {
        while( *s == '0' )
        {
          ++s;
          ++leading;
        }

        val = 0;
        numchars = 0;

        if( leading < 9 )
        {
          e = s;
          while( ( numchars + leading ) < 9 && isdigit( *e ) )
          {
            val *= 10;
            val += ( *e - '0' );
            ++e;
            ++numchars;
          }

          while( isdigit( *e ) )
            ++e;
        }
      }
      else
      {
        val = strtoul( s, (char**)&e, 10 );
      }
    }
  }

 
  // Copy values...

  if( d )
  {
    d->year   = (SWORD) values[0];
    d->month  = (UWORD) values[1];
    d->day    = (UWORD) values[2];

    if( i != 3 ) ok = FALSE;
    if( d->year < 0 || d->year > 9999 ) ok = FALSE;
    if( d->month < 1 || d->month > 12 ) ok = FALSE;
    if( d->day < 1 || d->day > 31 ) ok = FALSE;
  }
  else if( t )
  {
    t->hour   = (UWORD) values[0];
    t->minute = (UWORD) values[1];
    t->second = (UWORD) values[2];

    if( i != 2 && i != 3 ) ok = FALSE;
    if( t->hour > 23 ) ok = FALSE;
    if( t->minute > 59 ) ok = FALSE;
    if( t->second > 59 ) ok = FALSE;
  }
  else if( ts )
  {
    ts->year   = (SWORD) values[0];
    ts->month  = (UWORD) values[1];
    ts->day    = (UWORD) values[2];

    ts->hour   = (UWORD) values[3];
    ts->minute = (UWORD) values[4];
    ts->second = (UWORD) values[5];

    if( i > 6 && leading < 9 )
    {
      while( isspace( *e ) )
        ++e;

      if( *e != '\0' )
        ok = FALSE; // extra stuff at end...
      else
      {
          for( int i = 0; i < ( 9 - leading - numchars ); ++i ){
              values[6] *= 10;
          }
      }
    }  
    else
      values[6] = 0;

    ts->fraction = (UDWORD) values[6];

    if( i < 5 ) ok = FALSE;
    if( ts->year < 0 || ts->year > 9999 ) ok = FALSE;
    if( ts->month < 1 || ts->month > 12 ) ok = FALSE;
    if( ts->day < 1 || ts->day > 31 ) ok = FALSE;
    if( ts->hour > 23 ) ok = FALSE;
    if( ts->minute > 59 ) ok = FALSE;
    if( ts->second > 59 ) ok = FALSE;
    if( ts->fraction > 999999999 ) ok = FALSE;
  }
  else
    ok = FALSE;

  return ok;
}