/*!
  @file           IFRConversion_NumericConverter.cpp
  @author         D039759
  @ingroup        IFR_DataConv
  @brief          
  @see            

\if EMIT_LICENCE

    ========== licence begin  GPL
    Copyright (c) 2001-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



\endif
*/
#include "Interfaces/Runtime/IFR_Common.h"
#include "Interfaces/Runtime/Conversion/IFRConversion_NumericConverter.h"
#include "Interfaces/Runtime/Util/IFRUtil_VDNNumber.h"
#include "Interfaces/Runtime/Util/IFRUtil_SQLNumeric.h"
#include "Interfaces/Runtime/IFR_Connection.h"

#include <math.h>
#include <stdlib.h>

#ifdef OSF1
#ifndef _IEEE
#  ifndef _IEEE_FP
#    error This will only work with IEEE floating point arithmetic.
#  else
#    define _IEEE 1
#  endif
#endif
#include <nan.h>
#endif

#define DBUG_CLINK_METHOD_ENTER(x,y) DBUG_CONTEXT_METHOD_ENTER(x, y, &clink)


//----------------------------------------------------------------------
static IFR_size_t string_nlen(char *s, IFR_size_t max)
{
    for(IFR_size_t i=0; i<max; ++i) {
        if(*(s+i) == 0) {
            return i;
        }
    }
    return max;
}

//----------------------------------------------------------------------
static inline IFR_size_t compute_input_datalength(IFR_size_t datalength,
                                                  IFR_Length *lengthindicator,
                                                  char      *data,
                                                  IFR_ConnectionItem& clink,
                                                  IFR_Int4            index,
                                                  IFR_Bool&           error)
{
    error=false;
    if(lengthindicator) {
        if(*lengthindicator==IFR_NTS) {
            if(datalength != 0) {
                return string_nlen(data, datalength);
            } else {
                return strlen(data);
            }
        } else if(*lengthindicator < 0) {
            clink.error().setRuntimeError(IFR_ERR_INVALID_LENGTHINDICATOR_I, index);
            error=true;
            return 0;
        } else if (*lengthindicator >= 0) {
            if(datalength != 0) {
                return  (IFR_Length) datalength < *lengthindicator ? datalength : *lengthindicator;
            } else {
                return *lengthindicator;
            }
        } 
    } 
    if(datalength != 0) {
        return string_nlen(data, datalength);
    } else {
        return strlen(data);
    }
}



//----------------------------------------------------------------------
IFRConversion_NumericConverter::IFRConversion_NumericConverter(IFR_ShortInfo &shortinfo,
                                                               SAPDBMem_IRawAllocator& allocator,
                                                               IFR_Connection& connection)
:IFRConversion_Converter(shortinfo, allocator)
{
    m_noscientific = connection.numbersWithoutExponent();
}

//----------------------------------------------------------------------
IFRConversion_NumericConverter::~IFRConversion_NumericConverter()
{}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateAsciiInput(IFRPacket_DataPart& datapart,
                                                    char               *data,
                                                    IFR_Length            datalength,
                                                    IFR_Length*           lengthindicator,
                                                    IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateAsciiInput);
    IFR_Bool    error;
    IFR_size_t  used_datalength=compute_input_datalength(datalength,
                                                         lengthindicator,
                                                         data,
                                                         clink,
                                                         getIndex(),
                                                         error);
    if(error) {
        DBUG_RETURN(IFR_NOT_OK);
    }

    unsigned char *num=(unsigned char*)datapart.getInputData(m_shortinfo);
    IFR_Bool nan = false;
    IFR_Retcode rc=IFRUtil_VDNNumber::stringToNumber(data,
                                                     used_datalength,
                                                     IFR_StringEncodingAscii,
                                                     nan,
                                                     num,
                                                     !m_shortinfo.isFloat(),
                                                     m_shortinfo.length,
                                                     m_shortinfo.frac);
    if(rc==IFR_OK) {
        datapart.finishData(m_shortinfo.iolength, m_shortinfo);
    } else if(rc==IFR_OVERFLOW) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
    } else if(rc==IFR_NOT_OK) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
    } else if(nan) {
        rc=IFR_NOT_OK;
        clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
    }
    DBUG_RETURN(rc);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateUCS2Input(IFRPacket_DataPart& datapart,
                                                   char               *data,
                                                   IFR_Bool            swapped,
                                                   IFR_Length          datalength,
                                                   IFR_Length*         lengthindicator,
                                                   IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateUCS2Input);
    IFR_Bool    error;
    IFR_size_t  used_datalength=compute_input_datalength(datalength,
                                                         lengthindicator,
                                                         data,
                                                         clink,
                                                         getIndex(),
                                                         error);
    if(error) {
        DBUG_RETURN(IFR_NOT_OK);
    }

    unsigned char *num=(unsigned char*)datapart.getInputData(m_shortinfo);
    IFR_Bool nan = false;
    IFR_Retcode rc=IFRUtil_VDNNumber::stringToNumber(data,
                                                     used_datalength,
                                                     swapped?IFR_StringEncodingUCS2Swapped:IFR_StringEncodingUCS2,
                                                     nan,
                                                     num,
                                                     !m_shortinfo.isFloat(),
                                                     m_shortinfo.length,
                                                     m_shortinfo.frac);
    if(rc==IFR_OK) {
        datapart.finishData(m_shortinfo.iolength, m_shortinfo);
    } else if(rc==IFR_OVERFLOW) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
    } else if(rc==IFR_NOT_OK) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
    } else if(nan) {
        rc=IFR_NOT_OK;
        clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
    }
    DBUG_RETURN(rc);

}


