/*
_____       _    _    Corso   Italia,  178
(_|__   .  (_   |_|_  56125           Pisa
(_|_) |)|(()_)()| |   tel.  +39  050 46380
  |   |               picosoft@picosoft.it

 Copyright (C) Picosoft s.r.l. 1995-2002

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2, or (at your option)
 any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/
# include "stmtattr.h"
static char rcsid[] = "$Id: stmtattr.cpp 5.9 2001/09/24 11:26:05 picoSoft Exp Marco $";
static char rcsidh[] = stmtattr_h;
extern "C" {
# include "picoend.h"
}                      
# include "relation.h"
# include "perror.h"
# include "stmtrel.h"
# include "database.h"
# include "trace.h"
# include "sort.h"
extern "C" {
# include <string.h>
# include <stdlib.h>
# include <limits.h>
# include <ctype.h>
}
# include <math.h>
 
# define MINUS 0x0D
# define MAXCHARLEN 48
union cast {
   char chr [sizeof(double)];
   short sht;
   unsigned short usht;
   long lng;
   unsigned long ulng;
   double dbl;
   float flt;
};
static unsigned char unsetBit[8] = { 254, 253, 251, 247, 239, 223, 191, 127};
static unsigned char   setBit[8] = { 1, 2, 4, 8, 16, 32, 64, 128};
 
extern int Like (char *, char *, int, int);

PCLASSID(StmtAttr)

inline static int
strnlen (char *s, int l)
{
   register int i;
   for (i = 0; i < l && *s != 0; i++, s++)
      ;

   return i;
}

inline static int
alphanlen (char *s, int l)
{
   register int i;
//970709
   if (!*s)
      return SQL_NULL_DATA;
//      
   s += (l - 1);
   for (i = l; i > 0 && *s == ' '; i--, s--)
      ;

   return i;
}

inline int
TimeStampDiff (StmtAttr *a1, StmtAttr *a2)
{
   TIMESTAMP_STRUCT ts1, ts2;
   long len1 = 1, len2 = 1;
   a1->ToTimeStamp (&ts1, len1);
   a2->ToTimeStamp (&ts2, len2);
   if (!a1->Null && len1 > 0)
      if (!a2->Null && len2 > 0)
         if (ts1.year == ts2.year)
            if (ts1.month == ts2.month)
               if (ts1.day == ts2.day)
                  if (ts1.hour == ts2.hour)
                     if (ts1.minute == ts2.minute)
                        if (ts1.second == ts2.second)
                           if (ts1.fraction == ts2.fraction)
                              return 0;
                           else
                              return ts1.fraction - ts2.fraction;
                        else
                           return ts1.second - ts2.second;
                     else
                        return ts1.minute - ts2.minute;
                  else
                     return ts1.hour - ts2.hour;
               else
                  return ts1.day - ts2.day;
            else
               return ts1.month - ts2.month;
         else
            return ts1.year - ts2.year;
      else
         return 1;
   else
      if (!a2->Null && len2 > 0)
         return -1;
      else
         return 0;
}

static void
Round (char *num, unsigned int dec)
{
   char *comma = strchr (num, '.');
   char *pnt;
   
   if (comma) {
      unsigned int lenComma = strlen (++comma);
      while (!isdigit(*num) && *num != '.')
         num++;
      if (lenComma > dec) {
         if (comma[dec] >= '5') {
            for (pnt = &comma[dec - 1]; pnt >= num; pnt--) {
               if (*pnt == '.')
                  continue;
               else {
                  (*pnt)++;
                  if (*pnt > '9')
                     *pnt = '0';
                  else
                     break;
               }
            }                               
            if (pnt < num) {
               for (pnt = comma + lenComma - 1; pnt > num; pnt--)
                  *pnt = *(pnt - 1);
               *pnt = '1';
               comma++;
            }
         }
         for (pnt = &comma[dec]; *pnt; pnt++)
            *pnt = '0';
      }
   }
}

void
StmtAttr::allocBuffer()
{
   if (Buffer == 0 && StmtParent == 0) {
      Buffer = new char [Attr.getFldSize() + 1];
      memset (Buffer, '\0', Attr.getFldSize() + 1);
      allocBlobField();
   }
}

void
StmtAttr::allocBlobField()
{
   DataType t = Attr.GetType();
   if ((t == T_BLOB || t == T_CLOB) && bField == 0) {
      if (StmtParent != 0) {
         StmtParent->setBlob();
         bField = new BlobField (StmtParent->getBlob());
      } else
         bField = new BlobField (0); /* O^O */
   }
}

void
StmtAttr::init(toknum bi, PBool la)
{
   Buffer = (char*) 0;
   bField = 0;
   if (StmtParent == 0 && Attr.getFldSize() > 0) {
      Buffer = new char[Attr.getFldSize()];
      memset (Buffer, 0, Attr.getFldSize());
      allocBlobField();
   }
   //sj Expression = PFalse;
   aggregate = bi;
   LocalAttr = la;
   IndexPnt = 0;
   Null = PTrue;
}
  
StmtAttr::~StmtAttr ()
{
   if (LocalAttr)
      delete & Attr;
   if (StmtParent == 0 && Buffer)
      delete Buffer;
   if (bField != 0)
      delete bField;
}

void
StmtAttr::setBuffer()
{
   char *pnt;
   if ((pnt = StmtParent->getBuffer()) != 0) {
      Buffer = &pnt[Attr.getFldPos()];
      allocBlobField ();
      setNullBuffer();
   } else
      PError::InternalError ("Stmtattr init: Buffer Stmtrel == 0");
}

void 
StmtAttr::Aggregate (unsigned long i, StmtAttr *a)
{
   double attrDbl;
   long len = 0;
   double prec = NULLDOUBLE;
   
   switch (aggregate) {
   case MIN:
      if (i == 1)
         this->FromAttr (*a);
      else
         if (!a->isNull() && a->Compare (this, (toknum) '<', PFalse))
            this->FromAttr (*a);
      break;
   case MAX:
      if (i == 1)
         this->FromAttr (*a);
      else
         if (!a->isNull() && a->Compare (this, (toknum) '>', PFalse))
            this->FromAttr (*a);
      break;
   case COUNT:
      if (i == 1)
         FromDouble (0);
      if (!a->isNull()) {
         ToDouble (prec, len);
         FromDouble (prec + 1);
      }
      break;
   default:
      if (i == 1)
         this->FromAttr (*a);
      else {
         a->ToDouble (attrDbl, len);
         ToDouble (prec, len);
         CalcAggregate (aggregate, prec, attrDbl, i);
         FromDouble(attrDbl);
      }
      break;
   }
}

void 
CalcAggregate (toknum bi, double prec, double &calc, unsigned long i)
{  
   switch (bi) {
   case SUM:
      if (prec != NULLDOUBLE)
         if (calc == NULLDOUBLE)
            calc = prec;
         else
            calc += prec;
      break;
   case AVG:
      if (prec != NULLDOUBLE)
         if (calc == NULLDOUBLE)
            calc = (prec * (i - 1)) / i;
         else
            calc = (prec * (i - 1) + calc) / i;
      else 
         if (calc != NULLDOUBLE)
            calc = calc / i;
      break;
   default:
      PError::InternalError ("Invalid Aggregate in CalcAggregate");
      break;
   }
}

