blob: 649774c1dc16e0dabd3fd562f14d4fb5440fa3e7 [file] [log] [blame]
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
********************************************************************/
/**************************************************************************
**************************************************************************/
//
// MODULE: NSKIEEE.cpp
//
// Purpose: Routines to convert between t16 float and ieee float.
//
//64-bit float format :
// +--------------------------------------------------+
// |s| mantissa | exp |
// +--------------------------------------------------+
// 1 54 9
//
//32-bit float format :
// +--------------------------------------+
// |s| mantissa | exp |
// +--------------------------------------+
// 1 22 9
//
// IEEE 64-bit float format :
// +--------------------------------------------------+
// |s| exp | mantissa |
// +--------------------------------------------------+
// 1 11 52
//
//IEEE 32-bit float format :
// +--------------------------------------+
// |s| exp | mantissa |
// +--------------------------------------+
// 1 8 23
//
//float exponent is expressed as an excessed-256 value
// (biased by 256).
// The exponent range is between -256 to +255.
//
// IEEE float exponent is also biased. The exponent bias is 1023
// for double (64 bits) format and 127 for single (32 bits) format.
//
//-----------------------------------------------------------------
#include <windows.h>
#include <sqltypes.h>
#include "sqlcli.h"
#include "NSKIEEE.h"
#include "DrvrSrvr.h"
#ifdef NSK_PLATFORM
#include "kfpconv.h"
#endif
#define IEEE_EXPONENT_BIAS 1023
#define T16_EXPONENT_BIAS 256
#define BIAS_DIFFERENCE 767 // 1023 - 256 = 767
#define IEEE_EXPONENT_BIAS_S 127 // single format
#define BIAS_DIFFERENCE_S -129 // 127 - 256 = -129
//----------------------------------------------------------------
// If the source length is not an even number, no swapping will
// be performed. No error is generated in this function.
// IN/OUT : source/target, IN : swap length
//----------------------------------------------------------------
void ODBC::byte_swap(BYTE *source, long source_len)
{
#ifndef NSK_PLATFORM
BYTE *target;
BYTE temp;
short i;
if (!(source_len % 2))
{
for (i = 1, target = source; i <= source_len /2; i++)
{
temp = source[i-1];
target[i-1] = source[source_len - i];
source[source_len -i] = temp;
}
}
#endif
} // byte_swap
// The following byte order inversion routines were written by Dale Rempert. They are
// specific to the 80x86 processors. Even though the external representation is little endian
// the internal representation is big endian. Here is how these routines work. Take a short
// in big endian say 0xCDAB. When read by the processor it "sees" the value 0xABCD. We rotate
// this value by 8 bits yealding 0xCDAB. Then written out to memory we get 0xABCD. For 4 & 8
// byte values I read two byes at a time and build one or two 4 byte "longs" then write out the
// longs. This minimizes the reads/writes to slower memory, and if the compiler is nice will
// keep the temps in registers. Though some compilers will not do this if a routine contains
// inline assembly statements.
// Note the only reasonable sizes for endian inversion are 2, 4, and 8 bytes.
// byte_swap a 16 bit field (i.e. 2 bytes)
void ODBC::byte_swap_2(BYTE *source)
{
#ifndef NSK_PLATFORM
unsigned short tmp;
tmp = *(unsigned short *)source;
_asm rol tmp,8
*(unsigned short *)source = tmp;
#endif
}
// byte_swap a 32 bit field (i.e. 4 bytes)
void ODBC::byte_swap_4(BYTE *source)
{
#ifndef NSK_PLATFORM
unsigned long t32;
unsigned short t16;
t16 = *(unsigned short *)source;
_asm rol t16,8
t32 = ((unsigned long)t16) << 16;
t16 = *(short *)(source+2);
_asm rol t16,8
t32 |= (unsigned long)t16;
*(unsigned long *)source = t32;
#endif
}
// byte_swap a 64 bit field (i.e. 8 bytes)
// 0x1122334455667788 => 0x8877665544332211
void ODBC::byte_swap_8(BYTE *source)
{
#ifndef NSK_PLATFORM
unsigned long t32a, t32b;
unsigned short t16;
t16 = *(unsigned short *)source; // 0x2211
_asm rol t16,8 // 0x1122
t32a = ((unsigned long)t16) << 16; // 0x11220000
t16 = *(unsigned short *)(source+2); // 0x4433
_asm rol t16,8 // 0x3344
t32a |= (unsigned long)t16; // 0x11223344
t16 = *(unsigned short *)(source+4); // 0x6655
_asm rol t16,8 // 0x5566
t32b = ((unsigned long)t16) << 16; // 0x55660000
t16 = *(unsigned short *)(source+6); // 0x8877
_asm rol t16,8 // 0x7788
t32b |= (unsigned long)t16; // 0x55667788
*(unsigned long *)source = t32b; // 0x88776655
*(unsigned long *)(source+4) = t32a; // 0x44332211
#endif
}
// byte swap a string of chars in unicode UCS2 or any other chars in
// fixed two byte representation.
void ODBC::byte_swap_string(BYTE *source, long source_len)
{
#ifndef NSK_PLATFORM
unsigned short *target;
int i;
unsigned short tmp;
target = (unsigned short *)source;
for (i = source_len /2; i > 0; i--)
{
tmp = *target;
_asm rol tmp,8
*target++ = tmp;
}
#endif
} // byte_swap_string
//--------------------------------------------------------------------
// Convert T16 64-bit float to IEEE float.
// IN : T16 floating number, OUT: IEEE float
// For alignment reason, this is not declared as long long *.
//--------------------------------------------------------------------
short ODBC::conv_float64_to_ieee_d (BYTE *op)
{
unsigned int exp; // exponent
BYTE rop[8];
BYTE *exp1;
BYTE *exp2;
// Get exponent and sign.
exp = ((op[6] & 0x01) << 8) | op[7];
if (exp == 0)
return (STATUS_OK);
exp = exp + BIAS_DIFFERENCE; //1023 - 256
exp1 = (BYTE *)&exp;
exp2 = exp1 + 1;
rop[0] = (BYTE)((op[0] & 0x80) | (*exp2 << 4) | (*exp1 >> 4));
rop[1] = (BYTE)((*exp1 << 4) | ((op[0] & 0x7F) >> 3)); // RS has to remove the sign
rop[2] = (BYTE)((op[0] << 5) | (op[1] >> 3));
rop[3] = (BYTE)((op[1] << 5) | (op[2] >> 3));
rop[4] = (BYTE)((op[2] << 5) | (op[3] >> 3));
rop[5] = (BYTE)((op[3] << 5) | (op[4] >> 3));
rop[6] = (BYTE)((op[4] << 5) | (op[5] >> 3));
rop[7] = (BYTE)((op[5] << 5) | (op[6] >> 3));
byte_swap(rop, 8);
memcpy(op, rop, 8);
return (STATUS_OK);
} // conv_float64_to_ieee_d
//--------------------------------------------------------------------
// Convert IEEE float to T16 64-bit float.
//--------------------------------------------------------------------
short ODBC::conv_ieee_d_to_float64 (BYTE *op)
{
unsigned int exp; // exponent
BYTE rop[8];
BYTE *exp1;
BYTE *exp2;
byte_swap(op, 8);
// Get exponent and sign.
exp = (((op[0] & 0x7F) << 8 ) | (op[1] & 0xF0)) >> 4;
if (exp == 0)
return (STATUS_OK);
if ((int)exp < (1023 - 256))
return( STATUS_UNDERFLOW);
if ((int)exp > (1023 + 255))
return ( STATUS_OVERFLOW);
exp = exp - BIAS_DIFFERENCE; //1023 - 256
exp1 = (BYTE *)&exp;
exp2 = exp1 + 1;
rop[0] = (BYTE)((op[0] & 0x80) | ((op[1] & 0x0F) << 3) | ((op[2] & 0xE0) >> 5));
rop[1] = (BYTE)((op[2] << 3) | (op[3] >> 5));
rop[2] = (BYTE)((op[3] << 3) | (op[4] >> 5));
rop[3] = (BYTE)((op[4] << 3) | (op[5] >> 5));
rop[4] = (BYTE)((op[5] << 3) | (op[6] >> 5));
rop[5] = (BYTE)((op[6] << 3) | (op[7] >> 5));
rop[6] = (BYTE)((op[7] << 3) | (*exp2));
rop[7] = (BYTE)(*exp1);
memcpy(op, rop, 8);
return (STATUS_OK);
} // conv_ieee_d_to_float64
//--------------------------------------------------------------------
// Convert T16 32-bit float to IEEE float (single format)
// IN : T16 floating number, OUT: IEEE float ,single format.
//--------------------------------------------------------------------
short ODBC::conv_float32_to_ieee_s (BYTE *op )
{
unsigned int exp; // exponent
BYTE rop[4];
// Get exponent.
exp = ((op[2] & 0x01) << 8) | op[3];
if (exp == 0)
return (STATUS_OK);
// Check underflow or overflow, since Tandem has 9-bits exponents
// IEEE has 8-bits exponents.
if ( (int)exp < (127 - 256))
return ( STATUS_UNDERFLOW);
if ( (int)exp > (127 + 255))
return ( STATUS_OVERFLOW);
exp = exp + BIAS_DIFFERENCE_S; // 127 - 256
rop[0] = (BYTE)((op[0] & 0x80) | (exp >> 1));
rop[1] = (BYTE)(((exp & 0x01) << 7) | (op[0] & 0x7F));
rop[2] = op[1];
rop[3] = (BYTE)(op[2] & 0xFE);
byte_swap(rop, 4);
memcpy(op, rop, 4);
return (STATUS_OK);
} // conv_float32_to_ieee
//--------------------------------------------------------------------
// Convert IEEE float to T16 64-bit float.
//--------------------------------------------------------------------
short ODBC::conv_ieee_s_to_float32 (BYTE *op )
{
unsigned int exp; // exponent
BYTE rop[4];
byte_swap(op, 4);
// Get exponent.
exp = ((op[0] & 0x7F) << 1) | ((op[1] & 0x80) >> 7);
if (exp == 0)
return (STATUS_OK);
exp = exp - BIAS_DIFFERENCE_S; // 127 - 256
rop[0] = (BYTE)((op[0] & 0x80) | (op[1] & 0x7F));
rop[1] = (BYTE)(op[2]);
rop[2] = (BYTE)((op[3] & 0xFE) | (exp >> 8));
rop[3] = (BYTE)(exp);
memcpy(op, rop, 4);
return (STATUS_OK);
} // conv_ieee_s_to_float32
//--------------------------------------------------------------------
// Convert depending on datatype.
//--------------------------------------------------------------------
short ODBC::Datatype_Dependent_Swap(BYTE *source, long dataType, long source_len, BOOL tandem_ieee)
{
short rst = STATUS_OK;
switch (dataType)
{
case SQLTYPECODE_CHAR:
case SQLTYPECODE_INTERVAL:
// case SQLTYPECODE_CHAR_UP:
break;
case SQLTYPECODE_VARCHAR_WITH_LENGTH:
case SQLTYPECODE_VARCHAR:
// case SQLTYPECODE_VARCHAR_UP:
case SQLTYPECODE_VARCHAR_LONG:
byte_swap_2(source);
// if (charSet == SQLCHARSETCODE_UCS2)
// byte_swap_string(source+2,*(short *)source);
break;
case SQLTYPECODE_SMALLINT:
case SQLTYPECODE_SMALLINT_UNSIGNED:
byte_swap_2(source);
break;
case SQLTYPECODE_INTEGER:
case SQLTYPECODE_INTEGER_UNSIGNED:
byte_swap_4(source);
break;
case SQLTYPECODE_LARGEINT:
byte_swap_8(source);
break;
case SQLTYPECODE_IEEE_REAL:
/* Commented the following code since SQL/MX from 2.0 started supporting IEEE float.
if (tandem_ieee == TANDEM_TO_IEEE)
rst = conv_float32_to_ieee_s ((BYTE *)source);
else
rst = conv_ieee_s_to_float32 ((BYTE *)source);
*/
byte_swap_4(source);
break;
case SQLTYPECODE_IEEE_FLOAT:
case SQLTYPECODE_IEEE_DOUBLE:
/* Commented the following code since SQL/MX from 2.0 started supporting IEEE float.
if (tandem_ieee == TANDEM_TO_IEEE)
rst = conv_float64_to_ieee_d ((BYTE *)source);
else
rst = conv_ieee_d_to_float64 ((BYTE *)source);
*/
byte_swap_8(source);
break;
case SQLTYPECODE_DATETIME:
break;
case SQLTYPECODE_DECIMAL_UNSIGNED:
case SQLTYPECODE_DECIMAL:
case SQLTYPECODE_DECIMAL_LARGE_UNSIGNED: // Tandem extension
case SQLTYPECODE_DECIMAL_LARGE: // Tandem extension
break;
default:
byte_swap(source, source_len);
break;
}
return (rst);
}
#ifdef NSK_PLATFORM
short ODBC::Datatype_Dependent_Convert(BYTE *source, long dataType, long source_len, BOOL tandem_ieee)
{
uint32 rst = NSK_FLOAT_OK;
/* Commented the following code since SQL/MX from 2.0 started supporting IEEE float.
NSK_float_ieee32 in_ieee32;
NSK_float_ieee32 out_ieee32;
NSK_float_ieee64 in_ieee64;
NSK_float_ieee64 out_ieee64;
NSK_float_tns32 in_tns32;
NSK_float_tns32 out_tns32;
NSK_float_tns64 in_tns64;
NSK_float_tns64 out_tns64;
switch (dataType)
{
case SQLTYPECODE_IEEE_REAL:
if (tandem_ieee == TANDEM_TO_IEEE)
{
// float32_to_ieee_s
in_tns32 = *(NSK_float_tns32*)source;
rst = NSK_FLOAT_TNS32_TO_IEEE32_((const NSK_float_tns32*)&in_tns32, &out_ieee32);
*(NSK_float_ieee32*)source = out_ieee32;
}
else
{
// ieee_s_to_float32
in_ieee32 = *(NSK_float_ieee32*)source;
rst = NSK_FLOAT_IEEE32_TO_TNS32_((const NSK_float_ieee32*)&in_ieee32, &out_tns32);
*(NSK_float_tns32*)source = out_tns32;
}
break;
case SQLTYPECODE_IEEE_FLOAT:
case SQLTYPECODE_IEEE_DOUBLE:
if (tandem_ieee == TANDEM_TO_IEEE)
{
// float64_to_ieee_d
in_tns64 = *(NSK_float_tns64*)source;
rst = NSK_FLOAT_TNS64_TO_IEEE64_((const NSK_float_tns64*)&in_tns64, &out_ieee64);
*(NSK_float_ieee64*)source = out_ieee64;
}
else
{
// ieee_d_to_float64
in_ieee64 = *(NSK_float_ieee64*)source;
rst = NSK_FLOAT_IEEE64_TO_TNS64_((const NSK_float_ieee64*)&in_ieee64, &out_tns64);
*(NSK_float_tns64*)source = out_tns64;
}
break;
default:
break;
}
if (rst & NSK_FLOAT_IEEE_OVERFLOW)
rst = -1;
else
rst = 0;
*/
return (rst);
}
#endif
void ODBC::SQLDatatype_Dependent_Swap(BYTE *source, long dataType, SQLINTEGER charSet, long dataLength)
{
switch (dataType)
{
case SQLTYPECODE_INTERVAL:
break;
case SQLTYPECODE_CHAR:
if (charSet == SQLCHARSETCODE_UCS2)
byte_swap_string(source,dataLength);
break;
case SQLTYPECODE_VARCHAR_WITH_LENGTH:
case SQLTYPECODE_VARCHAR:
case SQLTYPECODE_VARCHAR_LONG:
byte_swap_2(source);
if (charSet == SQLCHARSETCODE_UCS2)
byte_swap_string(source+2,*(short *)source);
break;
case SQLTYPECODE_SMALLINT:
case SQLTYPECODE_SMALLINT_UNSIGNED:
byte_swap_2(source);
break;
case SQLTYPECODE_INTEGER:
case SQLTYPECODE_INTEGER_UNSIGNED:
byte_swap_4(source);
break;
case SQLTYPECODE_LARGEINT:
byte_swap_8(source);
break;
case SQLTYPECODE_IEEE_REAL:
byte_swap_4(source);
break;
case SQLTYPECODE_IEEE_FLOAT:
case SQLTYPECODE_IEEE_DOUBLE:
byte_swap_8(source);
break;
case SQLTYPECODE_DECIMAL_UNSIGNED:
case SQLTYPECODE_DECIMAL:
case SQLTYPECODE_DECIMAL_LARGE_UNSIGNED: // Tandem extension
case SQLTYPECODE_DECIMAL_LARGE: // Tandem extension
break;
default:
break;
}
}
#ifdef NSK_PLATFORM
short ODBC::SQLDatatype_Dependent_Convert(BYTE *source, long dataType, long DateTimeCode, BOOL tandem_ieee)
{
uint32 rst = NSK_FLOAT_OK;
/* Commented the following code since SQL/MX from 2.0 started supporting IEEE float.
NSK_float_ieee32 in_ieee32;
NSK_float_ieee32 out_ieee32;
NSK_float_ieee64 in_ieee64;
NSK_float_ieee64 out_ieee64;
NSK_float_tns32 in_tns32;
NSK_float_tns32 out_tns32;
NSK_float_tns64 in_tns64;
NSK_float_tns64 out_tns64;
switch (dataType)
{
case SQLTYPECODE_IEEE_REAL:
if (tandem_ieee == TANDEM_TO_IEEE)
{
// float32_to_ieee_s
in_tns32 = *(NSK_float_tns32*)source;
rst = NSK_FLOAT_TNS32_TO_IEEE32_((const NSK_float_tns32*)&in_tns32, &out_ieee32);
*(NSK_float_ieee32*)source = out_ieee32;
}
else
{
// ieee_s_to_float32
in_ieee32 = *(NSK_float_ieee32*)source;
rst = NSK_FLOAT_IEEE32_TO_TNS32_((const NSK_float_ieee32*)&in_ieee32, &out_tns32);
*(NSK_float_tns32*)source = out_tns32;
}
break;
case SQLTYPECODE_IEEE_FLOAT:
case SQLTYPECODE_IEEE_DOUBLE:
if (tandem_ieee == TANDEM_TO_IEEE)
{
// float64_to_ieee_d
in_tns64 = *(NSK_float_tns64*)source;
rst = NSK_FLOAT_TNS64_TO_IEEE64_((const NSK_float_tns64*)&in_tns64, &out_ieee64);
*(NSK_float_ieee64*)source = out_ieee64;
}
else
{
// ieee_d_to_float64
in_ieee64 = *(NSK_float_ieee64*)source;
rst = NSK_FLOAT_IEEE64_TO_TNS64_((const NSK_float_ieee64*)&in_ieee64, &out_tns64);
*(NSK_float_tns64*)source = out_tns64;
}
break;
default:
break;
}
if (rst & NSK_FLOAT_IEEE_OVERFLOW)
rst = -1;
else
rst = 0;
*/
return (rst);
}
#endif
long ODBC::dataLength(SQLSMALLINT SQLDataType, SQLINTEGER SQLOctetLength, unsigned char* buffer)
{
long allocLength = 0;
switch (SQLDataType)
{
case SQLTYPECODE_CHAR:
case SQLTYPECODE_BIT:
case SQLTYPECODE_VARCHAR:
case SQLTYPECODE_INTERVAL:
allocLength = SQLOctetLength;
break;
case SQLTYPECODE_VARCHAR_WITH_LENGTH:
case SQLTYPECODE_VARCHAR_LONG:
case SQLTYPECODE_BITVAR:
allocLength = *(USHORT *)buffer + 3;
break;
case SQLTYPECODE_SMALLINT:
case SQLTYPECODE_SMALLINT_UNSIGNED:
case SQLTYPECODE_INTEGER:
case SQLTYPECODE_INTEGER_UNSIGNED:
case SQLTYPECODE_LARGEINT:
case SQLTYPECODE_IEEE_REAL:
case SQLTYPECODE_IEEE_FLOAT:
case SQLTYPECODE_IEEE_DOUBLE:
case SQLTYPECODE_DATETIME:
case SQLTYPECODE_DECIMAL_UNSIGNED:
case SQLTYPECODE_DECIMAL:
case SQLTYPECODE_DECIMAL_LARGE_UNSIGNED: // Tandem extension
case SQLTYPECODE_DECIMAL_LARGE: // Tandem extension
default:
allocLength = SQLOctetLength;
break;
}
return allocLength;
}
long ODBC::dataLength(SQLSMALLINT SQLDataType, SQLINTEGER SQLOctetLength, unsigned char* buffer, BOOL out)
{
long allocLength = 0;
switch (SQLDataType)
{
case SQLTYPECODE_CHAR:
case SQLTYPECODE_BIT:
case SQLTYPECODE_VARCHAR:
case SQLTYPECODE_INTERVAL:
allocLength = SQLOctetLength;
break;
case SQLTYPECODE_VARCHAR_WITH_LENGTH:
case SQLTYPECODE_VARCHAR_LONG:
case SQLTYPECODE_BITVAR:
if (out == FALSE)
allocLength = *(USHORT *)buffer + 3;
else
{
short length;
length = *(USHORT *)buffer;
#ifndef NSK_PLATFORM
byte_swap_2((unsigned char*)&length);
#endif
allocLength = length + 2;
}
break;
case SQLTYPECODE_SMALLINT:
case SQLTYPECODE_SMALLINT_UNSIGNED:
case SQLTYPECODE_INTEGER:
case SQLTYPECODE_INTEGER_UNSIGNED:
case SQLTYPECODE_LARGEINT:
case SQLTYPECODE_IEEE_REAL:
case SQLTYPECODE_IEEE_FLOAT:
case SQLTYPECODE_IEEE_DOUBLE:
case SQLTYPECODE_DATETIME:
case SQLTYPECODE_DECIMAL_UNSIGNED:
case SQLTYPECODE_DECIMAL:
case SQLTYPECODE_DECIMAL_LARGE_UNSIGNED: // Tandem extension
case SQLTYPECODE_DECIMAL_LARGE: // Tandem extension
default:
allocLength = SQLOctetLength;
break;
}
return allocLength;
}
long ODBC::dataLengthFetchRowset(SQLSMALLINT SQLDataType, SQLINTEGER SQLOctetLength, SQLINTEGER maxRowLen, unsigned char* buffer)
{
long allocLength = 0;
long maxRowLength = maxRowLen;
switch (SQLDataType)
{
case SQLTYPECODE_VARCHAR_WITH_LENGTH:
case SQLTYPECODE_VARCHAR_LONG:
case SQLTYPECODE_BITVAR:
allocLength = *(USHORT *)buffer + 2;
break;
case SQLTYPECODE_CHAR:
case SQLTYPECODE_BIT:
case SQLTYPECODE_VARCHAR:
allocLength = SQLOctetLength - 1;
if (maxRowLength > 0)
allocLength = (allocLength>maxRowLength)?maxRowLength:allocLength;
break;
default:
allocLength = SQLOctetLength;
break;
}
return allocLength;
}
long ODBC::dataLengthFetchPerf(SQLSMALLINT SQLDataType, SQLINTEGER SQLOctetLength, SQLINTEGER maxRowLen, unsigned char* buffer)
{
long allocLength = 0;
long maxRowLength = maxRowLen;
switch (SQLDataType)
{
case SQLTYPECODE_VARCHAR_WITH_LENGTH:
case SQLTYPECODE_VARCHAR_LONG:
case SQLTYPECODE_BITVAR:
allocLength = *(USHORT *)buffer + 3;
break;
case SQLTYPECODE_CHAR:
case SQLTYPECODE_BIT:
case SQLTYPECODE_VARCHAR:
allocLength = SQLOctetLength;
if (maxRowLength > 0)
allocLength = (allocLength>maxRowLength)?maxRowLength + 1:allocLength;
break;
default:
allocLength = SQLOctetLength;
break;
}
return allocLength;
}