//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateUTF8Input(IFRPacket_DataPart& datapart,
                                                   char               *data,
                                                   IFR_Length            datalength,
                                                   IFR_Length*           lengthindicator,
                                                   IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateUTF8Input);
    DBUG_RETURN(translateAsciiInput(datapart, data, datalength, lengthindicator, clink));
}




//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateInput(IFRPacket_DataPart& datapart,
                                               double& data,
                                               IFR_Length *lengthindicator,
                                               IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateInput_double);
    unsigned char num[20];
    IFR_Retcode conversion_rc;
    if(ISNAN(data)) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    } 
    conversion_rc=IFRUtil_VDNNumber::doubleToNumber(data,
                                                    num, 
                                                    m_shortinfo.length, 
                                                    m_shortinfo.isFloat()?-1:m_shortinfo.frac);
    if(conversion_rc == IFR_OVERFLOW) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
    } else if(conversion_rc==IFR_OK || conversion_rc==IFR_DATA_TRUNC) {
        datapart.addBinaryParameter(num, m_shortinfo.iolength-1, m_shortinfo);
    }
    DBUG_RETURN(conversion_rc);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateInput(IFRPacket_DataPart& datapart,
                                               float& data,
                                               IFR_Length *lengthindicator,
                                               IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateInput_float);
    double d=data;
    DBUG_RETURN(translateInput(datapart, d, lengthindicator, clink));
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateInput(IFRPacket_DataPart& part,
                                               IFR_Int1& data,
                                               IFR_Length* lengthindicator,
                                               IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateInput_Int1);
    unsigned char *num=(unsigned char*)part.getInputData(m_shortinfo);
    IFR_Retcode rc=IFRUtil_VDNNumber::int1ToNumber(data, num, m_shortinfo.length-m_shortinfo.frac);
    if(rc==IFR_OK) {
        part.finishData(m_shortinfo.iolength, m_shortinfo);
    } else if(rc==IFR_OVERFLOW) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
    } else if(rc==IFR_NOT_OK) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
    }
    DBUG_RETURN(rc);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateInput(IFRPacket_DataPart& part,
                                               IFR_Int2& data,
                                               IFR_Length* lengthindicator,
                                               IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateInput_Int2);
    unsigned char *num=(unsigned char*)part.getInputData(m_shortinfo);
    IFR_Retcode rc=IFRUtil_VDNNumber::int2ToNumber(data, num, m_shortinfo.length-m_shortinfo.frac);
    if(rc==IFR_OK) {
        part.finishData(m_shortinfo.iolength, m_shortinfo);
    } else if(rc==IFR_OVERFLOW) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
    } else if(rc==IFR_NOT_OK) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
    }
    DBUG_RETURN(rc);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateInput(IFRPacket_DataPart& part,
                                               IFR_Int4& data,
                                               IFR_Length* lengthindicator,
                                               IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateInput_Int4);
    DBUG_PRINT(data);
    unsigned char *num=(unsigned char*)part.getInputData(m_shortinfo);
    IFR_Retcode rc=IFRUtil_VDNNumber::int4ToNumber(data, num, m_shortinfo.length-m_shortinfo.frac);
    if(rc==IFR_OK) {
        part.finishData(m_shortinfo.iolength, m_shortinfo);
    } else if(rc==IFR_OVERFLOW) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
    } else if(rc==IFR_NOT_OK) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
    }
    DBUG_RETURN(rc);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateInput(IFRPacket_DataPart& part,
                                               IFR_Int8 &data,
                                               IFR_Length* lengthindicator,
                                               IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateInput_Int8);
    unsigned char *num=(unsigned char*)part.getInputData(m_shortinfo);
    IFR_Retcode rc=IFRUtil_VDNNumber::int8ToNumber(data, num, m_shortinfo.length-m_shortinfo.frac);
    if(rc==IFR_OK) {
        part.finishData(m_shortinfo.iolength, m_shortinfo);
    } else if(rc==IFR_OVERFLOW) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
    } else if(rc==IFR_NOT_OK) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
    }
    DBUG_RETURN(rc);
}