void
StmtAttr::setNullBuffer ()
{
   union cast val;
   Null = PTrue;
   if (Buffer != 0)
      switch (Attr.GetType()) {
      case T_SHORT:
         val.sht = NULLSHORT;
         memcpy (Buffer, val.chr, sizeof(short));
         // *((short *) Buffer) = NULLSHORT;
         break;
      case T_LONG:
         val.lng = NULLLONG;
         memcpy (Buffer, val.chr, sizeof(long));
         // *((long *) Buffer) = NULLLONG;
         break;
      case T_FLOAT:
         val.flt = NULLFLOAT;
         memcpy (Buffer, val.chr, sizeof(float));
         // *((float *) Buffer) = NULLFLOAT;
         break;
      case T_DOUBLE: 
         if (aggregate == COUNT)
            val.dbl = 0;
            // *((double *) Buffer) = 0;
         else         
            val.dbl = NULLDOUBLE;
            // *((double *) Buffer) = NULLDOUBLE;
         memcpy (Buffer, val.chr, sizeof(double));
         break;
      case T_BLOB:
      case T_CLOB:
         bField->setNull();
         break;
      case T_PACKED_ORDERED:
      case T_CSTRING:
         memset (Buffer, 0, (int)Attr.getFldSize());
         break;
      case T_UNKNOWN:
         PError::InternalError ("T_UNKNOWN in setNullBuffer");
         break;
      default: 
         PError::InternalError ("Invalid type in setNullBuffer");
         break;
      }
}

void
StmtAttr::setHighValueBuffer ()
{
   Null = PFalse;
   union cast val;
   if (Buffer != 0)
      switch (Attr.GetType()) {
      case T_SHORT:
         // *((short *) Buffer) = HIGHVALUESHORT;
         val.sht = HIGHVALUESHORT;
         memcpy (Buffer, val.chr, sizeof(short));
         break;
      case T_LONG:
         // *((long *) Buffer) = HIGHVALUELONG;
         val.lng = HIGHVALUELONG;
         memcpy (Buffer, val.chr, sizeof(long));
         break;
      case T_FLOAT:
         // *((float *) Buffer) = HIGHVALUEFLOAT;
         val.flt = HIGHVALUEFLOAT;
         memcpy (Buffer, val.chr, sizeof(float));
         break;
      case T_DOUBLE: 
         // *((double *) Buffer) = HIGHVALUEDOUBLE;
         val.dbl = HIGHVALUEDOUBLE;
         memcpy (Buffer, val.chr, sizeof(double));
         break;
      case T_BLOB:
      case T_CLOB:
         break;
      case T_PACKED_ORDERED:
         Buffer[0] = '\xF9';
         memset (&Buffer[1], '\x99', (int)Attr.getFldSize() - 1);
         break;
      case T_CSTRING:
         memset (Buffer, '\xFF', (int)Attr.getFldSize());
         break;
      case T_UNKNOWN:
         PError::InternalError ("T_UNKNOWN in setHighValueBuffer");
         break;
      default: 
         PError::InternalError ("Invalid type in setHighValueBuffer");
         break;
      }
}

PBool
StmtAttr::isNull ()
{
   TIMESTAMP_STRUCT ts;
   long len;
   union cast val;
   
   if (Null)
      return PTrue;
   if (Attr.getDateType() == T_TIMESTAMP) {
      ToTimeStamp (&ts, len);
      if (len == SQL_NULL_DATA)
         return (Null = PTrue);
      else
         return PFalse;
   }
   if (Buffer != 0)
      switch (Attr.GetType()) {
      case T_CSTRING:
         if (Buffer[0])
            return PFalse;
         else
            return (Null = PTrue);
      case T_SHORT:
         memcpy (val.chr, Buffer, sizeof(short));
         return (Null = (val.sht == NULLSHORT));
      case T_LONG:
         memcpy (val.chr, Buffer, sizeof(long));
         return (Null = (val.lng == NULLLONG));
      case T_FLOAT:
         memcpy (val.chr, Buffer, sizeof(float));
         return (Null = (val.flt == NULLFLOAT));
      case T_DOUBLE: 
         memcpy (val.chr, Buffer, sizeof(double));
         return (Null = (val.dbl == NULLDOUBLE));
      case T_BLOB:
      case T_CLOB:
         return bField->isNull() && getBlobBlkNum() == 0;
      case T_PACKED_ORDERED:
         if (Buffer[0] != '\0')
            return PFalse;
         else
            return PTrue;
      case T_UNKNOWN:
         PError::InternalError ("T_UNKNOWN in isNull");
         return PFalse;
      default: 
         PError::InternalError ("Invalid type in isNull");
         return PFalse;
      }
   return PFalse;
}

/* Nuovo O^O */

int
StmtAttr::IndexCompare (StmtAttr *a)
{
   int Return;
   unsigned char *coll;

   if (Attr.getDateType() == T_TIMESTAMP)
      if (a->Attr.GetType() == T_UNKNOWN)
         PError::InternalError ("a->Attr T_UNKNOWN in IndexCompare");
      else if (a->couldBeTimeStamp())
         return TimeStampDiff (this, a);
      else
         return PFalse; 
   else if (a->Attr.getDateType() == T_TIMESTAMP)
      if (Attr.GetType() == T_UNKNOWN)
         PError::InternalError ("Attr T_UNKNOWN in IndexCompare");
      else if (couldBeTimeStamp())
         return TimeStampDiff (this, a);
      else
         return PFalse;
             
   switch (Attr.GetType()) {
   case T_CSTRING:
      switch (a->Attr.GetType()) {
      case T_CSTRING:
         if (Attr.getParent())
            coll = Attr.getParent()->getCollating();
         else if (a->Attr.getParent())
            coll = a->Attr.getParent()->getCollating();
         else
            coll = 0;
         Return =  StringCompare ((unsigned char *)Buffer, 
                                  (unsigned int) strnlen(Buffer, (int)Attr.GetLen()),
                                  (unsigned char *)a->Buffer, 
                                  (unsigned int) strnlen(a->Buffer,(int)a->Attr.GetLen()),
                                  coll, '\0');
         break;
      case T_BLOB: //I blob non si confrontano!
         Return = 0;
         break;
      case T_CLOB: //I blob non si confrontano?
         Return = 0;
         break;
      case T_PACKED_ORDERED: //Qui ci starebbe meglio un confronto stringa!
      case T_SHORT:
      case T_LONG:
      case T_FLOAT:
      case T_DOUBLE:
         {
            long len1, len2;
            double cfrt1, cfrt2;

            ToDouble(cfrt1, len1);
            a->ToDouble(cfrt2, len2);
            if (len1 == SQL_NULL_DATA)
               if (len2 == SQL_NULL_DATA)
                  Return = 0;
               else
                  Return = -1;
            else if (len2 == SQL_NULL_DATA)
                Return = 1;
            else if (cfrt1 > cfrt2)
                Return = 1;
            else if (cfrt1 < cfrt2)
                Return = -1;
            else
               Return = 0;
         }
         break;
      default:
         PError::InternalError ("default2 su IndexCompare");
         Return =  PFalse;
         break;
      }
      break;
   case T_BLOB: // In prima istanza
   case T_CLOB: // In prima istanza
   case T_PACKED_ORDERED:
   case T_SHORT:
   case T_LONG:
   case T_FLOAT:
   case T_DOUBLE:
      switch (a->Attr.GetType()) {
      case T_BLOB: // in prima istanza
      case T_CLOB: // in prima istanza
      case T_PACKED_ORDERED:
      case T_SHORT:
      case T_LONG:
      case T_FLOAT:
      case T_DOUBLE:
      case T_CSTRING:
         {
            long len1, len2;
            double cfrt1, cfrt2;

            ToDouble(cfrt1, len1);
            a->ToDouble(cfrt2, len2);
            if (len1 == SQL_NULL_DATA)
               if (len2 == SQL_NULL_DATA)
                  Return = 0;
               else
                  Return = -1;
            else if (len2 == SQL_NULL_DATA)
                Return = 1;
            else if (cfrt1 > cfrt2)
                Return = 1;
            else if (cfrt1 < cfrt2)
                Return = -1;
            else
               Return = 0;
         }
         break;
      default:
         PError::InternalError ("default3 su IndexCompare");
         Return =  PFalse;
         break;
      }
      break;
   default:
      PError::InternalError ("default4 su IndexCompare");
      Return =  PFalse;
      break;
   }
   return Return;
}

