/*!================================================================
 module:    typestest.cpp

 responsible: D039759

 special area: Type conversion
 description:  Check program that checks conversions.

 see:

 change history:


    ========== licence begin  GPL
    Copyright (c) 2000-2005 SAP AG

    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
    of the License, 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end




 ===================================================================*/

#include "SAPDB/Interfaces/sapdbifr.h"
#include "SAPDB/Interfaces/tests/TestUtils.h"
#include <limits.h>


template <class Integer>
Integer shred(Integer value)
{
    return ~value;
}

#ifdef SVR4
template <>
#endif
double shred(double value)
{
    return value * rand();
}

#define CHECK_INTEGRALTYPE_WP(xxtype, xxhosttype, xxvalue, xxindex, xxtablename, xxpformat)                         \
  do {                                                                                                              \
    xxtype x1;                                                                                                      \
    x1=(xxtype)xxvalue;                                                                                             \
    IFR_PreparedStmt *p1=tc_errorcheck(connection())->createPreparedStatement();                                    \
    IFR_Length x1len=(IFR_Length) sizeof(xxtype);                                                                   \
    tc_errorcheck(p1)->bindParameter(1, xxhosttype, &x1, &x1len, (IFR_Length)sizeof(xxtype));                       \
    tc_errorcheck(p1)->prepare("INSERT INTO " #xxtablename " VALUES(" #xxindex ", ?)", IFR_StringEncodingAscii);    \
    tc_errorcheck(p1)->execute();                                                                                   \
    xxtype x2;                                                                                                      \
    x2 = (xxtype) shred((xxtype)xxvalue);                                                                           \
    IFR_PreparedStmt *p2=tc_errorcheck(connection())->createPreparedStatement();                                    \
    IFR_Length x2len=(IFR_Length) sizeof(xxtype);                                                                   \
    tc_errorcheck(p2)->bindParameter(1, xxhosttype, &x2, &x2len, (IFR_Length) sizeof(xxtype));                      \
    tc_errorcheck(p2)->prepare("SELECT V INTO ? FROM " #xxtablename " WHERE K=" #xxindex, IFR_StringEncodingAscii); \
    tc_errorcheck(p2)->execute();                                                                                   \
    if(x2 != x1) {                                                                                                  \
        logerror("Value mismatch from inserted value " #xxvalue                                                     \
                 " for host type " #xxhosttype ", " xxpformat " found.", x2);                                       \
    }  else {                                                                                                       \
      if(x2 != (xxtype) xxvalue) {                                                                                  \
        logerror("Value mismatch in value " #xxvalue " for host type " #xxhosttype ", " xxpformat " found.", x2);   \
      }                                                                                                             \
    }                                                                                                               \
    connection()->releaseStatement(p1);                                                                             \
    connection()->releaseStatement(p2);                                                                             \
  } while(0)


#define CHECK_INTEGER(xxtype, xxhosttype, xxvalue, xxindex, xxtablename) \
  CHECK_INTEGRALTYPE_WP(xxtype, xxhosttype, xxvalue, xxindex, xxtablename, "%d")

#define CHECK_FLOAT(xxtype, xxhosttype, xxvalue, xxindex, xxtablename) \
  CHECK_INTEGRALTYPE_WP(xxtype, xxhosttype, xxvalue, xxindex, xxtablename, "%f")


#define CHECK_STRING_Z(xxinsertstr, xxcomparestr, xxhosttype, xxindex, xxtablename) \
CheckString((char *)xxinsertstr, IFR_NTS, (char *)xxcomparestr, xxhosttype, xxindex,(char *) #xxtablename)

#define CHECK_STRING(xxinsertstr, xxstrlen, xxcomparestr, xxhosttype, xxindex, xxtablename) \
CheckString((char *)xxinsertstr, xxstrlen, (char *)xxcomparestr, xxhosttype, xxindex, (char *) #xxtablename)

//----------------------------------------------------------------------
class CharAsciiTest : public IFR_TestCase
{
public:
    CharAsciiTest(const char *test = "CharAsciiTest")
    :IFR_TestCase(test)
    {}

  void CheckString(char *xxinsertstr, IFR_Int4 xxstrlen, char *xxcomparestr, IFR_HostType xxhosttype,
                    int xxindex, char *xxtablename)

  {
      int xxlen = (xxstrlen == IFR_NTS) ? strlen(xxinsertstr)+1 : xxstrlen+1;
      if (xxhosttype == IFR_HOSTTYPE_UCS2_NATIVE)
        xxlen *= 2;
      char *x1=new char[xxlen];
      char *x2=new char[xxlen];
      if (xxhosttype == IFR_HOSTTYPE_UCS2_NATIVE) {
        convertToUCS2((unsigned short*)x1, xxlen, xxinsertstr);
        if (xxstrlen != IFR_NTS)
          xxstrlen = xxstrlen*2;
      }
      else
        strcpy(x1, xxinsertstr);
      memcpy(x2, x1, xxlen);
      IFR_PreparedStmt *p1=tc_errorcheck(connection())->createPreparedStatement();
      IFR_Length x1len=xxstrlen;
      tc_errorcheck(p1)->bindParameter(1, xxhosttype, x1, &x1len, xxlen);
      char szSQL[500];
      sprintf(szSQL, "INSERT INTO \"%s\" VALUES (%d, ?)", xxtablename, xxindex);
      tc_errorcheck(p1)->prepare(szSQL, IFR_StringEncodingAscii);
      tc_errorcheck(p1)->execute();
      if(memcmp(x1, x2, xxlen)!=0) {
        logerror("Insert modified the data for \"%s\".", xxinsertstr);
      }
      xxlen = strlen(xxcomparestr)+1;
      if (xxhosttype == IFR_HOSTTYPE_UCS2_NATIVE)
        xxlen *= 2;
      delete [] x2;
      x2=new char[xxlen];
      if (xxhosttype == IFR_HOSTTYPE_UCS2_NATIVE)
        convertToUCS2((unsigned short*)x2, xxlen, xxcomparestr);
      else
        strcpy(x2, xxcomparestr);
      char *x3=new char[xxlen];
      memset(x3, 0, xxlen);
      IFR_PreparedStmt *p2=tc_errorcheck(connection())->createPreparedStatement();
      IFR_Length x3len=0;
      tc_errorcheck(p2)->bindParameter(1, xxhosttype, x3, &x3len, xxlen);
      sprintf(szSQL, "SELECT V INTO ? FROM \"%s\" WHERE K=%d", xxtablename, xxindex);
      tc_errorcheck(p2)->prepare(szSQL, IFR_StringEncodingAscii);
      tc_errorcheck(p2)->execute();
      if(memcmp(x2, x3, xxlen)!=0) {
        logerror("Value mismatch in value \"%s\" inserted was \"%s\".", xxcomparestr, xxinsertstr);
      }
      delete [] x1;
      delete [] x2;
      delete [] x3;
      connection()->releaseStatement(p1);
      connection()->releaseStatement(p2);
  }

    virtual IFR_Bool run()
    {
        dropTable("CHARASCII_TEST");
        m_success = m_success && execSQL("CREATE TABLE CHARASCII_TEST (K INT, V CHAR (40) ASCII)");


        CHECK_STRING_Z("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
                       "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
                       IFR_HOSTTYPE_ASCII,
                       1,
                       CHARASCII_TEST);

        CHECK_STRING_Z("",
                       "                                        ",
                       IFR_HOSTTYPE_ASCII,
                       2,
                       CHARASCII_TEST);

        CHECK_STRING_Z("AA",
                       "AA                                      ",
                       IFR_HOSTTYPE_ASCII,
                       3,
                       CHARASCII_TEST);

        CHECK_STRING_Z("  AA  AA  ",
                       "  AA  AA                                ",
                       IFR_HOSTTYPE_ASCII,
                       4,
                       CHARASCII_TEST);

        CHECK_STRING("1", 1,
                     "1                                       ",
                     IFR_HOSTTYPE_ASCII,
                     5,
                     CHARASCII_TEST);

        CHECK_STRING("1", 1,
                     "1                                       ",
                     IFR_HOSTTYPE_UCS2_NATIVE,
                     6,
                     CHARASCII_TEST);

        CHECK_STRING("1234567890123456789012345678901234567890", 40,
                     "1234567890123456789012345678901234567890",
                     IFR_HOSTTYPE_ASCII,
                     7,
                     CHARASCII_TEST);

        CHECK_STRING("1234567890123456789012345678901234567890", 40,
                     "1234567890123456789012345678901234567890",
                     IFR_HOSTTYPE_UCS2_NATIVE,
                     8,
                     CHARASCII_TEST);

        CHECK_STRING("  34  78  ", 10,
                     "  34  78                                ",
                     IFR_HOSTTYPE_UCS2_NATIVE,
                     9,
                     CHARASCII_TEST);

        CHECK_INTEGER(IFR_Int1, IFR_HOSTTYPE_INT1, 0, 100, CHARASCII_TEST);
        CHECK_INTEGER(IFR_Int2, IFR_HOSTTYPE_INT2, 0, 101, CHARASCII_TEST);
        CHECK_INTEGER(IFR_Int4, IFR_HOSTTYPE_INT4, 0, 102, CHARASCII_TEST);
        CHECK_INTEGER(IFR_Int8, IFR_HOSTTYPE_INT8, 0, 103, CHARASCII_TEST);


        CHECK_INTEGER(IFR_UInt1, IFR_HOSTTYPE_UINT1, 0, 104, CHARASCII_TEST);
        CHECK_INTEGER(IFR_UInt2, IFR_HOSTTYPE_UINT2, 0, 105, CHARASCII_TEST);
        CHECK_INTEGER(IFR_UInt4, IFR_HOSTTYPE_UINT4, 0, 106, CHARASCII_TEST);
        CHECK_INTEGER(IFR_UInt8, IFR_HOSTTYPE_UINT8, 0, 107, CHARASCII_TEST);

        CHECK_INTEGER(IFR_Int1, IFR_HOSTTYPE_INT1, -128, 108, CHARASCII_TEST);
        CHECK_INTEGER(IFR_Int1, IFR_HOSTTYPE_INT1, 127, 109, CHARASCII_TEST);

        CHECK_INTEGER(IFR_Int2, IFR_HOSTTYPE_INT2, -32768, 110, CHARASCII_TEST);
        CHECK_INTEGER(IFR_Int2, IFR_HOSTTYPE_INT2, 32767, 111, CHARASCII_TEST);


        CHECK_INTEGER(IFR_Int4, IFR_HOSTTYPE_INT4, (-2147483647 - 1), 112, CHARASCII_TEST);
        CHECK_INTEGER(IFR_Int4, IFR_HOSTTYPE_INT4, 2147483647, 113, CHARASCII_TEST);


#if defined(WIN32)
        CHECK_INTEGER(IFR_Int8, IFR_HOSTTYPE_INT8, _I64_MIN, 114, CHARASCII_TEST);
        CHECK_INTEGER(IFR_Int8, IFR_HOSTTYPE_INT8, _I64_MAX, 115, CHARASCII_TEST);
        CHECK_INTEGER(IFR_UInt8, IFR_HOSTTYPE_UINT8, _UI64_MAX, 116, CHARASCII_TEST);
#elif (defined(UNIX) && !defined(BIT64)) || defined(LINUX)
        CHECK_INTEGER(IFR_Int8, IFR_HOSTTYPE_INT8, 9223372036854775807LL , 114, CHARASCII_TEST);
        CHECK_INTEGER(IFR_Int8, IFR_HOSTTYPE_INT8, -9223372036854775808LL, 115, CHARASCII_TEST);
        CHECK_INTEGER(IFR_UInt8, IFR_HOSTTYPE_UINT8, 18446744073709551615ULL, 116, CHARASCII_TEST);
#else
        CHECK_INTEGER(IFR_Int8, IFR_HOSTTYPE_INT8, 9223372036854775807 , 114, CHARASCII_TEST);
        CHECK_INTEGER(IFR_Int8, IFR_HOSTTYPE_INT8, -9223372036854775808, 115, CHARASCII_TEST);
        CHECK_INTEGER(IFR_UInt8, IFR_HOSTTYPE_UINT8, 18446744073709551615UL, 116, CHARASCII_TEST);
#endif
        CHECK_INTEGER(IFR_UInt4, IFR_HOSTTYPE_UINT4, 4294967295, 117, CHARASCII_TEST);
        CHECK_INTEGER(IFR_UInt2, IFR_HOSTTYPE_UINT2, (unsigned short)65535, 118, CHARASCII_TEST);
        CHECK_INTEGER(IFR_UInt1, IFR_HOSTTYPE_UINT1, (unsigned char)255, 119, CHARASCII_TEST);

        execSQL("COMMIT WORK");
        return m_success;
    }
};


//----------------------------------------------------------------------
class CharUnicodeTest : public CharAsciiTest
{
public:
    CharUnicodeTest()
    :CharAsciiTest("CharUnicodeTest")
    {}

    virtual IFR_Bool run()
    {
      if (!connection()->isUnicodeDatabase()) {
        return m_success;
      }
        dropTable("CHARUNICODE_TEST");
        m_success = m_success && execSQL("CREATE TABLE CHARUNICODE_TEST (K INT, V CHAR (40) UNICODE)");


        CHECK_STRING_Z("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
                       "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
                       IFR_HOSTTYPE_ASCII,
                       1,
                       CHARUNICODE_TEST);

        CHECK_STRING_Z("",
                       "                                        ",
                       IFR_HOSTTYPE_ASCII,
                       2,
                       CHARUNICODE_TEST);

        CHECK_STRING_Z("AA",
                       "AA                                      ",
                       IFR_HOSTTYPE_ASCII,
                       3,
                       CHARUNICODE_TEST);

        CHECK_STRING_Z("  AA  AA  ",
                       "  AA  AA                                ",
                       IFR_HOSTTYPE_ASCII,
                       4,
                       CHARUNICODE_TEST);

        CHECK_STRING_Z("1",
                       "1                                       ",
                       IFR_HOSTTYPE_UCS2_NATIVE,
                       5,
                       CHARUNICODE_TEST);

        CHECK_STRING_Z("1234567890123456789012345678901234567890",
                       "1234567890123456789012345678901234567890",
                       IFR_HOSTTYPE_UCS2_NATIVE,
                       6,
                       CHARUNICODE_TEST);

        CHECK_STRING  ("  34  78  ", 10,
                       "  34  78                                ",
                       IFR_HOSTTYPE_UCS2_NATIVE,
                       7,
                       CHARUNICODE_TEST);

        CHECK_INTEGER(IFR_Int1, IFR_HOSTTYPE_INT1, 0, 100, CHARUNICODE_TEST);
        CHECK_INTEGER(IFR_Int2, IFR_HOSTTYPE_INT2, 0, 101, CHARUNICODE_TEST);
        CHECK_INTEGER(IFR_Int4, IFR_HOSTTYPE_INT4, 0, 102, CHARUNICODE_TEST);
        CHECK_INTEGER(IFR_Int8, IFR_HOSTTYPE_INT8, 0, 103, CHARUNICODE_TEST);


        CHECK_INTEGER(IFR_UInt1, IFR_HOSTTYPE_UINT1, 0, 104, CHARUNICODE_TEST);
        CHECK_INTEGER(IFR_UInt2, IFR_HOSTTYPE_UINT2, 0, 105, CHARUNICODE_TEST);
        CHECK_INTEGER(IFR_UInt4, IFR_HOSTTYPE_UINT4, 0, 106, CHARUNICODE_TEST);
        CHECK_INTEGER(IFR_UInt8, IFR_HOSTTYPE_UINT8, 0, 107, CHARUNICODE_TEST);

        CHECK_INTEGER(IFR_Int1, IFR_HOSTTYPE_INT1, -128, 108, CHARUNICODE_TEST);
        CHECK_INTEGER(IFR_Int1, IFR_HOSTTYPE_INT1, 127, 109, CHARUNICODE_TEST);

        CHECK_INTEGER(IFR_Int2, IFR_HOSTTYPE_INT2, -32768, 110, CHARUNICODE_TEST);
        CHECK_INTEGER(IFR_Int2, IFR_HOSTTYPE_INT2, 32767, 111, CHARUNICODE_TEST);

        CHECK_INTEGER(IFR_Int4, IFR_HOSTTYPE_INT4, (-2147483647 - 1), 112, CHARUNICODE_TEST);
        CHECK_INTEGER(IFR_Int4, IFR_HOSTTYPE_INT4, 2147483647, 113, CHARUNICODE_TEST);

#if defined(WIN32)
        CHECK_INTEGER(IFR_Int8, IFR_HOSTTYPE_INT8, _I64_MIN, 114, CHARUNICODE_TEST);
        CHECK_INTEGER(IFR_Int8, IFR_HOSTTYPE_INT8, _I64_MAX, 115, CHARUNICODE_TEST);
        CHECK_INTEGER(IFR_UInt8, IFR_HOSTTYPE_UINT8, _UI64_MAX, 116, CHARUNICODE_TEST);
#elif (defined(UNIX) && !defined(BIT64)) || defined(LINUX)
        CHECK_INTEGER(IFR_Int8, IFR_HOSTTYPE_INT8, 9223372036854775807LL , 114, CHARUNICODE_TEST);
        CHECK_INTEGER(IFR_Int8, IFR_HOSTTYPE_INT8, -9223372036854775808LL, 115, CHARUNICODE_TEST);
        CHECK_INTEGER(IFR_UInt8, IFR_HOSTTYPE_UINT8, 18446744073709551615ULL, 116, CHARUNICODE_TEST);
#else
        CHECK_INTEGER(IFR_Int8, IFR_HOSTTYPE_INT8, 9223372036854775807 , 114, CHARUNICODE_TEST);
        CHECK_INTEGER(IFR_Int8, IFR_HOSTTYPE_INT8, -9223372036854775808, 115, CHARUNICODE_TEST);
        CHECK_INTEGER(IFR_UInt8, IFR_HOSTTYPE_UINT8, 18446744073709551615UL, 116, CHARUNICODE_TEST);
#endif

        CHECK_INTEGER(IFR_UInt4, IFR_HOSTTYPE_UINT4, 4294967295, 117, CHARUNICODE_TEST);
        CHECK_INTEGER(IFR_UInt2, IFR_HOSTTYPE_UINT2, (unsigned short)65535, 118, CHARUNICODE_TEST);
        CHECK_INTEGER(IFR_UInt1, IFR_HOSTTYPE_UINT1, (unsigned char)255, 119, CHARUNICODE_TEST);

        execSQL("COMMIT WORK");
        return m_success;
    }
};


class NumericTest : public IFR_TestCase
{
public:
    NumericTest()
    :IFR_TestCase("NumericTest")
    {}

    IFR_Bool runInteger()
    {
        dropTable("INTEGER_TEST");
        m_success = m_success && execSQL("CREATE TABLE INTEGER_TEST (K INT, V INTEGER)");

         CHECK_INTEGER(IFR_Int1, IFR_HOSTTYPE_INT1, 17, 1, INTEGER_TEST);
         CHECK_INTEGER(IFR_Int2, IFR_HOSTTYPE_INT2, 17, 2, INTEGER_TEST);
         CHECK_INTEGER(IFR_Int4, IFR_HOSTTYPE_INT4, 17, 3, INTEGER_TEST);
         CHECK_INTEGER(IFR_Int8, IFR_HOSTTYPE_INT8, 17, 4, INTEGER_TEST);

         CHECK_INTEGER(IFR_UInt1, IFR_HOSTTYPE_UINT1, 17, 5, INTEGER_TEST);
         CHECK_INTEGER(IFR_UInt2, IFR_HOSTTYPE_UINT2, 17, 6, INTEGER_TEST);
         CHECK_INTEGER(IFR_UInt4, IFR_HOSTTYPE_UINT4, 17, 7, INTEGER_TEST);
         CHECK_INTEGER(IFR_UInt8, IFR_HOSTTYPE_UINT8, 17, 8, INTEGER_TEST);

         CHECK_INTEGER(IFR_Int1, IFR_HOSTTYPE_INT1, -17, 9, INTEGER_TEST);
         CHECK_INTEGER(IFR_Int2, IFR_HOSTTYPE_INT2, -17, 10, INTEGER_TEST);
         CHECK_INTEGER(IFR_Int4, IFR_HOSTTYPE_INT4, -17, 11, INTEGER_TEST);
         CHECK_INTEGER(IFR_Int8, IFR_HOSTTYPE_INT8, -17, 12, INTEGER_TEST);

         CHECK_INTEGER(IFR_Int1, IFR_HOSTTYPE_INT1, MIN_IFR_INT1, 13, INTEGER_TEST);
         CHECK_INTEGER(IFR_Int1, IFR_HOSTTYPE_INT1, MAX_IFR_INT1, 14, INTEGER_TEST);
         CHECK_INTEGER(IFR_Int2, IFR_HOSTTYPE_INT2, MIN_IFR_INT2, 15, INTEGER_TEST);
         CHECK_INTEGER(IFR_Int2, IFR_HOSTTYPE_INT2, MAX_IFR_INT2, 16, INTEGER_TEST);
         CHECK_INTEGER(IFR_Int4, IFR_HOSTTYPE_INT4, MIN_IFR_INT4, 17, INTEGER_TEST);
         CHECK_INTEGER(IFR_Int4, IFR_HOSTTYPE_INT4, MAX_IFR_INT4, 18, INTEGER_TEST);

/*
         CHECK_INTEGER(IFR_Int8, IFR_HOSTTYPE_INT8, MIN_IFR_INT8, 19, INTEGER_TEST);
         CHECK_INTEGER(IFR_Int8, IFR_HOSTTYPE_INT8, MAX_IFR_INT8, 20, INTEGER_TEST);
*/
         CHECK_INTEGER(IFR_UInt1, IFR_HOSTTYPE_UINT1, MAX_IFR_UINT1, 21, INTEGER_TEST);
         CHECK_INTEGER(IFR_UInt2, IFR_HOSTTYPE_UINT2, MAX_IFR_UINT2, 22, INTEGER_TEST);
         // CHECK_INTEGER(IFR_UInt4, IFR_HOSTTYPE_UINT4, MAX_IFR_UINT4, 23, INTEGER_TEST);
         // CHECK_INTEGER(IFR_UInt8, IFR_HOSTTYPE_UINT8, MAX_IFR_UINT8, 24, INTEGER_TEST);
         CHECK_INTEGER(IFR_Int2, IFR_HOSTTYPE_INT2, -32730, 25, INTEGER_TEST);
         return m_success;
    }

    IFR_Bool runBigInteger()
    {
        dropTable("BIGINTEGER_TEST");
        m_success = m_success && execSQL("CREATE TABLE BIGINTEGER_TEST (K INT, V FIXED(38,0))");

         CHECK_INTEGER(IFR_Int1, IFR_HOSTTYPE_INT1, 17, 1, BIGINTEGER_TEST);
         CHECK_INTEGER(IFR_Int2, IFR_HOSTTYPE_INT2, 17, 2, BIGINTEGER_TEST);
         CHECK_INTEGER(IFR_Int4, IFR_HOSTTYPE_INT4, 17, 3, BIGINTEGER_TEST);
         CHECK_INTEGER(IFR_Int8, IFR_HOSTTYPE_INT8, 17, 4, BIGINTEGER_TEST);

         CHECK_INTEGER(IFR_UInt1, IFR_HOSTTYPE_UINT1, 17, 5, BIGINTEGER_TEST);
         CHECK_INTEGER(IFR_UInt2, IFR_HOSTTYPE_UINT2, 17, 6, BIGINTEGER_TEST);
         CHECK_INTEGER(IFR_UInt4, IFR_HOSTTYPE_UINT4, 17, 7, BIGINTEGER_TEST);
         CHECK_INTEGER(IFR_UInt8, IFR_HOSTTYPE_UINT8, 17, 8, BIGINTEGER_TEST);

         CHECK_INTEGER(IFR_Int1, IFR_HOSTTYPE_INT1, -17, 9, BIGINTEGER_TEST);
         CHECK_INTEGER(IFR_Int2, IFR_HOSTTYPE_INT2, -17, 10, BIGINTEGER_TEST);
         CHECK_INTEGER(IFR_Int4, IFR_HOSTTYPE_INT4, -17, 11, BIGINTEGER_TEST);
         CHECK_INTEGER(IFR_Int8, IFR_HOSTTYPE_INT8, -17, 12, BIGINTEGER_TEST);

         CHECK_INTEGER(IFR_Int1, IFR_HOSTTYPE_INT1, MIN_IFR_INT1, 13, BIGINTEGER_TEST);
         CHECK_INTEGER(IFR_Int1, IFR_HOSTTYPE_INT1, MAX_IFR_INT1, 14, BIGINTEGER_TEST);
         CHECK_INTEGER(IFR_Int2, IFR_HOSTTYPE_INT2, MIN_IFR_INT2, 15, BIGINTEGER_TEST);
         CHECK_INTEGER(IFR_Int2, IFR_HOSTTYPE_INT2, MAX_IFR_INT2, 16, BIGINTEGER_TEST);
         CHECK_INTEGER(IFR_Int4, IFR_HOSTTYPE_INT4, MIN_IFR_INT4, 17, BIGINTEGER_TEST);
         CHECK_INTEGER(IFR_Int4, IFR_HOSTTYPE_INT4, MAX_IFR_INT4, 18, BIGINTEGER_TEST);

         CHECK_INTEGER(IFR_Int8, IFR_HOSTTYPE_INT8, MIN_IFR_INT8, 19, BIGINTEGER_TEST);

         CHECK_INTEGER(IFR_Int8, IFR_HOSTTYPE_INT8, MAX_IFR_INT8, 20, BIGINTEGER_TEST);

         CHECK_INTEGER(IFR_UInt1, IFR_HOSTTYPE_UINT1, MAX_IFR_UINT1, 21, BIGINTEGER_TEST);
         CHECK_INTEGER(IFR_UInt2, IFR_HOSTTYPE_UINT2, MAX_IFR_UINT2, 22, BIGINTEGER_TEST);
         CHECK_INTEGER(IFR_UInt4, IFR_HOSTTYPE_UINT4, MAX_IFR_UINT4, 23, BIGINTEGER_TEST);
         CHECK_INTEGER(IFR_UInt8, IFR_HOSTTYPE_UINT8, MAX_IFR_UINT8, 24, BIGINTEGER_TEST);

         return m_success;
    }


    virtual IFR_Bool run()
    {
        m_success = m_success && runInteger();
        m_success = m_success && runBigInteger();
        execSQL("COMMIT WORK");
        return m_success;
    }

};

class TimeCharTest
    : public IFR_TestCase
{
public:
    TimeCharTest()
    :IFR_TestCase("TimeCharTest")
    {}

    virtual IFR_Bool run()
    {

        dropTable("TIMECHAR_TEST");
        m_success = m_success && execSQL("CREATE TABLE TIMECHAR_TEST (K INT, V CHAR(8))");
        m_success = m_success && execSQL("INSERT INTO TIMECHAR_TEST (K, V) VALUES (1, '15:32:56')");

        SQL_TIME_STRUCT tm1;
        IFR_PreparedStmt *p1=tc_errorcheck(connection())->createPreparedStatement();
        {
            IFR_Length len=0;
            tc_errorcheck(p1)->bindParameter(1, IFR_HOSTTYPE_ODBCTIME, &tm1, &len, sizeof(SQL_TIME_STRUCT));
            tc_errorcheck(p1)->prepare("SELECT V INTO ? FROM TIMECHAR_TEST WHERE K=1", IFR_StringEncodingAscii);
            tc_errorcheck(p1)->execute();
        }
        if(tm1.hour!=15 ||
           tm1.minute!=32 ||
           tm1.second!=56) {
            logerror("Difference, expected 15:32:56, found %.2d:%.2d:%.2d", tm1.hour,
                     tm1.minute, tm1.second);
        }
        connection()->releaseStatement(p1);



       SQL_TIME_STRUCT tm2;
       tm2.hour=14;
       tm2.minute=35;
       tm2.second=42;

       IFR_PreparedStmt* p2=tc_errorcheck(connection())->createPreparedStatement();
       {
           IFR_Length len=0;
           tc_errorcheck(p2)->bindParameter(1, IFR_HOSTTYPE_ODBCTIME, &tm2, &len, sizeof(IFR_HOSTTYPE_ODBCTIME));
           tc_errorcheck(p2)->prepare("INSERT INTO TIMECHAR_TEST VALUES (2, ?)", IFR_StringEncodingAscii);
           tc_errorcheck(p2)->execute();
       }
       connection()->releaseStatement(p2);


       SQL_TIME_STRUCT tm3;
       IFR_PreparedStmt *p3=tc_errorcheck(connection())->createPreparedStatement();
       {
           IFR_Length len = 0;
           tc_errorcheck(p3)->bindParameter(1, IFR_HOSTTYPE_ODBCTIME, &tm3, &len, sizeof(SQL_TIME_STRUCT));
           tc_errorcheck(p3)->prepare("SELECT V INTO ? FROM TIMECHAR_TEST WHERE K=2", IFR_StringEncodingAscii);
           tc_errorcheck(p3)->execute();
       }
       connection()->releaseStatement(p3);

       if(tm2.hour!=tm3.hour ||
          tm2.minute!=tm3.minute ||
          tm2.second!=tm3.second) {
           logerror("Wrong %.2d:%.2d:%.2d time, expected 14:35:42.");
       }
       execSQL("COMMIT WORK");
       return m_success;
    }
};

class TimeTimeTest
    : public IFR_TestCase
{
public:
    TimeTimeTest()
    :IFR_TestCase("TimeTimeTest")
    {}

    virtual IFR_Bool run()
    {
        dropTable("TIMETIME_TEST");
        m_success = m_success && execSQL("CREATE TABLE TIMETIME_TEST (K INT, V TIME)");
        m_success = m_success && execSQL("INSERT INTO TIMETIME_TEST (K, V) VALUES (1, '15:32:56')");

        SQL_TIME_STRUCT tm1;
        IFR_PreparedStmt *p1=tc_errorcheck(connection())->createPreparedStatement();

        {
            IFR_Length len = 0;
            tc_errorcheck(p1)->bindParameter(1, IFR_HOSTTYPE_ODBCTIME, &tm1, &len, sizeof(SQL_TIME_STRUCT));
            tc_errorcheck(p1)->prepare("SELECT V INTO ? FROM TIMETIME_TEST WHERE K=1", IFR_StringEncodingAscii);
            tc_errorcheck(p1)->execute();
        }

        if(tm1.hour!=15 ||
           tm1.minute!=32 ||
           tm1.second!=56) {
            logerror("Difference, expected 15:32:56, found %.2d:%.2d:%.2d", tm1.hour,
                     tm1.minute, tm1.second);
        }
        connection()->releaseStatement(p1);

        SQL_TIME_STRUCT tm2;
        tm2.hour=14;
        tm2.minute=35;
        tm2.second=42;

        IFR_PreparedStmt* p2=tc_errorcheck(connection())->createPreparedStatement();
        {
            IFR_Length len = sizeof(SQL_TIME_STRUCT);
            tc_errorcheck(p2)->bindParameter(1, IFR_HOSTTYPE_ODBCTIME, &tm2, &len, sizeof(SQL_TIME_STRUCT));
            tc_errorcheck(p2)->prepare("INSERT INTO TIMETIME_TEST VALUES (2, ?)", IFR_StringEncodingAscii);
            tc_errorcheck(p2)->execute();
        }
        connection()->releaseStatement(p2);

        SQL_TIME_STRUCT tm3;
        IFR_PreparedStmt *p3=tc_errorcheck(connection())->createPreparedStatement();
        {
            IFR_Length len = 0;
            tc_errorcheck(p3)->bindParameter(1, IFR_HOSTTYPE_ODBCTIME, &tm3, &len, sizeof(SQL_TIME_STRUCT));
            tc_errorcheck(p3)->prepare("SELECT V INTO ? FROM TIMETIME_TEST WHERE K=2", IFR_StringEncodingAscii);
            tc_errorcheck(p3)->execute();
        }
        connection()->releaseStatement(p3);
        if(tm2.hour!=tm3.hour ||
           tm2.minute!=tm3.minute ||
           tm2.second!=tm3.second) {
            logerror("Wrong %.2d:%.2d:%.2d time, expected 14:35:42.");
        }
        execSQL("COMMIT WORK");
        return m_success;

    }
};



class DateCharTest
    : public IFR_TestCase
{
public:
    DateCharTest()
    :IFR_TestCase("DateCharTest")
    {}

    virtual IFR_Bool run()
    {

        dropTable("DATECHAR_TEST");
        m_success = m_success && execSQL("CREATE TABLE DATECHAR_TEST (K INT, V CHAR(10))");
        m_success = m_success && execSQL("INSERT INTO DATECHAR_TEST (K, V) VALUES (1, '2002-05-06')");

        SQL_DATE_STRUCT dt1;
        IFR_PreparedStmt *p1=tc_errorcheck(connection())->createPreparedStatement();
        {
            IFR_Length len = 0;
            tc_errorcheck(p1)->bindParameter(1, IFR_HOSTTYPE_ODBCDATE, &dt1, &len, sizeof(SQL_DATE_STRUCT));
            tc_errorcheck(p1)->prepare("SELECT V INTO ? FROM DATECHAR_TEST WHERE K=1", IFR_StringEncodingAscii);
            tc_errorcheck(p1)->execute();
        }
        if(dt1.day!=6 || dt1.month!=5 || dt1.year!=2002) {
            logerror("Difference, expected 2002-05-06, found %.4d-%.2d-%.2d", dt1.year,
                     dt1.month, dt1.day);
        }
        connection()->releaseStatement(p1);



       SQL_DATE_STRUCT dt2;
       dt2.year=2002;
       dt2.month=7;
       dt2.day=31;

       IFR_PreparedStmt* p2=tc_errorcheck(connection())->createPreparedStatement();
       {
           IFR_Length len=0;
           tc_errorcheck(p2)->bindParameter(1, IFR_HOSTTYPE_ODBCDATE, &dt2, &len, sizeof(IFR_HOSTTYPE_ODBCDATE));
           tc_errorcheck(p2)->prepare("INSERT INTO DATECHAR_TEST VALUES (2, ?)", IFR_StringEncodingAscii);
           tc_errorcheck(p2)->execute();
       }
        connection()->releaseStatement(p2);

       SQL_DATE_STRUCT dt3;
       IFR_PreparedStmt *p3=tc_errorcheck(connection())->createPreparedStatement();
       {
           IFR_Length len = 0;
           tc_errorcheck(p3)->bindParameter(1, IFR_HOSTTYPE_ODBCDATE, &dt3, &len, sizeof(SQL_DATE_STRUCT));
           tc_errorcheck(p3)->prepare("SELECT V INTO ? FROM DATECHAR_TEST WHERE K=2", IFR_StringEncodingAscii);
           tc_errorcheck(p3)->execute();
       }
       connection()->releaseStatement(p3);

       if(!memcmp(&dt2, &dt3, sizeof(SQL_DATE_STRUCT)) == 0) {
           logerror("Difference, expected 2002-07-31, found %.4d-%.2d-%.2d", dt3.year,
                    dt3.month, dt3.day);
       }
       execSQL("COMMIT WORK");
       return m_success;
    }
};

class DateDateTest
    : public IFR_TestCase
{
public:
    DateDateTest()
    :IFR_TestCase("DateDateTest")
    {}

    virtual IFR_Bool run()
    {

        dropTable("DATEDATE_TEST");
        m_success = m_success && execSQL("CREATE TABLE DATEDATE_TEST (K INT, V DATE)");
        m_success = m_success && execSQL("INSERT INTO DATEDATE_TEST (K, V) VALUES (1, '2002-05-06')");

        SQL_DATE_STRUCT dt1;
        IFR_PreparedStmt *p1=tc_errorcheck(connection())->createPreparedStatement();
        {
            IFR_Length len = 0;
            tc_errorcheck(p1)->bindParameter(1, IFR_HOSTTYPE_ODBCDATE, &dt1, &len, sizeof(SQL_DATE_STRUCT));
            tc_errorcheck(p1)->prepare("SELECT V INTO ? FROM DATEDATE_TEST WHERE K=1", IFR_StringEncodingAscii);
            tc_errorcheck(p1)->execute();
        }
        if(dt1.day!=6 || dt1.month!=5 || dt1.year!=2002) {
            logerror("Difference, expected 2002-05-06, found %.4d-%.2d-%.2d", dt1.year,
                     dt1.month, dt1.day);
        }
        connection()->releaseStatement(p1);
        

       SQL_DATE_STRUCT dt2;
       dt2.year=2002;
       dt2.month=7;
       dt2.day=31;

       IFR_PreparedStmt* p2=tc_errorcheck(connection())->createPreparedStatement();
       {
           IFR_Length len=0;
           tc_errorcheck(p2)->bindParameter(1, IFR_HOSTTYPE_ODBCDATE, &dt2, &len, sizeof(IFR_HOSTTYPE_ODBCDATE));
           tc_errorcheck(p2)->prepare("INSERT INTO DATEDATE_TEST VALUES (2, ?)", IFR_StringEncodingAscii);
           tc_errorcheck(p2)->execute();
       }
        connection()->releaseStatement(p2);

       SQL_DATE_STRUCT dt3;
       IFR_PreparedStmt *p3=tc_errorcheck(connection())->createPreparedStatement();
       {
           IFR_Length len;
           tc_errorcheck(p3)->bindParameter(1, IFR_HOSTTYPE_ODBCDATE, &dt3, &len, sizeof(SQL_DATE_STRUCT));
           tc_errorcheck(p3)->prepare("SELECT V INTO ? FROM DATEDATE_TEST WHERE K=2", IFR_StringEncodingAscii);
           tc_errorcheck(p3)->execute();
       }
        connection()->releaseStatement(p2);

       if(!memcmp(&dt2, &dt3, sizeof(SQL_DATE_STRUCT)) == 0) {
           logerror("Difference, expected 2002-07-31, found %.4d-%.2d-%.2d", dt3.year,
                    dt3.month, dt3.day);
       }
       execSQL("COMMIT WORK");
       return m_success;
    }
};


class FloatFloatTest
    : public IFR_TestCase
{
public:
    FloatFloatTest()
    :IFR_TestCase("FloatFloatTest")
    {}

    void checkValue(int key, double value, const char *tablename)
    {
        double x1;
        x1=value;
        IFR_PreparedStmt *p1=tc_errorcheck(connection())->createPreparedStatement();
        IFR_Length x1len=sizeof(double);
        tc_errorcheck(p1)->bindParameter(1, IFR_HOSTTYPE_DOUBLE, &x1, &x1len, sizeof(double));
        char insert_stm[1024];
        sprintf(insert_stm, "INSERT INTO  %s VALUES(%d, ?)", tablename, key);
        tc_errorcheck(p1)->prepare(insert_stm, IFR_StringEncodingAscii);
        tc_errorcheck(p1)->execute();
        double x2;
        x2 = shred((double)value);
        IFR_PreparedStmt *p2=tc_errorcheck(connection())->createPreparedStatement();
        IFR_Length x2len=sizeof(double);
        tc_errorcheck(p2)->bindParameter(1, IFR_HOSTTYPE_DOUBLE, &x2, &x2len, sizeof(double));
        char select_stm[1024];
        sprintf(select_stm, "SELECT V INTO ? FROM  %s  WHERE K=%d", tablename, key);
        tc_errorcheck(p2)->prepare(select_stm, IFR_StringEncodingAscii);
        tc_errorcheck(p2)->execute();
        char error[1024];
        // AS INEXACT AS JAVA
        if(fabs(x2 -x1) > 1.0e-13) {
            sprintf(error, "Value mismatch from inserted value %.38f for host type IFR_HOSTTYPE_DOUBLE, %.38f found.",
                    x1, x2);
            logerror(error);
        }
        connection()->releaseStatement(p1);
        connection()->releaseStatement(p2);
    }

    virtual IFR_Bool run()
    {
        return run38() && run10();
    }

    IFR_Bool run38()
    {

        dropTable("FLOATFLOAT_TEST38");
        m_success = m_success && execSQL("CREATE TABLE FLOATFLOAT_TEST38 (K INT, V FLOAT(38))");

        double test_array[] = { 0.0, 7.0, 1.0, -1.0, 42.7, 3.1, 3.14, 3.141, 3.1415, 3.14159,
                                3.141592, 3.14159265, 91.5, 100.7 };
        for(int i=0; i<sizeof(test_array)/sizeof(double); ++i) {
            checkValue(i+1, test_array[i], "FLOATFLOAT_TEST38");
        }
        execSQL("COMMIT WORK");
        return m_success;
    }

    IFR_Bool run10()
    {
        dropTable("FLOATFLOAT_TEST10");
        m_success = m_success && execSQL("CREATE TABLE FLOATFLOAT_TEST10 (K INT, V FLOAT(10))");

        double test_array[] = { -42.7, 0.0, 7.0, 1.0, -1.0, 42.7, 3.1, 3.14, 3.141, 91.5, -100.7 };
        for(int i=0; i<sizeof(test_array)/sizeof(double); ++i) {
            checkValue(i+1, test_array[i], "FLOATFLOAT_TEST10");
        }
        execSQL("COMMIT WORK");
        return m_success;
    }

};

//----------------------------------------------------------------------
class FloatNANTest
    : public IFR_TestCase
{
public:
    FloatNANTest()
    :IFR_TestCase("FloatNANTest")
    {}

    virtual IFR_Bool run()
    {
        dropTable("FLOATNAN_TEST");
        m_success = m_success && execSQL("CREATE TABLE FLOATNAN_TEST (A FLOAT, B FLOAT)");
        m_success = m_success && execSQL("INSERT INTO FLOATNAN_TEST VALUES (1.0, 0.0)");
        IFR_PreparedStmt *p1=tc_errorcheck(connection())->createPreparedStatement();
        IFR_Length x1len=sizeof(double);
        double x1;
        tc_errorcheck(p1)->bindParameter(1, IFR_HOSTTYPE_DOUBLE, &x1, &x1len, sizeof(double));
        tc_errorcheck(p1)->prepare("SELECT A/B INTO ? FROM FLOATNAN_TEST", IFR_StringEncodingAscii);
        tc_errorcheck(p1)->execute();
        if(!ISNAN(x1)) {
            logerror("Expected NAN output through division by zero in data.");
        }
// disabled, kernel croaks on these values
#if 0
        IFR_PreparedStmt *p2=tc_errorcheck(connection())->createPreparedStatement();
        tc_errorcheck(p2)->prepare("INSERT INTO FLOATNAN_TEST VALUES (?, ?)", IFR_StringEncodingAscii);
        tc_errorcheck(p2)->bindParameter(1, IFR_HOSTTYPE_DOUBLE, &x1, &x1len, sizeof(double));
        tc_errorcheck(p2)->bindParameter(2, IFR_HOSTTYPE_DOUBLE, &x1, &x1len, sizeof(double));
        tc_errorcheck(p2)->execute();
        connection()->releaseStatement(p2);
#endif
        execSQL("COMMIT WORK");
        connection()->releaseStatement(p1);
        return m_success;
    }
};


//----------------------------------------------------------------------
class NumericCharTest
    : public IFR_TestCase
{
public:
    NumericCharTest()
    :IFR_TestCase("NumericCharTest")
    {}

    IFR_Bool run()
    {
        m_success = runFixedInsert();
        m_success = m_success && runFixed();
        m_success = m_success && runFloat();
        return m_success;
    }

    IFR_Bool runFixedInsert()
    {
        dropTable("FIXEDCHAR_INSERTTEST");
        m_success = m_success && execSQL("CREATE TABLE FIXEDCHAR_INSERTTEST (V FIXED(10,3))");
#define CHECK_VALUE(v, vcmp)                                                                                    \
        do {                                                                                                    \
            execSQL("DELETE FROM FIXEDCHAR_INSERTTEST");                                                        \
            char inbuffer[256];                                                                                 \
            IFR_Length inbufferlength=IFR_NTS;                                                                  \
            strcpy(inbuffer, v);                                                                                \
            IFR_PreparedStmt *p0=tc_errorcheck(connection())->createPreparedStatement();                        \
            tc_errorcheck(p0)->bindParameter(1, IFR_HOSTTYPE_ASCII, inbuffer, &inbufferlength, 256);            \
            tc_errorcheck(p0)->prepare("INSERT INTO FIXEDCHAR_INSERTTEST VALUES (?)", IFR_StringEncodingAscii); \
            tc_errorcheck(p0)->execute();                                                                       \
            char outbuffer[256];                                                                                \
            IFR_Length outbufferlen=256;                                                                        \
            IFR_PreparedStmt *p1=tc_errorcheck(connection())->createPreparedStatement();                        \
            tc_errorcheck(p1)->bindParameter(1, IFR_HOSTTYPE_ASCII, outbuffer, &outbufferlen, 256);             \
            tc_errorcheck(p1)->prepare("SELECT V INTO ? FROM FIXEDCHAR_INSERTTEST", IFR_StringEncodingAscii);   \
            tc_errorcheck(p1)->execute();                                                                       \
            m_success = (strcmp(vcmp, outbuffer) == 0);                                                         \
            loginfo("Value expected: |%s| found |%s|", vcmp, outbuffer);                                        \
            connection()->releaseStatement(p0);                                                                 \
            connection()->releaseStatement(p1);                                                                 \
        } while(0)

        CHECK_VALUE("111.111", "111.111");
        CHECK_VALUE("1", "1.000");
        CHECK_VALUE("0", "0");
        CHECK_VALUE("-1", "-1.000");
        CHECK_VALUE("1e3", "1000.000");
        CHECK_VALUE("+0000000000015.00", "15.000");
        CHECK_VALUE(".123", "0.123");
        CHECK_VALUE("0.123", "0.123");
        CHECK_VALUE("1.001", "1.001");
        CHECK_VALUE("0.001", "0.001");
        CHECK_VALUE("+000000.00", "0.000");
#undef CHECK_VALUE
        return m_success;
    }


    IFR_Bool runFixed()
    {
        dropTable("FIXEDCHAR_TEST");
        m_success = m_success && execSQL("CREATE TABLE FIXEDCHAR_TEST (V FIXED(10,3))");

#define CHECK_VALUE( v )                                                                                \
        do {                                                                                            \
            execSQL("DELETE FROM FIXEDCHAR_TEST");                                                      \
            execSQL("INSERT INTO FIXEDCHAR_TEST VALUES (" v ")");                                       \
            char buffer[256];                                                                           \
            IFR_Length bufferlen=256;                                                                   \
            IFR_PreparedStmt *p1=tc_errorcheck(connection())->createPreparedStatement();                \
            tc_errorcheck(p1)->bindParameter(1, IFR_HOSTTYPE_ASCII, buffer, &bufferlen, 256);           \
            tc_errorcheck(p1)->prepare("SELECT V INTO ? FROM FIXEDCHAR_TEST", IFR_StringEncodingAscii); \
            tc_errorcheck(p1)->execute();                                                               \
            m_success = (strcmp(v, buffer) == 0);                                                       \
            /* loginfo("Value expected: |%s| found |%s|", v, buffer); */                                \
           connection()->releaseStatement(p1);                                                          \
        } while(0)

        CHECK_VALUE("11.200");
        CHECK_VALUE("11.201");
        CHECK_VALUE("0");
        CHECK_VALUE("0.001");
        CHECK_VALUE("0.100");
        CHECK_VALUE("100.000");
        CHECK_VALUE("9999999.999");
        CHECK_VALUE("-9999999.999");

        execSQL("COMMIT WORK");
        return m_success;
    }

    IFR_Bool runFloat()
    {
        dropTable("FLOATCHAR_TEST");
        m_success = m_success && execSQL("CREATE TABLE FLOATCHAR_TEST (V FLOAT(20))");

#undef CHECK_VALUE
#define CHECK_VALUE( v )                                                                                \
        do {                                                                                            \
            execSQL("DELETE FROM FLOATCHAR_TEST");                                                      \
            execSQL("INSERT INTO FLOATCHAR_TEST VALUES (" v ")");                                       \
            char buffer[256];                                                                           \
            IFR_Length bufferlen=256;                                                                   \
            IFR_PreparedStmt *p1=tc_errorcheck(connection())->createPreparedStatement();                \
            tc_errorcheck(p1)->bindParameter(1, IFR_HOSTTYPE_ASCII, buffer, &bufferlen, 256);           \
            tc_errorcheck(p1)->prepare("SELECT V INTO ? FROM FLOATCHAR_TEST", IFR_StringEncodingAscii); \
            tc_errorcheck(p1)->execute();                                                               \
            m_success = (strcmp(v, buffer) == 0);                                                       \
            /* loginfo("Value expected: |%s| found |%s|", v, buffer); */                                \
           connection()->releaseStatement(p1);                                                          \
        } while(0)

        CHECK_VALUE("0");
        CHECK_VALUE("0.1");
        CHECK_VALUE("0.11");
        CHECK_VALUE("0.111");
        CHECK_VALUE("1E25");
        CHECK_VALUE("1E-25");
        CHECK_VALUE("1.1E25");
        CHECK_VALUE("1.111E25");
        CHECK_VALUE("1.111E-25");
        CHECK_VALUE("3.14159265");
        CHECK_VALUE("1.111E-62");
        CHECK_VALUE("1.111E62");
        execSQL("COMMIT WORK");
        return m_success;
    }



};

//----------------------------------------------------------------------
class UCS2CharTest : public IFR_TestCase
{
public:
    UCS2CharTest(const char *test = "UCS2CharTest")
    :IFR_TestCase(test)
    {}

    IFR_Bool run()
    {
        m_success=true;
        execSQL("DROP TABLE UCS2_TEST");
        IFR_Retcode rc = statement()->execute("CREATE TABLE UCS2_TEST(K INT PRIMARY KEY, V VARCHAR(200) UNICODE)",
                                              IFR_StringEncodingAscii);
        if(rc != IFR_OK) {
            if(statement()->error().getErrorCode()==-3002) {
                loginfo("Skipping unicode test for non-unicode database.");
                return m_success=true;
            }
            logerror("Error: %d sql state %5s, %s in file %s:%d",
                     statement()->error().getErrorCode(),
                     statement()->error().getSQLState(),
                     statement()->error().getErrorText(),
                     __FILE__,
                     __LINE__);
            return m_success=false;
        }

        IFR_PreparedStmt *ps=tc_errorcheck(connection())->createPreparedStatement();
        IFR_String stm(IFR_StringEncodingUCS2, ps->allocator);
        IFR_Bool memory_ok=true;
        stm.append("INSERT INTO UCS2_TEST VALUES (1, 'TESTDATA')", IFR_StringEncodingAscii, IFR_NTS, memory_ok);
        ps->prepare(stm.getBuffer(), stm.getEncoding());
        tc_errorcheck(ps)->execute();
        connection()->releaseStatement(ps);

        IFR_PreparedStmt *ps2=tc_errorcheck(connection())->createPreparedStatement();
        const char *data_expected = "T\0E\0S\0T\0D\0A\0T\0A\0\0\0";
        char data[18];
        IFR_Length lengthindicator = 0;
        tc_errorcheck(ps2)->prepare("SELECT V INTO ? FROM UCS2_TEST WHERE K=1", IFR_StringEncodingAscii);
        tc_errorcheck(ps2)->bindParameter(1, IFR_HOSTTYPE_UCS2_SWAPPED, data, &lengthindicator, 18);
        tc_errorcheck(ps2)->execute();
        connection()->releaseStatement(ps2);
        if(memcmp(data, data_expected, 18)!=0) {
            logerror("Data differs from expected value.");
        }
        return m_success;
    }

};

//----------------------------------------------------------------------
class SQLNumericTest
    : public IFR_TestCase
{
public:
    SQLNumericTest()
    :IFR_TestCase("SQLNumericTest")
    {}

    IFR_Bool run()
    {
        m_success = runNumericInputTest("FIXED(10,5)", "2A", 0, 1, "42.00000");
        m_success = m_success && runNumericInputTest("FIXED(10,5)", "2A", 0, 0, "-42.00000");
        m_success = m_success && runNumericInputTest("FIXED(10,5)", "2A", 1, 0, "-4.20000");
        m_success = m_success && runNumericInputTest("FIXED(10,5)", "2A", 4, 0, "-0.00420");
        m_success = m_success && runNumericInputTest("FIXED(38,0)", "9210", 0, 1, "4242");
        m_success = m_success && runNumericInputTest("FIXED(38,0)", "B2578702", 0, 1, "42424242");
        m_success = m_success && runNumericInputTest("FIXED(10,5)", "00", 0, 0, "0.00000");
        m_success = m_success && runNumericInputTest("VARCHAR(255)", "2A", 0, 0, "-42");
        m_success = m_success && runNumericInputTest("VARCHAR(255)", "2A", 1, 0, "-4.2");
        m_success = m_success && runNumericInputTest("VARCHAR(255)", "2A", 4, 0, "-0.0042");
        m_success = m_success && runNumericInputTest("VARCHAR(255)", "9210", 0, 1, "4242");
        m_success = m_success && runNumericInputTest("VARCHAR(255)", "B2578702", 0, 1, "42424242");


        // m_success = m_success && runNumericOutputTest("FIXED(38,0)", "B2578702", 0, 1, "42424242");
        return m_success;
    }

    IFR_Bool runNumericInputTest(const char *columntype,
                                 const char *hexstr,
                                 IFR_Int4    scale,
                                 IFR_Int4    sign,
                                 const char *stringrep)
    {
        execSQL("DROP TABLE SQLNUM_TEST");
        char createTableCmd[1024];
        sprintf(createTableCmd, "CREATE TABLE SQLNUM_TEST(V %s)", columntype);

        { tc_errorcheck(statement())->execute(createTableCmd, IFR_StringEncodingAscii); }
        if(m_success==false) { return false; }

        IFR_PreparedStmt *ps=tc_errorcheck(connection())->createPreparedStatement();
        SQL_NUMERIC_STRUCT testvalue;
        initNumeric(testvalue, hexstr, scale, sign);
        IFR_Length numericLength=sizeof(SQL_NUMERIC_STRUCT);
        { tc_errorcheck(ps)->bindParameter(1, IFR_HOSTTYPE_ODBCNUMERIC, &testvalue, &numericLength, numericLength); }
        { tc_errorcheck(ps)->prepare("INSERT INTO SQLNUM_TEST VALUES (?)", IFR_StringEncodingAscii); }
        { tc_errorcheck(ps)->execute(); }
        connection()->commit();
        connection()->releaseStatement(ps);

        IFR_PreparedStmt *psread=tc_errorcheck(connection())->createPreparedStatement();
        char charvalue[1024];
        IFR_Length charvalueind;

        { tc_errorcheck(psread)->bindParameter(1, IFR_HOSTTYPE_ASCII, charvalue, &charvalueind, 1024); }
        { tc_errorcheck(psread)->prepare("SELECT V INTO ? FROM SQLNUM_TEST", IFR_StringEncodingAscii); }
        { tc_errorcheck(psread)->execute(); }

        if(strcmp(charvalue, stringrep) != 0) {
            logerror("Expected value %s, found %s.", stringrep, charvalue);
        }

        connection()->releaseStatement(psread);

        return m_success;
    }

    IFR_Bool runNumericOutputTest(const char *columntype,
                                 const char *hexstr,
                                 IFR_Int4    scale,
                                 IFR_Int4    sign,
                                 const char *stringrep)
    {
        execSQL("DROP TABLE SQLNUM_TEST");
        char createTableCmd[1024];
        sprintf(createTableCmd, "CREATE TABLE SQLNUM_TEST(V %s)", columntype);

        { tc_errorcheck(statement())->execute(createTableCmd, IFR_StringEncodingAscii); }
        if(m_success==false) { return false; }

        IFR_PreparedStmt *ps=tc_errorcheck(connection())->createPreparedStatement();
        { tc_errorcheck(ps)->prepare("INSERT INTO SQLNUM_TEST VALUES (?)", IFR_StringEncodingAscii); }
        IFR_Length stringLength=strlen(stringrep);
        { tc_errorcheck(ps)->bindParameter(1, IFR_HOSTTYPE_ASCII, (void *)stringrep, &stringLength, stringLength); }
        { tc_errorcheck(ps)->execute(); }
        connection()->commit();
        connection()->releaseStatement(ps);
        SQL_NUMERIC_STRUCT testvalue;
        SQL_NUMERIC_STRUCT checkvalue;
        initNumeric(checkvalue, hexstr, scale, sign);
        IFR_Length numericLength=sizeof(SQL_NUMERIC_STRUCT);
        IFR_PreparedStmt *psread=tc_errorcheck(connection())->createPreparedStatement();
        { tc_errorcheck(psread)->prepare("SELECT V INTO ? FROM SQLNUM_TEST", IFR_StringEncodingAscii); }
        { tc_errorcheck(psread)->bindParameter(1, IFR_HOSTTYPE_ODBCNUMERIC, &testvalue, &numericLength, numericLength); }
        { tc_errorcheck(psread)->execute(); }

        if(memcmp(testvalue.val, checkvalue.val, 16) != 0) {
            logerror("Error, mantissa did not match for %s ", stringrep);
        }
        if(testvalue.scale != checkvalue.scale) {
            logerror("Error, scale found is % instead of %d", (IFR_Int4)testvalue.scale, (IFR_Int4)checkvalue.scale);
        }

        connection()->releaseStatement(psread);

        return m_success;
    }



    void initNumeric(SQL_NUMERIC_STRUCT& num,
                     const char *hexstr,
                     IFR_Int4    scale,
                     IFR_Int4    sign)
    {
        memset(&num, 0, sizeof(SQL_NUMERIC_STRUCT));
        num.scale = (IFR_Int1)scale;
        num.sign  = (IFR_UInt1)sign;

        IFR_Int4 l=strlen(hexstr);
        IFR_Int4 valindex=0;
        for(IFR_Int4 i=0; i< MIN(l, 38); ++i) {
            if(i & 1) {
                num.val[valindex] |= getValue(hexstr[i]);
                ++valindex;
            } else {
                num.val[valindex] = getValue(hexstr[i]) << 4;
            }
        }
        return;
    }

    unsigned char getValue(char hexchar)
    {
        if(hexchar >= '0' && hexchar <= '9') {
            return hexchar - '0';
        } else if(hexchar >='A' && hexchar <='F') {
            return 10 + (hexchar - 'A');
        } else if(hexchar >='a' && hexchar <='a') {
            return 10 + (hexchar - 'a');
        } else {
            return 0;
        }
    }

};



//----------------------------------------------------------------------
int main(int argc, char **argv)
{
    // Initalize from command line params
    IFR_TestFrame testframe(argc, argv);
     testframe.addTestCase(new CharAsciiTest());
     testframe.addTestCase(new CharUnicodeTest());
     testframe.addTestCase(new NumericTest());
     testframe.addTestCase(new TimeCharTest());
     testframe.addTestCase(new TimeTimeTest());
     testframe.addTestCase(new DateCharTest());
     testframe.addTestCase(new DateDateTest());
     testframe.addTestCase(new FloatFloatTest());
     testframe.addTestCase(new FloatNANTest());
     testframe.addTestCase(new NumericCharTest());
     testframe.addTestCase(new UCS2CharTest());
     testframe.addTestCase(new SQLNumericTest());
    if(testframe.run()) return 0;
    return 1;
}