//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateInput(IFRPacket_DataPart& part,
                                               IFR_UInt1& data,
                                               IFR_Length* lengthindicator,
                                               IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateInput_UInt1);
    unsigned char *num=(unsigned char*)part.getInputData(m_shortinfo);
    IFR_Retcode rc=IFRUtil_VDNNumber::uint1ToNumber(data, num, m_shortinfo.length-m_shortinfo.frac);
    if(rc==IFR_OK) {
        part.finishData(m_shortinfo.iolength, m_shortinfo);
    } else if(rc==IFR_OVERFLOW) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
    } else if(rc==IFR_NOT_OK) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
    }
    DBUG_RETURN(rc);
}
//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateInput(IFRPacket_DataPart& part,
                                               IFR_UInt2& data,
                                               IFR_Length* lengthindicator,
                                               IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateInput_UInt2);
    unsigned char *num=(unsigned char*)part.getInputData(m_shortinfo);
    IFR_Retcode rc=IFRUtil_VDNNumber::uint2ToNumber(data, num, m_shortinfo.length-m_shortinfo.frac);
    if(rc==IFR_OK) {
        part.finishData(m_shortinfo.iolength, m_shortinfo);
    } else if(rc==IFR_OVERFLOW) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
    } else if(rc==IFR_NOT_OK) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
    }
    DBUG_RETURN(rc);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateInput(IFRPacket_DataPart& part,
                                               IFR_UInt4& data,
                                               IFR_Length* lengthindicator,
                                               IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateInput_UInt4);
    unsigned char *num=(unsigned char*)part.getInputData(m_shortinfo);
    IFR_Retcode rc=IFRUtil_VDNNumber::uint4ToNumber(data, num, m_shortinfo.length-m_shortinfo.frac);
    if(rc==IFR_OK) {
        part.finishData(m_shortinfo.iolength, m_shortinfo);
    } else if(rc==IFR_OVERFLOW) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
    } else if(rc==IFR_NOT_OK) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
    }
    DBUG_RETURN(rc);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateInput(IFRPacket_DataPart& part,
                                               IFR_UInt8 &data,
                                               IFR_Length* lengthindicator,
                                               IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateInput_UInt8);
    unsigned char *num=(unsigned char*)part.getInputData(m_shortinfo);
    IFR_Retcode rc=IFRUtil_VDNNumber::uint8ToNumber(data, num, m_shortinfo.length-m_shortinfo.frac);
    if(rc==IFR_OK) {
        part.finishData(m_shortinfo.iolength, m_shortinfo);
    } else if(rc==IFR_OVERFLOW) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
    } else if(rc==IFR_NOT_OK) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
    }
    DBUG_RETURN(rc);
}