/* Fine Nuovo O^O*/

inline static PBool
NullCompare (StmtAttr *a1, toknum op, StmtAttr *a2)
{
   PBool Return;
   int result = 0;
   
   if (a1->isNull())
      if (a2->isNull())
         result = 0;
      else
         result = 1;
   else
      if (a2->isNull())
         result = -1;

   switch (op) {
   case '>':
      if (result < 0)
         Return = PTrue;
      else
         Return = PFalse;
      break;
   case '<':
      if (result > 0)
         Return = PTrue;
      else
         Return = PFalse;
      break;
   case '=':
   case IN_:
      if (result == 0)
         Return = PTrue;
      else
         Return = PFalse;
      break;
   case _GE_:
      if (result <= 0)
         Return = PTrue;
      else
         Return = PFalse;
      break;
   case _LE_:
      if (result >= 0)
         Return = PTrue;
      else
         Return = PFalse;
      break;
   case _NE_:
      if (result != 0)
         Return = PTrue;
      else
         Return = PFalse;
      break;
   case _OJ_:
      Return = PTrue;
      break;
   default:
      Return = PFalse;
   }
   return Return;
}

PBool
StmtAttr::Compare (StmtAttr *a, toknum op, PBool checkOnly)
{
   PBool Return;
          
   if (!checkOnly)
      if (isNull() || a->isNull())
         return NullCompare (this, op, a);

   if (Attr.getDateType() == T_TIMESTAMP)
      if (a->Attr.GetType() == T_UNKNOWN)
         if (checkOnly)
            return PTrue;
         else
            return PFalse;
      else if (a->couldBeTimeStamp())
         if (checkOnly)
            if (op != LIKE && op != NOT_LIKE)
               return PTrue;
            else
               return PFalse;
         else
            return TimeStampCompare (a, op);
      else
         return PFalse; 
   else if (a->Attr.getDateType() == T_TIMESTAMP)
      if (Attr.GetType() == T_UNKNOWN)
         if (checkOnly)
            return PTrue;
         else
            return PFalse;
      else if (couldBeTimeStamp())
         if (checkOnly)
            if (op != LIKE && op != NOT_LIKE)
               return PTrue;
            else
               return PFalse;
         else
            return TimeStampCompare (a, op);
      else
         return PFalse;
             
   switch (Attr.GetType()) {
   case T_CSTRING:
      switch (a->Attr.GetType()) {
      case T_CSTRING:
         if (checkOnly)
            Return = PTrue;
         else {
            unsigned char *coll;
            if (Attr.getParent())
               coll = Attr.getParent()->getCollating();
            else if (a->Attr.getParent())
               coll = a->Attr.getParent()->getCollating();
            else
               coll = 0;
            Return =  StringCompare (Buffer, 
                                     strnlen(Buffer, (int)Attr.GetLen()), op,
                                     a->Buffer, 
                                     strnlen(a->Buffer,(int)a->Attr.GetLen()),
                                     coll, '\0');
         }
         break;
      case T_BLOB: // In prima istanza
      case T_CLOB: // In prima istanza
      case T_PACKED_ORDERED:
      case T_SHORT:
      case T_LONG:
      case T_FLOAT:
      case T_DOUBLE:
         if (checkOnly)
            Return = PTrue;
         else
            Return =  NumberCompare (this, op, a);
         break;
      case T_UNKNOWN:
         if (checkOnly)
            Return = PTrue;
         else
            Return = PFalse;
         break;
      default:
         Return =  PFalse;
         break;
      }
      break;
   case T_BLOB: // In prima istanza
   case T_CLOB: // In prima istanza
   case T_PACKED_ORDERED:
   case T_SHORT:
   case T_LONG:
   case T_FLOAT:
   case T_DOUBLE:
      switch (a->Attr.GetType()) {
      case T_CSTRING:
      case T_BLOB: // In prima istanza
      case T_CLOB: // In prima istanza
      case T_PACKED_ORDERED:
      case T_SHORT:
      case T_LONG:
      case T_FLOAT:
      case T_DOUBLE:
         if (checkOnly)
            if (op != LIKE && op != NOT_LIKE)
               Return =  PTrue;
            else
               Return = PFalse;
         else
            Return =  NumberCompare (this, op, a);
         break;
      case T_UNKNOWN:
         if (checkOnly)
            Return = PTrue;
         else
            Return = PFalse;
         break;
      default:
         Return =  PFalse;
         break;
      }
      break;
   default:
      Return =  PFalse;
      break;
   }
   return Return;
}


PBool
StmtAttr::TimeStampCompare (StmtAttr *sa, toknum op)
{
   PBool Return;
   int result = TimeStampDiff (this, sa);

   switch (op) {
   case '>':
      if (result > 0)
         Return = PTrue;
      else
         Return = PFalse;
      break;
   case '<':
      if (result < 0)
         Return = PTrue;
      else
         Return = PFalse;
      break;
   case '=':
   case IN_:
      if (result == 0)
         Return = PTrue;
      else
         Return = PFalse;
      break;
   case _GE_:
      if (result >= 0)
         Return = PTrue;
      else
         Return = PFalse;
      break;
   case _LE_:
      if (result <= 0)
         Return = PTrue;
      else
         Return = PFalse;
      break;
   case _NE_:
      if (result != 0)
         Return = PTrue;
      else
         Return = PFalse;
      break;
   case _OJ_:
      Return = PTrue;
      break;
   default:
      Return = PFalse;
   }
   return Return;
}