//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateOutput(IFRPacket_DataPart& datapart,
                                                IFR_Int1& data,
                                                IFR_Length *lengthindicator,
                                                IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateOutput_Int1);
    unsigned char *vdn=(unsigned char *)datapart.getOutputData(m_shortinfo.pos.bufpos);        
    IFR_Retcode rc=IFRUtil_VDNNumber::numberToInt1(vdn, data, m_shortinfo.iolength);
    if(rc == IFR_NOT_OK) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
    }
    if(rc==IFR_OVERFLOW) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
    }
    if(lengthindicator) 
        *lengthindicator=sizeof(data);
    DBUG_PRINT(data);
    DBUG_RETURN(rc);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateOutput(IFRPacket_DataPart& datapart,
                                                IFR_Int2& data,
                                                IFR_Length *lengthindicator,
                                                IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateOutput_Int2);
    unsigned char *vdn=(unsigned char *)datapart.getOutputData(m_shortinfo.pos.bufpos);        
    IFR_Retcode rc=IFRUtil_VDNNumber::numberToInt2(vdn, data, m_shortinfo.iolength);
    if(rc == IFR_NOT_OK) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
    }
    if(rc==IFR_OVERFLOW) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
    }
    if(lengthindicator) 
        *lengthindicator=sizeof(data);
    DBUG_PRINT(data);
    DBUG_RETURN(rc);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateOutput(IFRPacket_DataPart& datapart,
                                                IFR_Int4& data,
                                                IFR_Length *lengthindicator,
                                                IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateOutput_Int4);
    unsigned char *vdn=(unsigned char *)datapart.getOutputData(m_shortinfo.pos.bufpos);        
    IFR_Retcode rc=IFRUtil_VDNNumber::numberToInt4(vdn, data, m_shortinfo.iolength);
    if(rc == IFR_NOT_OK) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
    }
    if(rc==IFR_OVERFLOW) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
    }
    if(lengthindicator) 
        *lengthindicator=sizeof(data);
    DBUG_PRINT(data);
    DBUG_RETURN(rc);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateOutput(IFRPacket_DataPart& datapart,
                                                IFR_Int8& data,
                                                IFR_Length *lengthindicator,
                                                IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateOutput_Int8);
    unsigned char *vdn=(unsigned char *)datapart.getOutputData(m_shortinfo.pos.bufpos);        
    IFR_Retcode rc=IFRUtil_VDNNumber::numberToInt8(vdn, data, m_shortinfo.iolength);
    if(rc == IFR_NOT_OK) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
    }
    if(rc==IFR_OVERFLOW) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
    }
    if(lengthindicator) 
        *lengthindicator=sizeof(data);
    DBUG_PRINT(data);
    DBUG_RETURN(rc);
}


//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateOutput(IFRPacket_DataPart& datapart,
                                                IFR_UInt1& data,
                                                IFR_Length *lengthindicator,
                                                IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateOutput_UInt1);
    unsigned char *vdn=(unsigned char *)datapart.getOutputData(m_shortinfo.pos.bufpos);        
    IFR_Retcode rc=IFRUtil_VDNNumber::numberToUInt1(vdn, data, m_shortinfo.iolength);
    if(rc == IFR_NOT_OK) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
    }
    if(rc==IFR_OVERFLOW) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
    }
    if(lengthindicator) 
        *lengthindicator=sizeof(data);
    DBUG_PRINT(data);
    DBUG_RETURN(rc);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateOutput(IFRPacket_DataPart& datapart,
                                                IFR_UInt2& data,
                                                IFR_Length *lengthindicator,
                                                IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateOutput_UInt2);
    unsigned char *vdn=(unsigned char *)datapart.getOutputData(m_shortinfo.pos.bufpos);        
    IFR_Retcode rc=IFRUtil_VDNNumber::numberToUInt2(vdn, data, m_shortinfo.iolength);
    if(rc == IFR_NOT_OK) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
    }
    if(rc==IFR_OVERFLOW) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
    }
    if(lengthindicator) 
        *lengthindicator=sizeof(data);
    DBUG_PRINT(data);
    DBUG_RETURN(rc);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateOutput(IFRPacket_DataPart& datapart,
                                                IFR_UInt4& data,
                                                IFR_Length *lengthindicator,
                                                IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateOutput_UInt4);
    unsigned char *vdn=(unsigned char *)datapart.getOutputData(m_shortinfo.pos.bufpos);        
    IFR_Retcode rc=IFRUtil_VDNNumber::numberToUInt4(vdn, data, m_shortinfo.iolength);
    if(rc == IFR_NOT_OK) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
    }
    if(rc==IFR_OVERFLOW) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
    }
    if(lengthindicator) 
        *lengthindicator=sizeof(data);
    DBUG_PRINT(data);
    DBUG_RETURN(rc);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateOutput(IFRPacket_DataPart& datapart,
                                                IFR_UInt8& data,
                                                IFR_Length *lengthindicator,
                                                IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateOutput_UInt8);
    unsigned char *vdn=(unsigned char *)datapart.getOutputData(m_shortinfo.pos.bufpos);        
    IFR_Retcode rc=IFRUtil_VDNNumber::numberToUInt8(vdn, data, m_shortinfo.iolength);
    if(rc == IFR_NOT_OK) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
    }
    if(rc==IFR_OVERFLOW) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
    }
    if(lengthindicator) 
        *lengthindicator=sizeof(data);
    DBUG_PRINT(data);
    DBUG_RETURN(rc);
}


//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateOutput(IFRPacket_DataPart& datapart,
                                                double& data,
                                                IFR_Length *lengthindicator,
                                                IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateOutput_double);
    unsigned char *vdn=(unsigned char *)datapart.getOutputData(m_shortinfo.pos.bufpos);        
    // Check whether there was a division by zero or similar harmful stuff
    if(*(vdn - 1) == csp_oflw_byte) {
#if defined(WIN32)
        data=sqrt(-1.0); errno=0;
#elif defined(OSF1)
        // There is no way to create a NaN by a function on the DEC.
        // So it must be done manually.
        memset(&data, 0, 8);
        dnan *np = (dnan *)&data;
        np->nan_parts.exponent     = 0x7FF;
        np->nan_parts.bits         = 1;
        np->nan_parts.fraction_low = 1;
#else
        data=strtod("nan", NULL);
#endif
        DBUG_RETURN(IFR_OK);
    }
    IFR_Retcode rc=IFRUtil_VDNNumber::numberToDouble(vdn, data, m_shortinfo.length);
    if(rc == IFR_NOT_OK) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
    }
    if(rc==IFR_OVERFLOW) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
    }
    if(lengthindicator) 
        *lengthindicator=sizeof(data);
    DBUG_RETURN(rc);
}

//----------------------------------------------------------------------
IFR_Retcode 
IFRConversion_NumericConverter::translateOutput(IFRPacket_DataPart&   datapart,
                                                float&      data,
                                                IFR_Length*             lengthindicator,
                                                IFR_ConnectionItem&   clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateOutput_float);
    double d;
    IFR_Retcode rc=translateOutput(datapart, d, lengthindicator, clink);
    if(rc == IFR_OK) {
        // NAN is different for float
        if(ISNAN(d)) {
            data = (float)d;
            DBUG_RETURN(IFR_OK);
        }
        // check the MAX_FLOAT limit
        if(d > 3.4028235e+38) {
            clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
            DBUG_RETURN(IFR_NOT_OK);
        }
        data = (float)d; // the resulting precision loss is accepted here,
        // and inevitable. 
        if(lengthindicator) {
            *lengthindicator=sizeof(float);
        }
    }
    DBUG_RETURN(rc);
}