/*
PBool
StringCompare (char * c1, int len1, toknum op, char * c2, int len2, char fill)
{
   PBool Return;
   int Result;
   int len = (len1 > len2) ? len1 : len2;

   len = (len > MAXBUFFER) ? MAXBUFFER : len;

   memset (CfrtBuf1, fill, MAXBUFFER);
   memcpy (CfrtBuf1, c1, len1);

   memset (CfrtBuf2, fill, MAXBUFFER);
   memcpy (CfrtBuf2, c2, len2);

   if (op == LIKE)
      Return = Like (CfrtBuf1, CfrtBuf2, len1, len2);
   else if (op == NOT_LIKE)
      Return = !Like (CfrtBuf1, CfrtBuf2, len1, len2);
   else {
      Result = memcmp (CfrtBuf1, CfrtBuf2, len);
      switch (op) {
      case '>':
         if (Result > 0)
            Return = PTrue;
         else
            Return = PFalse;
         break;
      case '<':
         if (Result < 0)
            Return = PTrue;
         else
            Return = PFalse;
         break;
      case '=':
      case IN_:
         if (Result == 0)
            Return = PTrue;
         else
            Return = PFalse;
         break;
      case _GE_:
         if (Result >= 0)
            Return = PTrue;
         else
            Return = PFalse;
         break;
      case _LE_:
         if (Result <= 0)
            Return = PTrue;
         else
            Return = PFalse;
         break;
      case _NE_:
         if (Result != 0)
            Return = PTrue;
         else
            Return = PFalse;
         break;
      case _OJ_:
         Return = PTrue;
         break;
      default:
         Return = PFalse;
      }
   }
   return Return;
}
*/

PBool
StringCompare (char * c1, int len1, toknum op,
               char * c2, int len2,
               unsigned char *coll, unsigned char fill)
{
   PBool Return;   
   int result;

   if (op == LIKE)
      Return = Like (c1, c2, len1, len2);
   else if (op == NOT_LIKE)
      Return = !Like (c1, c2, len1, len2);
   else {
      result = StringCompare ((unsigned char *) c1, (unsigned int) len1,
                              (unsigned char *) c2, (unsigned int) len2,
                              coll, fill);
      switch (op) {
      case '>':
         if (result > 0)
            Return = PTrue;
         else
            Return = PFalse;
         break;
      case '<':
         if (result < 0)
            Return = PTrue;
         else
            Return = PFalse;
         break;
      case '=':
      case IN_:
         if (result == 0)
            Return = PTrue;
         else
            Return = PFalse;
         break;
      case _GE_:
         if (result >= 0)
            Return = PTrue;
         else
            Return = PFalse;
         break;
      case _LE_:
         if (result <= 0)
            Return = PTrue;
         else
            Return = PFalse;
         break;
      case _NE_:
         if (result != 0)
            Return = PTrue;
         else
            Return = PFalse;
         break;
      case _OJ_:
         Return = PTrue;
         break;
      default:
         Return = PFalse;
      }
   }
   return Return;
}

PBool
NumberCompare (StmtAttr * c1, toknum op, StmtAttr * c2)
{
   PBool Return;
   long dummylen;
   double cfrt1, cfrt2;
   double result;

   c1->ToDouble(cfrt1, dummylen);
   c2->ToDouble(cfrt2, dummylen);
   result = cfrt1 - cfrt2;

   switch (op) {
   case '>':
      if (result > 0)
         Return = PTrue;
      else
         Return = PFalse;
      break;
   case '<':
      if (result < 0)
         Return = PTrue;
      else
         Return = PFalse;
      break;
   case '=':
   case IN_:
      if (result == 0)
         Return = PTrue;
      else
         Return = PFalse;
      break;
   case _GE_:
      if (result >= 0)
         Return = PTrue;
      else
         Return = PFalse;
      break;
   case _LE_:
      if (result <= 0)
         Return = PTrue;
      else
         Return = PFalse;
      break;
   case _NE_:
      if (result != 0)
         Return = PTrue;
      else
         Return = PFalse;
      break;
   case _OJ_:
      Return = PTrue;
      break;
   default:
      Return = PFalse;
   }
   return Return;
}

Error
StmtAttr::ToDouble (double & out, long & len)
{
   Error Return = SQL_SUCCESS;
   char *chr;
   union cast val;
     
   if (Null) {
      len = SQL_NULL_DATA;
      return Return;
   }
   switch (Attr.GetType()) {
   case T_BLOB:
      Return = SQL_ERROR;
      break;
   case T_CLOB:
      Return = SQL_ERROR;
      break;
   case T_PACKED_ORDERED:
      ToChar (&chr, len);
      if (len == SQL_NULL_DATA)
         out = NULLDOUBLE;
      else
         out = atof (chr);
      break;
   case T_SHORT:
      memcpy (val.chr, Buffer, sizeof(short));
      if (val.sht == NULLSHORT)
         len = SQL_NULL_DATA;
      else
         if (Attr.GetSign() == UNSIGNED)
            out = val.usht;
         else
            out = val.sht;
      break; 
   case T_LONG:
      memcpy (val.chr, Buffer, sizeof(long));
      if (val.lng == NULLLONG)
         len = SQL_NULL_DATA;
      else
         if (Attr.GetSign() == UNSIGNED)
            out = val.ulng;
         else
            out = val.lng;
      break;
   case T_FLOAT:
      memcpy (val.chr, Buffer, sizeof(float));
      if (val.flt == NULLFLOAT)
         len = SQL_NULL_DATA;
      else
         out = val.flt;
      break;
   case T_DOUBLE:
      memcpy (val.chr, Buffer, sizeof(double));
      if (val.dbl == NULLDOUBLE)
         len = SQL_NULL_DATA;
      else
         out = val.dbl;
      break;
   case T_CSTRING:
      {
         char buff[MAXCHARLEN + 1];
         long len = Attr.getFldSize();
         len = len < MAXCHARLEN ? len : MAXCHARLEN;
         memcpy (buff, Buffer, len);
         buff[len] = 0;
         out = atof(buff);
      }
      break;
   case T_UNKNOWN:
      PError::InternalError ("T_UNKNOWN in ToDouble");
      Return = SQL_ERROR;
      break;
   default: 
      PError::InternalError ("Invalid type in ToDouble");
      Return = SQL_ERROR;
      break;
   }
   if (len != SQL_NULL_DATA)
      len = sizeof(double);
   return Return;
}

Error
StmtAttr::ToFloat (float &out, long & len)
{
   double dummy;
   Error Return = ToDouble(dummy, len);

   out = (float) dummy;
   if (len != SQL_NULL_DATA)
      len = sizeof(float);
   return Return;
}
Error
StmtAttr::ToLong (long &out, long & len)
{
   double dummy;
   double maxL  = LONG_MAX;
   double minL  = LONG_MIN;

   Error Return = ToDouble(dummy, len);
   if (len >= 0)
      if (dummy > maxL || dummy < minL)
         Return = SQL_ERROR;
      else
         out = (long) dummy;
   if (len != SQL_NULL_DATA)
      len = sizeof(long);
   return Return;
}

Error
StmtAttr::ToULong (unsigned long &out, long & len)
{
   double dummy;
   double maxUL = ULONG_MAX;
   double minUL = 0x0UL;

   Error Return = ToDouble(dummy, len);
   if (len >= 0)     
      if (dummy > maxUL || dummy < minUL)
         Return = SQL_ERROR;
      else
         out = (unsigned long) dummy;
   if (len != SQL_NULL_DATA)
      len = sizeof(unsigned long);
   return Return;
}

Error
StmtAttr::ToShort (short &out, long &len)
{
   double dummy;
   double maxS  = SHRT_MAX;
   double minS  = SHRT_MIN;

   Error Return = ToDouble(dummy, len);
   if (len >= 0)
      if (dummy > maxS || dummy < minS)
         Return = SQL_ERROR;
      else
         out = (short) dummy;
   if (len != SQL_NULL_DATA)
      len = sizeof(short);
   return Return;
}
   
Error
StmtAttr::ToUShort (unsigned short &out, long &len)
{
   double dummy;
   double maxUS = USHRT_MAX;
   double minUS = 0x0;

   Error Return = ToDouble(dummy, len);
   if (len >= 0)
      if (dummy > maxUS || dummy < minUS)
         Return = SQL_ERROR;
      else
         out = (unsigned short) dummy;
   if (len != SQL_NULL_DATA)
      len = sizeof(unsigned short);
   return Return;
}

Error
StmtAttr::FromDouble (double n)
{
   Error Return = SQL_SUCCESS;
   char buffer[MAXCHARLEN];
   union cast val;

   setNullBuffer();
   if (n == NULLDOUBLE)
      return Return;
   else
      Null = PFalse;
   switch (Attr.GetType()) {
   case T_SHORT:
      if (Attr.GetSign() == UNSIGNED)
         val.usht = (unsigned short) n;
      else
         val.sht = (short) n;
      memcpy (Buffer, val.chr, sizeof(short));
      break;
   case T_LONG:
      if (Attr.GetSign() == UNSIGNED)
         val.ulng = (unsigned long) n;
      else
         val.lng = (long) n;
      memcpy (Buffer, val.chr, sizeof(long));
      break;    
   case T_FLOAT:
      val.flt = n;
      memcpy (Buffer, val.chr, sizeof(float));
      break;  
   case T_DOUBLE:
      val.dbl = n;
      memcpy (Buffer, val.chr, sizeof(double));
      break;
   case T_BLOB:
      Return = SQL_ERROR;
      break;
   case T_CLOB:
      Return = SQL_ERROR;
      break;
   case T_PACKED_ORDERED:
      sprintf (buffer, "%lf", n);
      CharToPackedOrdered (buffer);
      break; 
   default:
      Return = SQL_ERROR;
      break;
   }
   return Return;
}

Error
StmtAttr::ToTsChar (char **out, long &len)
{
   static char numBuff[MAXCHARLEN];
   TIMESTAMP_STRUCT ts;
   ToTimeStamp (&ts, len);
   *out = numBuff;
   if (!Null && len > 0) {
      if (strcmp (Attr.getDateFmt(), TIME_INTFMT) == 0)
         sprintf (*out, "%02d:%02d:%02d.%d",
                         ts.hour, ts.minute, ts.second, ts.fraction);
      else if (strcmp (Attr.getDateFmt(), DATE_INTFMT) == 0)
         sprintf (*out, "%04d-%02d-%02d", ts.year, ts.month, ts.day);
      else
         sprintf (*out, "%04d-%02d-%02d %02d:%02d:%02d.%d",
                        ts.year, ts.month, ts.day,
                        ts.hour, ts.minute, ts.second, ts.fraction);
      len = strlen (*out);
   } else {
      (*out)[0] = 0;
      len = SQL_NULL_DATA;
   }
   return SQL_SUCCESS;
}

/* Da Cassare
Error
StmtAttr::ToTsChar (char **out, long &len)
{
   static char numBuff[MAXCHARLEN];
   TIMESTAMP_STRUCT ts;
   ToTimeStamp (&ts, len);
   *out = numBuff;
   if (!Null && len > 0) {
      sprintf (*out, "%04d-%02d-%02d %02d:%02d:%02d.%d",
                    ts.year, ts.month, ts.day,
                    ts.hour, ts.minute, ts.second, ts.fraction);
      len = TIMESTAMPPREC;
   } else {
      (*out)[0] = 0;
      len = SQL_NULL_DATA;
   }
   return SQL_SUCCESS;
}
*/

Error
StmtAttr::FromTimeStamp (const TIMESTAMP_STRUCT * its)
{
   char dateBuffer[MAXCHARLEN];
   
   Null = PFalse;
   TimeStampToString (its, dateBuffer, Attr.getDateFmt(), DB.GetStartDate());
   FromString (dateBuffer);
   return SQL_SUCCESS;
}

Error
StmtAttr::ToTimeStamp (TIMESTAMP_STRUCT * ts, long & len)
{
   char *dateBuffer;
    
   if (Null) {
      len = SQL_NULL_DATA;
      return SQL_SUCCESS;
   }   
   ToChar (&dateBuffer, len);
   if (len == SQL_NULL_DATA)
      return SQL_SUCCESS;
   else {
      const char *fmt = Attr.getDateFmt();
      if (Attr.GetType() == T_PACKED_ORDERED) {
         int fLen = strlen (fmt);
         int diff = fLen - len;
         int i;
         if (diff > 0) {
            for (i = len; i >= 0; i--)
               dateBuffer[i + diff] = dateBuffer[i];
            for (i = 0; i < diff; i++)
               dateBuffer[i] = '0';
         }
      }
      return StringToTimeStamp (ts, dateBuffer, len, fmt, DB.GetStartDate());
   }
}
/*
Error
StmtAttr::ToTimeStamp (TIMESTAMP_STRUCT * ts, long & len)
{
   char *dateBuffer;
    
   if (Null) {
      len = SQL_NULL_DATA;
      return SQL_SUCCESS;
   }   
   ToChar (&dateBuffer, len);
   return StringToTimeStamp (ts, dateBuffer, len, Attr.getDateFmt(), DB.GetStartDate());
}
*/
Error
StmtAttr::ToChar (char **out, long & len)
{
   register int i, j;
   static char numBuff[MAXCHARLEN]; 
   char *pntBuff, *pntSign;
   union cast val;
       
   if (Null) {
      len = SQL_NULL_DATA;
      return SQL_SUCCESS;
   }
   memset (numBuff, 0, sizeof(numBuff));
   *out = numBuff;

   switch (Attr.GetType()) {
   case T_CSTRING:
      len = strnlen (Buffer, (int)Attr.GetLen());
      if (len == 0)
         len = SQL_NULL_DATA;
      else
         *out = Buffer;
      break;
   case T_BLOB:
   case T_CLOB:
      if (bField != 0) {
         len = bField->getBlobLen();
         if (len == 0)
            len = SQL_NULL_DATA;
         else
            *out = (char*)bField->getBlob();
      } else {
         len = SQL_NULL_DATA;
      }
      break;
   case T_PACKED_ORDERED:
      *out = PackedOrderedToChar((char *)Buffer, (int)Attr.getFldSize(), Attr.GetDecimal());
      if (*out == 0)
         len = SQL_NULL_DATA;
      else
         len = strlen(*out);
      break; 
   case T_SHORT:
      memcpy (val.chr, Buffer, sizeof(short));
      if (val.sht == NULLSHORT)
         len = SQL_NULL_DATA;
      else {
         if (Attr.GetSign() == UNSIGNED) 
            sprintf (numBuff, "%u", val.usht);
         else
            sprintf (numBuff, "%d", val.sht);
         len = strlen(*out);
      }
      break; 
   case T_LONG:
      memcpy (val.chr, Buffer, sizeof(long));
      if (val.lng == NULLLONG)
         len = SQL_NULL_DATA;
      else {
         if (Attr.GetSign() == UNSIGNED) 
            sprintf (numBuff, "%lu", val.ulng);
         else
            sprintf (numBuff, "%ld", val.lng);
         len = strlen(*out);
      }
      break; 
   case T_FLOAT:
      memcpy (val.chr, Buffer, sizeof(float));
      if (val.flt == NULLFLOAT)
         len = SQL_NULL_DATA;
      else {
         sprintf (numBuff, "%.18g", val.flt);
         len = strlen(*out);
      }
      break; 
   case T_DOUBLE:
      memcpy (val.chr, Buffer, sizeof(double));
      if (val.dbl == NULLDOUBLE)
         len = SQL_NULL_DATA;
      else {
         sprintf (numBuff, "%.36g", val.dbl);
         len = strlen(*out);
      }
      break;
   case T_UNKNOWN:
      PError::InternalError ("T_UNKNOWN in ToChar");
      break;
   default: 
      PError::InternalError ("Invalid type in ToChar");
      break;
   }
   return SQL_SUCCESS;
}