//----------------------------------------------------------------------
inline IFR_size_t ucsx_bytelen(char *c)
{
    IFR_size_t result=0;
    while(*c || *(c+1)) {
        c+=2;
        result+=2;
    }
    return result;
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateCharacterOutput(IFRPacket_DataPart& datapart,
                                                         char           *data,
                                                         IFR_Length        datalength,
                                                         IFR_Length*       lengthindicator,
                                                         IFR_ConnectionItem &clink,
                                                         IFR_StringEncoding encoding,
                                                         IFR_Bool terminate)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateAsciiOutput);
    unsigned char *vdn=(unsigned char *)datapart.getOutputData(m_shortinfo.pos.bufpos);        

    // unfortunately, we must possibly report the original length to the
    // caller. So for now we will copy the result anyway ...
    char tmp_data[140]; // 64 digits (E64), '.' and '-', if no scientific ... makes 132 (plus some safety)
    const char *numstr; 
    IFR_size_t numlength;
    if(*(vdn - 1) == csp_oflw_byte) {
        if(encoding == IFR_StringEncodingAscii || encoding==IFR_StringEncodingUTF8) {
            numstr="NaN";
            numlength=3;
        } else if (encoding == IFR_StringEncodingUCS2) {
            numstr="\0N\0a\0N\0";
            numlength=6;
        } else if (encoding == IFR_StringEncodingUCS2Swapped) {
            numstr="N\0a\0N\0\0";
            numlength=6;
        }
    } else {
        IFR_Retcode rc=
            IFRUtil_VDNNumber::numberToString(vdn, 
                                              tmp_data,
                                              sizeof(tmp_data),
                                              encoding,
                                              m_noscientific || !m_shortinfo.isFloat(),
                                              m_shortinfo.length,
                                              m_shortinfo.frac);
        
        if(rc!=IFR_OK) {
            DBUG_RETURN(IFR_NOT_OK);
        }
        numstr=tmp_data;
        if(encoding == IFR_StringEncodingAscii || encoding == IFR_StringEncodingUTF8) {
            numlength=strlen(tmp_data);
        } else {
            numlength = ucsx_bytelen(tmp_data);
        }
    }
    IFR_Length terminatorSize=IFR_ENCODING(encoding)->terminatorSize;
    IFR_size_t copylength = (numlength < (IFR_size_t)datalength - ((terminate) ? terminatorSize : 0)) 
      ? numlength + ((terminate) ? terminatorSize : 0) 
      : datalength;

    memcpy(data, numstr, copylength);
    if(lengthindicator) {
        *lengthindicator=(IFR_Length)numlength;
    }
    
    if(numlength > (IFR_size_t)(datalength - ((terminate) ? terminatorSize : 0))) {
        DBUG_RETURN(IFR_DATA_TRUNC);
    } else {
        DBUG_RETURN(IFR_OK);
    }
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateUTF8Output(IFRPacket_DataPart& datapart,
                                                    char           *data,
                                                    IFR_Length        datalength,
                                                    IFR_Length*       lengthindicator,
                                                    IFR_Bool       terminate,
                                                    IFR_ConnectionItem &clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateUTF8Output);
    DBUG_RETURN(translateCharacterOutput(datapart, data, datalength, lengthindicator, clink, IFR_StringEncodingUTF8, terminate));
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateAsciiOutput(IFRPacket_DataPart& datapart,
                                                     char           *data,
                                                     IFR_Length        datalength,
                                                     IFR_Length*       lengthindicator,
                                                     IFR_Bool       terminate,
                                                     IFR_ConnectionItem &clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateAsciiOutput);
    DBUG_RETURN(translateCharacterOutput(datapart, data, datalength, lengthindicator, clink, IFR_StringEncodingAscii, terminate));
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateUCS2Output(IFRPacket_DataPart& datapart,
                                                    char           *data,
                                                    IFR_Bool        swapped,
                                                    IFR_Length        datalength,
                                                    IFR_Length*       lengthindicator,
                                                    IFR_Bool       terminate,
                                                    IFR_ConnectionItem &clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateUCS2Output);
    IFR_StringEncoding encoding = (swapped) ? IFR_StringEncodingUCS2Swapped : IFR_StringEncodingUCS2;
    DBUG_RETURN(translateCharacterOutput(datapart, data, datalength, lengthindicator, clink, encoding, terminate));
}

//----------------------------------------------------------------------
IFR_Retcode 
IFRConversion_NumericConverter::translateInput(IFRPacket_DataPart&   datapart,
                           SQL_NUMERIC_STRUCT&      data,
                           IFR_Length*             lengthindicator,
                           IFR_ConnectionItem&   clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateInput_NUMERIC);
    unsigned char *num=(unsigned char*)datapart.getInputData(m_shortinfo);
    IFR_Retcode rc=IFRUtil_SQLNumeric::numericToNumber(data, num, m_shortinfo.length);
    if(rc==IFR_OK) {
        datapart.finishData(m_shortinfo.iolength, m_shortinfo);
    } else if(rc==IFR_OVERFLOW) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
    } else if(rc==IFR_NOT_OK) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
    }
    DBUG_RETURN(rc);
}