# define getSemiByte(buf,idx) \
   ('0' + ((idx & 1) ? (unsigned char)buf[(idx + 1)/2] >> 4 : \
                       (unsigned char)buf[(idx + 1)/2] & 0x0f))

char *
StmtAttr::PackedOrderedToChar (char *a, int size, int right)
{
   static char out[MAXCHARLEN];
   char *decstr = out;
   int decstr_len = MAXCHARLEN - 1;
   char decvar[MAXCHARLEN / 2 + 1];
   int totDigit = (size * 2) - 1;
   int bufLen = totDigit / 2 + 1;
   PBool negative = PFalse;
   char *pnt;
   int i;

   if (a[0] == 0x00)
      return 0;

   memcpy (decvar, a, size);
   if ((decvar[0] & 0xF0) == 0) {
      negative = PTrue;
      for (i = 0, pnt = decvar; i < bufLen; i++, pnt++)
         *pnt = ~(*pnt);
      if (decstr_len > 1) {
         *decstr++ = '-';
         decstr_len--;
      }
   }
   pnt = decstr;
   for (i = 0; i < totDigit - right && getSemiByte(decvar,i) == '0'; i++)
      ;
   for (  ; i < totDigit - right && decstr_len > 1; i++, decstr_len--)
      *decstr++ = getSemiByte(decvar,i);
   if (pnt == decstr && decstr_len > 1) {
      *decstr++ = '0';
      decstr_len--;
   }
   if (decstr_len > 1 && i < totDigit) {
      *decstr++ = '.';
      decstr_len--;
   }
   for (  ; i < totDigit && decstr_len > 1; i++, decstr_len--)
      *decstr++ = getSemiByte(decvar,i);
   *decstr =  0;

   return out;

}

# define putSemiByte(chr, buf, idx) \
                    (buf[(idx + 1)/2] |= (idx & 1) ? ((chr -'0') << 4) : chr - '0')

void
StmtAttr::CharToPackedOrdered (const char *in)
{
   char locinstat[MAXCHARLEN + 1];
   int totDigit = Attr.GetLen();
   int bufLen = Attr.getFldSize();
   int scale = Attr.GetDecimal();
   char * decvar = Buffer;
   PBool negative = PFalse;
   const char *start;
   char *pnt;
   int decLen;
   int i;

   strncpy (locinstat, in, MAXCHARLEN);
   locinstat[MAXCHARLEN] = 0;  
   Round(locinstat, Attr.GetDecimal());
   if ((totDigit & 1) == 0)
      totDigit++;
   for (i = 0, pnt = decvar; i < bufLen; i++, pnt++)
      *pnt = 0;
   for (start = locinstat;
        *start && (*start < '0' || *start > '9') && *start != '-'; start++)
      ;
   if (*start == '-') {
      negative = PTrue;
      start++;
   }
   if ((pnt = strchr (locinstat, '.'))) {
      decLen = pnt - start;
      for (i = totDigit - scale, ++pnt;
           i < totDigit && *pnt >= '0' && *pnt <= '9'; i++, pnt++)
         putSemiByte (*pnt, decvar, i);
   } else
      decLen = strlen(start);
   for (i = totDigit - scale - decLen; i < totDigit - scale; i++, start++)
         putSemiByte (*start, decvar, i);
   decvar[0] |= 0xF0;
   if (negative)
      for (i = 0, pnt = decvar; i < bufLen; i++, pnt++)
         *pnt = ~(*pnt);
}

void
StmtAttr::setBlobBlkNum (unsigned long blkNum)
{
   int lastByte = Attr.getFldSize() - 1;
   int i;
   for (i = lastByte; i > 0; i--) {
      Buffer[i] = blkNum % 10;
      blkNum /= 10;
      Buffer[i] |= (blkNum % 10) << 4;
      blkNum /= 10;
   }
   Buffer[i] = 0xF0 | (blkNum % 10);

}

unsigned long
StmtAttr::getBlobBlkNum ()
{
   unsigned long Return = 0;
   int lastByte = Attr.getFldSize() - 1;
   int i;
   unsigned long fact = 1;
   for (i = lastByte; i > 0; i--) {
      Return += (Buffer[i] & 0x0F) * fact;
      fact *= 10;
      Return += ((Buffer[i] & 0xF0) >> 4) * fact;
      fact *= 10;
   }
   Return += (Buffer[i] & 0x0F) * fact;
   return Return;
}

Error
StmtAttr::FromTokenTs(const Token &t)
{
   TIMESTAMP_STRUCT ts;
   char *pnt = t.word.gets();
   char *end = pnt + t.word.size();
   char *start;
   PBool isTime = (*pnt == 't'||*pnt == 'T')&&(pnt[1] == ' '||pnt[1] == '\'');
   Null = PFalse;
   
   ts.fraction = ts.year = ts.month = ts.day = 
   ts.hour = ts.minute = ts.second = 0;
   
   for (pnt = t.word.gets(); *pnt; pnt++)
      if (isdigit(*pnt))
         break;
   start = pnt;
   for ( ; *pnt; pnt++)
      if (!isdigit(*pnt))
         break;
   *pnt = 0;
   ts.year = atoi (start);
   if (pnt < end) {
      start = ++pnt;
      for ( ; *pnt; pnt++)
         if (!isdigit(*pnt))
            break;
      *pnt = 0;
      ts.month = atoi (start);
      if (pnt < end) {
         start = ++pnt;
         for ( ; *pnt; pnt++)
            if (!isdigit(*pnt))
               break;
         *pnt = 0;
         ts.day = atoi (start);
         if (pnt < end) {
            for (++pnt; *pnt; pnt++)
                if (isdigit(*pnt))
                   break;
            start = pnt;
            for ( ; *pnt; pnt++)
               if (!isdigit(*pnt))
                  break;
            *pnt = 0;
            ts.hour = atoi (start);
            if (pnt < end) {
               start = ++pnt;
               for ( ; *pnt; pnt++)
                  if (!isdigit(*pnt))
                     break;
               *pnt = 0;
               ts.minute = atoi (start);
               if (pnt < end) {
                  start = ++pnt;
                  for ( ; *pnt; pnt++)
                     if (!isdigit(*pnt))
                        break;
                  *pnt = 0;
                  ts.second = atoi (start);
                  if (pnt < end) {
                     start = ++pnt;
                     for ( ; *pnt; pnt++)
                        if (!isdigit(*pnt))
                           break;
                     *pnt = 0;
                     ts.fraction = atoi (start);
                  }
               }  
            }
         }
      }
   }
   if (isTime) {
      ts.fraction = ts.hour;
      ts.second = ts.day;
      ts.minute = ts.month;
      ts.hour = ts.year;
      ts.year = ts.month = ts.day = 1;
   }
   if (isTimeStampOk (&ts))
      return FromTimeStamp(&ts);
   else {
      setNullBuffer();
      return SQL_SUCCESS;
   }
}

Error
StmtAttr::FromToken(const Token &t)
{
   Error Return = SQL_SUCCESS;
   int len;
   union cast val;
            
   Null = PFalse;            
   if (Attr.getDateType() == T_TIMESTAMP) {
      Return = FromTokenTs (t);
   } else {
      if (t.token == NULL_) {
         setNullBuffer();
         return Return;
      }

      switch (Attr.GetType()) {
      case T_CSTRING:
         memset (Buffer, 0, (int)Attr.getFldSize());
         if (t.token == STR_LITERAL) {
            len = (int) t.word.size() - 2;
            if (len > Attr.GetLen())
            Return = SQL_SUCCESS_WITH_INFO;
            strncpy (Buffer, t.word (1, len).gets(), Attr.GetLen());
         }
         else
            Return = SQL_ERROR;
         break;
      case T_SHORT:
         if (t.token == NUMBER) {
            if (Attr.GetSign() == UNSIGNED)
               val.usht = atoi(t.word.gets());
            else
               val.sht = atoi(t.word.gets());
            memcpy (Buffer, val.chr, sizeof(short));
         } else
            Return = SQL_ERROR;
         break;
      case T_LONG:
         if (t.token == NUMBER) {
            if (Attr.GetSign() == UNSIGNED)
               val.ulng = atol(t.word.gets());
            else
               val.lng = atol(t.word.gets());
            memcpy (Buffer, val.chr, sizeof(long));
         } else
            Return = SQL_ERROR;
         break;
      case T_FLOAT:
         if (t.token == NUMBER) {
            val.flt = (float) atof(t.word.gets());
            memcpy (Buffer, val.chr, sizeof(float));
         } else
            Return = SQL_ERROR;
         break;
      case T_DOUBLE:
         if (t.token == NUMBER) {
            val.dbl = atof(t.word.gets());
            memcpy (Buffer, val.chr, sizeof(double));
         } else
            Return = SQL_ERROR;
         break;
       case T_BLOB:
          Return = SQL_ERROR;
          break;
       case T_CLOB:
          Return = SQL_ERROR;
          break;
       case T_PACKED_ORDERED:
         if (t.token == NUMBER)
            CharToPackedOrdered (t.word.gets());
         else
            Return = SQL_ERROR;
         break; 
      case T_UNKNOWN:
         PError::InternalError ("T_UNKNOWN in FromToken");
         Return = SQL_ERROR;
         break;
      default: 
         PError::InternalError ("Invalid type in FromToken");
         Return = SQL_ERROR;
         break;
      }
   }
   return Return;
}