//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_NumericConverter::translateOutput(IFRPacket_DataPart&   datapart,
                                               SQL_NUMERIC_STRUCT&    data,
                                               IFR_Length*            lengthindicator,
                                               IFR_ConnectionItem&    clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateOutput_NUMERIC);
    unsigned char *vdn=(unsigned char *)datapart.getOutputData(m_shortinfo.pos.bufpos);
    if(lengthindicator) {
        *lengthindicator=sizeof(SQL_NUMERIC_STRUCT);
    }
    IFR_Retcode rc=IFRUtil_SQLNumeric::numberToNumeric(vdn, 
                                                       m_shortinfo.length,
                                                       data,
                                                       m_shortinfo.frac);
    DBUG_RETURN(rc);
}


//----------------------------------------------------------------------
#ifdef IFR_NEED_VIRTUAL_DELEGATION
IFR_Retcode 
IFRConversion_NumericConverter::translateInput(IFRPacket_DataPart&   datapart,
                                               SQL_DATE_STRUCT&      data,
                                               IFR_Length*             lengthindicator,
                                               IFR_ConnectionItem&   clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateInput_DATE);
    DBUG_RETURN(IFRConversion_Converter::translateInput(datapart, data, lengthindicator, clink));
}

IFR_Retcode 
IFRConversion_NumericConverter::translateInput(IFRPacket_DataPart&   datapart,
                           SQL_TIME_STRUCT&      data,
                           IFR_Length*             lengthindicator,
                           IFR_ConnectionItem&   clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateInput_TIME);
    DBUG_RETURN(IFRConversion_Converter::translateInput(datapart, data, lengthindicator, clink));
}

IFR_Retcode 
IFRConversion_NumericConverter::translateInput(IFRPacket_DataPart&   datapart,
                           SQL_TIMESTAMP_STRUCT&      data,
                           IFR_Length*             lengthindicator,
                           IFR_ConnectionItem&   clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateInput_TIMESTAMP);
    DBUG_RETURN(IFRConversion_Converter::translateInput(datapart, data, lengthindicator, clink));
}


IFR_Retcode 
IFRConversion_NumericConverter::translateInput(IFRPacket_DataPart&   datapart,
                           GUID&                data,
                           IFR_Length*            lengthindicator,
                           IFR_ConnectionItem&  clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateInput_GUID);
    DBUG_RETURN(IFRConversion_Converter::translateInput(datapart, data, lengthindicator, clink));
}

IFR_Retcode
IFRConversion_NumericConverter::translateOutput(IFRPacket_DataPart&   datapart,
                                               SQL_DATE_STRUCT&      data,
                                               IFR_Length*             lengthindicator,
                                               IFR_ConnectionItem&   clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateOutput_DATE);
    DBUG_RETURN(IFRConversion_Converter::translateOutput(datapart, data, lengthindicator, clink));
}

IFR_Retcode
IFRConversion_NumericConverter::translateOutput(IFRPacket_DataPart&   datapart,
                                               SQL_TIME_STRUCT&      data,
                                               IFR_Length*             lengthindicator,
                                               IFR_ConnectionItem&   clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateOutput_TIME);
    DBUG_RETURN(IFRConversion_Converter::translateOutput(datapart, data, lengthindicator, clink));
}

IFR_Retcode
IFRConversion_NumericConverter::translateOutput(IFRPacket_DataPart&   datapart,
                                               SQL_TIMESTAMP_STRUCT&      data,
                                               IFR_Length*             lengthindicator,
                                               IFR_ConnectionItem&   clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateOutput_TIMESTAMP);
    DBUG_RETURN(IFRConversion_Converter::translateOutput(datapart, data, lengthindicator, clink));
}


IFR_Retcode
IFRConversion_NumericConverter::translateOutput(IFRPacket_DataPart&   datapart,
                                               GUID&      data,
                                               IFR_Length*             lengthindicator,
                                               IFR_ConnectionItem&   clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_NumericConverter, translateOutput_GUID);
    DBUG_RETURN(IFRConversion_Converter::translateOutput(datapart, data, lengthindicator, clink));
}

#endif