Error
StmtAttr::FromAttr (StmtAttr &a)
{
   Error Return = SQL_SUCCESS;
   char *tmpNum;
   long len;
   TIMESTAMP_STRUCT ts;
   union cast val, a_val;

   if (Buffer == 0 || a.Buffer == 0)
      return SQL_ERROR;
   setNullBuffer();
   if (a.isNull())
      return Return;
   else
      Null = PFalse;
      
   if (Attr.getDateType() == T_TIMESTAMP)
      if (a.couldBeTimeStamp()) {
         a.ToTimeStamp (&ts, len = 1);
         FromTimeStamp (&ts);
         return Return;
      } else           
         return Return = SQL_ERROR;

   if (a.Attr.getFldSize() != SQL_NULL_DATA)
      switch (Attr.GetType()) {
      case T_CSTRING:
         switch (a.Attr.GetType()) {
         case T_CSTRING:
            if ((len = strnlen (a.Buffer, a.Attr.GetLen())) > Attr.GetLen()) {
               len = Attr.GetLen();
               Return = SQL_SUCCESS_WITH_INFO;
            }
            memcpy (Buffer, a.Buffer, (int) len);
            if (len < Attr.GetLen())
               Buffer[len] = 0;
            break;
         case T_BLOB: // In prima istanza
         case T_CLOB: // In prima istanza
         case T_PACKED_ORDERED:
         case T_SHORT:
         case T_LONG:
         case T_FLOAT:
         case T_DOUBLE:
            a.ToChar (&tmpNum, len);
            strncpy (Buffer, tmpNum,  Attr.GetLen());
            break;
         default:
            Return = SQL_ERROR;
            break;
         }
         break;
      case T_SHORT:
         switch (a.Attr.GetType()) {
         case T_SHORT:
            memcpy (a_val.chr, a.Buffer, sizeof(short));
            if (Attr.GetSign() == UNSIGNED)
               if (a.Attr.GetSign() == UNSIGNED)
                  val.usht = a_val.usht;
               else
                  val.usht = a_val.sht;
            else
               if (a.Attr.GetSign() == UNSIGNED)
                  val.sht = a_val.usht;
               else
                  val.sht = a_val.sht;
            memcpy (Buffer, val.chr, sizeof(short));
            break;
         case T_LONG:
            memcpy (a_val.chr, a.Buffer, sizeof(long));
            if (Attr.GetSign() == UNSIGNED)
               if (a.Attr.GetSign() == UNSIGNED)
                  val.usht = a_val.ulng;
               else
                  val.usht = a_val.lng;
            else 
               if (a.Attr.GetSign() == UNSIGNED)
                  val.sht = a_val.ulng;
               else
                  val.sht = a_val.lng;
            memcpy (Buffer, val.chr, sizeof(short));
            break;
         case T_FLOAT:
            memcpy (a_val.chr, a.Buffer, sizeof(float));
            if (Attr.GetSign() == UNSIGNED)
               val.usht = (unsigned short) a_val.flt;
            else
               val.sht = (short) a_val.flt;
            memcpy (Buffer, val.chr, sizeof(short));
            break;
         case T_DOUBLE:
            memcpy (a_val.chr, a.Buffer, sizeof(double));
            if (Attr.GetSign() == UNSIGNED)
               val.usht = (unsigned short) a_val.dbl;
            else
               val.sht = (short) a_val.dbl;
            memcpy (Buffer, val.chr, sizeof(short));
            break;
         case T_BLOB: // In prima istanza
         case T_CLOB: // In prima istanza
         case T_PACKED_ORDERED:
            a.ToChar (&tmpNum, len);
            if (Attr.GetSign() == UNSIGNED)
               val.usht = atoi (tmpNum);
            else
               val.sht = atoi (tmpNum);
            memcpy (Buffer, val.chr, sizeof(short));
            break;
         case T_CSTRING:
            if (Attr.GetSign() == UNSIGNED)
               val.usht = atoi (a.Buffer);
            else
               val.sht = atoi(a.Buffer);
            memcpy (Buffer, val.chr, sizeof(short));
            break;
         default:
            Return =  SQL_ERROR;
            break;
         }
         break;
      case T_LONG:
         switch (a.Attr.GetType()) {
         case T_SHORT:
            memcpy (a_val.chr, a.Buffer, sizeof(short));
            if (Attr.GetSign() == UNSIGNED)
               if (a.Attr.GetSign() == UNSIGNED)
                  val.ulng = a_val.usht;
               else 
                  val.ulng = a_val.sht;
            else
               if (a.Attr.GetSign() == UNSIGNED)
                  val.lng = a_val.usht;
               else
                  val.lng = a_val.sht;
            memcpy (Buffer, val.chr, sizeof(long));
            break;
         case T_LONG:
            memcpy (a_val.chr, a.Buffer, sizeof(long));
            if (Attr.GetSign() == UNSIGNED)
               if (a.Attr.GetSign() == UNSIGNED)
                  val.ulng = a_val.ulng;
               else
                  val.ulng = a_val.lng;
            else
               if (a.Attr.GetSign() == UNSIGNED)
                  val.lng = a_val.ulng;
               else
                  val.lng = a_val.lng;
            memcpy (Buffer, val.chr, sizeof(long));
            break;
         case T_FLOAT:
            memcpy (a_val.chr, a.Buffer, sizeof(float));
            if (Attr.GetSign() == UNSIGNED)
               val.ulng = (unsigned long) a_val.flt;
            else
               val.lng = (long) a_val.flt;
            memcpy (Buffer, val.chr, sizeof(long));
            break;
         case T_DOUBLE:
            memcpy (a_val.chr, a.Buffer, sizeof(double));
            if (Attr.GetSign() == UNSIGNED)
               val.ulng = (unsigned long) a_val.dbl;
            else
               val.lng = (long) a_val.dbl;
            memcpy (Buffer, val.chr, sizeof(long));
            break;
         case T_BLOB: // In prima istanza
         case T_CLOB: // In prima istanza
         case T_PACKED_ORDERED:
            a.ToChar (&tmpNum, len);
            if (Attr.GetSign() == UNSIGNED)
               val.ulng = atol (tmpNum);
            else
               val.lng = atol (tmpNum);
            memcpy (Buffer, val.chr, sizeof(long));
            break;
         case T_CSTRING:
            if (Attr.GetSign() == UNSIGNED)
               val.ulng = atol(a.Buffer);
            else
               val.lng = atol(a.Buffer);
            memcpy (Buffer, val.chr, sizeof(long));
            break;
         default:
            Return =  SQL_ERROR;
            break;
         }
         break;
      case T_FLOAT:
         switch (a.Attr.GetType()) {
         case T_SHORT:
            memcpy (a_val.chr, a.Buffer, sizeof(short));
            if (a.Attr.GetSign() == UNSIGNED)
               val.flt = a_val.usht;
            else
               val.flt = a_val.sht;
            memcpy (Buffer, val.chr, sizeof(float));
            break;
         case T_LONG:
            memcpy (a_val.chr, a.Buffer, sizeof(long));
            if (a.Attr.GetSign() == UNSIGNED)
               val.flt = a_val.ulng;
            else
               val.flt = a_val.lng;
            memcpy (Buffer, val.chr, sizeof(float));
            break;
         case T_FLOAT:
            memcpy (a_val.chr, a.Buffer, sizeof(float));
            val.flt = a_val.flt;
            memcpy (Buffer, val.chr, sizeof(float));
            break;
         case T_DOUBLE:
            memcpy (a_val.chr, a.Buffer, sizeof(double));
            val.flt = a_val.dbl;
            memcpy (Buffer, val.chr, sizeof(float));
            break;
         case T_BLOB: // In prima istanza
         case T_CLOB: // In prima istanza
         case T_PACKED_ORDERED:
            a.ToChar (&tmpNum, len);
            val.flt = atof (tmpNum);
            memcpy (Buffer, val.chr, sizeof(float));
            break;
         case T_CSTRING:
            val.flt = atof(a.Buffer);
            memcpy (Buffer, val.chr, sizeof(float));
            break;
         default:
            Return =  SQL_ERROR;
            break;
         }
         break;
      case T_DOUBLE:
         switch (a.Attr.GetType()) {
         case T_SHORT:
            memcpy (a_val.chr, a.Buffer, sizeof(short));
            if (a.Attr.GetSign() == UNSIGNED)
               val.dbl = a_val.usht;
            else
               val.dbl = a_val.sht;
            memcpy (Buffer, val.chr, sizeof(double));
            break;
         case T_LONG:
            memcpy (a_val.chr, a.Buffer, sizeof(long));
            if (a.Attr.GetSign() == UNSIGNED)
               val.dbl = a_val.ulng;
            else
               val.dbl = a_val.lng;
            memcpy (Buffer, val.chr, sizeof(double));
            break;
         case T_FLOAT:
            memcpy (a_val.chr, a.Buffer, sizeof(float));
            val.dbl = a_val.flt;
            memcpy (Buffer, val.chr, sizeof(double));
            break;
         case T_DOUBLE:
            memcpy (a_val.chr, a.Buffer, sizeof(double));
            val.dbl = a_val.dbl;
            memcpy (Buffer, val.chr, sizeof(double));
            break;
         case T_BLOB: // In prima istanza
         case T_CLOB: // In prima istanza
         case T_PACKED_ORDERED:
            a.ToChar (&tmpNum, len);
            val.dbl = atof (tmpNum);
            memcpy (Buffer, val.chr, sizeof(double));
            break;
         case T_CSTRING:
            val.dbl = atof(a.Buffer);
            memcpy (Buffer, val.chr, sizeof(double));
            break;
         default:
            Return =  SQL_ERROR;
            break;
         }
         break;
      case T_BLOB:
      case T_CLOB:
         if (a.bField) {
            if (a.Buffer[0] != 0)
               memcpy (Buffer, a.Buffer, a.Attr.getFldSize());
            *bField = *a.bField;
         } else
            bField->setBlob ((unsigned char *)a.Buffer,
                             a.getAttr()->getFldSize());
         break;
      case T_PACKED_ORDERED:
         a.ToChar (&tmpNum, len);
         CharToPackedOrdered (tmpNum);
         break; 
      default:
         Return =  SQL_ERROR;
         break;
      }
   return Return;
}

Error
StmtAttr::FromString(const char *s)
{
   Error Return = SQL_SUCCESS;
   int len;
   union cast val;

   setNullBuffer();
   if (s == 0)
      return Return;
   else
      Null = PFalse;
   switch (Attr.GetType()) {
   case T_CSTRING: 
      strncpy (Buffer, s, Attr.GetLen());
      break;
   case T_SHORT:
      if (Attr.GetSign() == UNSIGNED)
         val.usht= atoi(s);
      else
         val.sht= atoi(s);
      memcpy (Buffer, val.chr, sizeof(short));
      break; 
   case T_LONG:
      if (Attr.GetSign() == UNSIGNED)
         val.ulng = atol(s);
      else
         val.lng = atol(s);
      memcpy (Buffer, val.chr, sizeof(long));
      break;  
   case T_FLOAT:
      val.flt = atof(s);
      memcpy (Buffer, val.chr, sizeof(float));
      break;    
   case T_DOUBLE:
      val.dbl = atof(s);
      memcpy (Buffer, val.chr, sizeof(double));
      break;
   case T_BLOB: // solo in prima istanza
   case T_CLOB: // solo in prima istanza
   case T_PACKED_ORDERED:
      CharToPackedOrdered (s);
      break; 
   case T_UNKNOWN:
      // Qui non ci deve arrivare mai !
      break;
   }
   return Return;
}
