blob: 8c5d4434adfc4daab6ffc71f3c78e13fd952411d [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 @@@
**********************************************************************/
/* -*-C++-*-
*****************************************************************************
*
* File: exp_conv.cpp
* Description:
*
*
* Created: 7/10/95
* Language: C++
*
*
*
*
*****************************************************************************
*/
#include "Platform.h"
#include "exp_ieee.h"
//#ifndef NA_NO_C_RUNTIME
#include <stdlib.h>
#include <errno.h>
//#endif
#include <math.h>
# define MathPow(op1, op2, err) pow(op1, op2)
//extern double MathPow(double Base, double Power, short &err);
#define MathLog10(op, err) log10(op)
#include <stdlib.h>
#if defined( NA_SHADOWCALLS )
#include "sqlclisp.h" //shadow
#endif
#include "exp_stdh.h"
#include "exp_clause_derived.h"
//#include "exp_tuple_desc.h"
#include "float.h"
#include "str.h"
#include "wstr.h"
#include "BigNumHelper.h"
#include "NAAssert.h"
#include "NLSConversion.h"
#include "nawstring.h"
#include "exp_datetime.h"
#include "SQLTypeDefs.h"
#include "exp_bignum.h"
#include "fenv.h"
//#pragma innerlist
// forward declarations
NA_EIDPROC
//SQ_LINUX #ifdef NA_HSC
static
rec_datetime_field getIntervalStartField(Lng32 datatype);
NA_EIDPROC
Int64 getMaxDecValue(Lng32 targetLen);
NA_EIDPROC
Lng32 getDigitCount(UInt64 value);
NA_EIDPROC
void setVCLength(char * VCLen, Lng32 VCLenSize, ULng32 value);
NA_EIDPROC
ex_expr::exp_return_type checkPrecision(Int64 source,
Lng32 sourceLen,
short sourceType,
Lng32 sourcePrecision,
Lng32 sourceScale,
short targetType,
Lng32 targetPrecision,
Lng32 targetScale,
CollHeap *heap,
ComDiagsArea** diagsArea,
ULng32 flags);
//////////////////////////////////////////////////////////////////
//
// Function to double the value of the varchar length field for
// Unicode related conversion. All unicode related conversions
// involving non-chartype operands reuse the corresponding
// Ascii version. This function is used to adjust the varchar
// length calculated by the Ascii function. 6/3/98
//
//////////////////////////////////////////////////////////////////
NA_EIDPROC
void double_varchar_length(
char * varCharLen, // NULL if not a varChar
Lng32 varCharLenSize // 0 if not a varChar
)
{
if (varCharLenSize == sizeof(Lng32)) {
Lng32 x;
// LCOV_EXCL_START
str_cpy_all((char*)&x, varCharLen, sizeof(Lng32));
x *= BYTES_PER_NAWCHAR;
str_cpy_all(varCharLen, (char *)&x, sizeof(Lng32));
// LCOV_EXCL_STOP
} else {
short x;
str_cpy_all((char*)&x, varCharLen, sizeof(short));
x *= BYTES_PER_NAWCHAR;
str_cpy_all(varCharLen, (char *)&x, sizeof(short));
}
}
//////////////////////////////////////////////////////////////////
//
//A helper function to return charset name
//
/////////////////////////////////////////////////////////////////
static const char* scaleToString(short scale)
{
switch(scale)
{
case SQLCHARSETCODE_ISO88591:
return "ISO88591";
case SQLCHARSETCODE_KANJI:
return "KANJI";
case SQLCHARSETCODE_KSC5601:
return "KSC5601";
case SQLCHARSETCODE_SJIS:
return "SJIS";
case SQLCHARSETCODE_UCS2 :
return "UCS2";
case SQLCHARSETCODE_EUCJP :
return "EUCJP";
case SQLCHARSETCODE_BIG5:
return "BIG5";
case SQLCHARSETCODE_GB18030:
return "GB18030";
case SQLCHARSETCODE_UTF8:
return "UTF8";
case SQLCHARSETCODE_MB_KSC5601:
return "MB_KSC5601";
case SQLCHARSETCODE_GB2312:
return "GB2312";
case SQLCHARSETCODE_GBK:
return "GBK";
default:
return "UNKNOWN";
}
return "UNKNOWN";
}
//////////////////////////////////////////////////////////////////
//
// A helper function that multiplies the dvalue by 10 and
// adds the digit. It checks overflow during the computation.
//
// This function returns 0 if not overflow or 1 otherwise.
//
// This function is used by convAsciiToFloat64 to coverting
// a string of digits to double. jdu 6/10/02
//
//////////////////////////////////////////////////////////////////
NA_EIDPROC
static Int32 safe_add_digit_to_double(
double dvalue, // Original value
Int32 digit, // Single digit to be added
double * result
)
{
short ov;
*result = MathReal64Mul(dvalue, (double)10, &ov);
if (ov != 0) // result overflowed
return ov;
*result = MathReal64Add(*result, (double)digit, &ov);
return ov;
}
//////////////////////////////////////////////////////////////////
// function to convert a signed BIN (of 2, 4 or 8 bytes) to
// a signed BIN (of 2, 4 or 8 bytes), with multiplication by a
// scaling factor
//
// This is useful when overflows and truncations from scaling
// need to be captured; but it also works with the diagsArea
// error model.
//
// Returns ex_expr::EXPR_OK if (conversion was successful) or (a
// conversion error occurred and the data conversion error flag
// is present).
//
// Returns ex_expr::EXPR_ERROR if (a conversion error occurred) and
// (no data conversion error flag is present).
///////////////////////////////////////////////////////////////////
NA_EIDPROC
ex_expr::exp_return_type convBinToBinScaleMult(
char *target,
short targetType,
Lng32 targetLen,
Lng32 targetPrecision,
Lng32 targetScale,
char *source,
short sourceType,
Lng32 sourceLen,
Lng32 sourcePrecision,
Int64 scaleFactor,
CollHeap *heap,
ComDiagsArea** diagsArea,
Lng32 *dataConversionErrorFlag,
ULng32 flags)
{
Lng32 tempDataConversionErrorFlag = ex_conv_clause::CONV_RESULT_OK; // assume success
ex_expr::exp_return_type rc = ex_expr::EXPR_OK;
// widen source to Int 64
Int64 intermediate;
switch (sourceLen)
{
case SQL_SMALL_SIZE:
intermediate = *(short *)source;
break;
case SQL_INT_SIZE:
intermediate = *(Lng32 *)source;
break;
case SQL_LARGE_SIZE:
intermediate = *(Int64 *)source;
break;
default:
// shouldn't happen
intermediate = 0;
break;
}
assert (sourceType >= REC_MIN_INTERVAL && sourceType <= REC_MAX_INTERVAL &&
targetType >= REC_MIN_INTERVAL && targetType <= REC_MAX_INTERVAL);
// make sure value is small enough to be successfully converted,
// then convert it else raise an error
if ((intermediate < LLONG_MAX/scaleFactor) &&
(intermediate > LLONG_MIN/scaleFactor))
{
intermediate = intermediate * scaleFactor;
}
// LCOV_EXCL_START
else if (dataConversionErrorFlag)
{
if (intermediate > 0)
{
// result too large -- just set it to max
intermediate = LLONG_MAX;
tempDataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
// result too small -- just set it to min
intermediate = LLONG_MIN;
tempDataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, sourceType, 0, targetType, flags);
return ex_expr::EXPR_ERROR;
}
// LCOV_EXCL_STOP
// now move converted intermediate to target
if (targetLen == SQL_LARGE_SIZE)
{
*(Int64 *)target = intermediate; // yeah, it's an extra move
if (dataConversionErrorFlag)
*dataConversionErrorFlag = tempDataConversionErrorFlag;
if (((sourceType >= REC_MIN_INTERVAL) &&
(sourceType <= REC_MAX_INTERVAL) &&
(targetType >= REC_MIN_INTERVAL) &&
(targetType <= REC_MAX_INTERVAL)) &&
(getIntervalStartField (sourceType) <
getIntervalStartField (targetType) ||
sourcePrecision > targetPrecision )) // truncation is possible
{
rc = checkPrecision(intermediate,
sourceLen,
sourceType,
sourcePrecision,
targetScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
flags);
}
}
else
{
short physicalTargetType = (short) REC_BIN16_SIGNED;
ConvInstruction index = CONV_BIN64S_BIN16S;
if (targetLen == SQL_INT_SIZE)
{
physicalTargetType = (short) REC_BIN32_SIGNED;
index = CONV_BIN64S_BIN32S;
}
// In this convDoIt, we're purposely passing in 0 for target precision
// because we don't want this convDoIt to check for precision validity
// since this call to convDoIt is converting 2 binary operands, and not
// intervals. checkPrecision is called after this convDoIt with the correct
// interval types
rc = convDoIt((char *) &intermediate,
SQL_LARGE_SIZE,
(short) REC_BIN64_SIGNED,
sourcePrecision,
0, // sourceScale
target,
targetLen,
physicalTargetType,
0, //target precision
0, // targetScale,
NULL, // varCharLen
0, // varCharLenSize
heap,
diagsArea,
index,
dataConversionErrorFlag,
flags | CONV_INTERMEDIATE_CONVERSION);
// if there was no error on the second conversion,
// then report back any error from the first conversion
// (see the discussion in convDoIt() case CONV_LARGEDEC_BIN16S
// for a proof of why this is the correct thing to do)
if (dataConversionErrorFlag) {
if (*dataConversionErrorFlag == ex_conv_clause::CONV_RESULT_OK)
*dataConversionErrorFlag = tempDataConversionErrorFlag;
}
if (rc != ex_expr::EXPR_OK) {
return rc;
}
rc = checkPrecision(intermediate,
sourceLen,
sourceType,
sourcePrecision,
targetScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
flags);
}
return rc;
}
//////////////////////////////////////////////////////////////////
// function to convert a signed BIN (of 2, 4 or 8 bytes) to
// a signed BIN (of 2, 4 or 8 bytes), with division by a
// scaling factor
//
// This is useful when overflows and truncations from scaling
// need to be captured; but it also works with the diagsArea
// error model.
//
// Returns ex_expr::EXPR_OK if (conversion was successful) or (a
// conversion error occurred and the data conversion error flag
// is present).
//
// Returns ex_expr::EXPR_ERROR if (a conversion error occurred) and
// (no data conversion error flag is present).
///////////////////////////////////////////////////////////////////
NA_EIDPROC
ex_expr::exp_return_type convBinToBinScaleDiv(
char *target,
short targetType,
Lng32 targetLen,
Lng32 targetPrecision,
Lng32 targetScale,
char *source,
short sourceType,
Lng32 sourceLen,
Lng32 sourcePrecision,
Int64 scaleFactor,
CollHeap *heap,
ComDiagsArea** diagsArea,
Lng32 *dataConversionErrorFlag,
ULng32 flags)
{
Lng32 tempDataConversionErrorFlag = ex_conv_clause::CONV_RESULT_OK; // assume success
ex_expr::exp_return_type rc = ex_expr::EXPR_OK;
// widen source to Int 64
Int64 intermediate;
switch (sourceLen)
{
case SQL_SMALL_SIZE:
intermediate = *(short *)source;
break;
case SQL_INT_SIZE:
intermediate = *(Lng32 *)source;
break;
case SQL_LARGE_SIZE:
intermediate = *(Int64 *)source;
break;
default:
// shouldn't happen
intermediate = 0;
break;
}
assert (sourceType >= REC_MIN_INTERVAL && sourceType <= REC_MAX_INTERVAL &&
targetType >= REC_MIN_INTERVAL && targetType <= REC_MAX_INTERVAL);
// divide by the scaleFactor, checking to see if significant
// truncation occurred
Int64 intermediate2 = intermediate / scaleFactor;
Int64 intermediate3 = intermediate2 * scaleFactor;
if (dataConversionErrorFlag)
{
if (intermediate3 < intermediate)
{
// truncation occurred; result was rounded down
// (can happen only if intermediate is positive)
tempDataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
else if (intermediate3 > intermediate)
{
// truncation occurred; result was rounded up
// (can happen only if intermediate is negative)
tempDataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
}
}
else
{
// scale truncation occurred - raise error
if (intermediate3 != intermediate) {
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, 0,
targetType, flags);
return ex_expr::EXPR_ERROR;
}
}
intermediate = intermediate2;
// now move converted intermediate to target
if (targetLen == SQL_LARGE_SIZE)
{
*(Int64 *)target = intermediate; // yeah, it's an extra move
if (dataConversionErrorFlag)
*dataConversionErrorFlag = tempDataConversionErrorFlag;
if (((sourceType >= REC_MIN_INTERVAL) &&
(sourceType <= REC_MAX_INTERVAL) &&
(targetType >= REC_MIN_INTERVAL) &&
(targetType <= REC_MAX_INTERVAL)) &&
(getIntervalStartField (sourceType) <
getIntervalStartField (targetType) ||
sourcePrecision > targetPrecision )) // truncation is possible
{
rc = checkPrecision(intermediate,
sourceLen,
sourceType,
sourcePrecision,
targetScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
flags);
}
}
else
{
short physicalTargetType = (short) REC_BIN16_SIGNED;
ConvInstruction index = CONV_BIN64S_BIN16S;
if (targetLen == SQL_INT_SIZE)
{
physicalTargetType = (short) REC_BIN32_SIGNED;
index = CONV_BIN64S_BIN32S;
}
if (targetLen == SQL_INT_SIZE)
physicalTargetType = (short) REC_BIN32_SIGNED;
// In this convDoIt, we're purposely passing in 0 for target precision
// because we don't want this convDoIt to check for precision validity
// since this call to convDoIt is converting 2 binary operands, and not
// intervals. checkPrecision is called after this convDoIt with the correct
// interval types
rc = convDoIt((char *) &intermediate,
SQL_LARGE_SIZE,
(short) REC_BIN64_SIGNED,
sourcePrecision,
0, // sourceScale
target,
targetLen,
physicalTargetType,
0, // target precision
0, // targetScale,
NULL, // varCharLen
0, // varCharLenSize
heap,
diagsArea,
index,
dataConversionErrorFlag,
flags | CONV_INTERMEDIATE_CONVERSION);
// if there was no error on the second conversion,
// then report back any error from the first conversion
// (see the discussion in convDoIt() case CONV_LARGEDEC_BIN16S
// for a proof of why this is the correct thing to do)
if (dataConversionErrorFlag)
{
if (*dataConversionErrorFlag == ex_conv_clause::CONV_RESULT_OK)
*dataConversionErrorFlag = tempDataConversionErrorFlag;
}
if (rc != ex_expr::EXPR_OK)
return rc;
rc = checkPrecision(intermediate,
sourceLen,
sourceType,
sourcePrecision,
targetScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
flags);
}
return rc;
}
//////////////////////////////////////////////////////////////////
// function to convert an Int64 to an ASCII string
// Trailing '\0' is not set!
//
// For fixed char targets, left pad fillers if leftPad is
// TRUE, or right pad fillers (default mode) otherwise.
//
// convDoIt sets leftPad to TRUE if callers pass in a
// CONV_UNKNOWN_LEFTPAD to convDoIt.
//
// In only a few cases of fixed char, leftPad will be set to TRUE.
// e.g., caller wants to convert 7 -> 07 as in month -> ascii
// or 8 -> ' 8' as in sqlci display
///////////////////////////////////////////////////////////////////
NA_EIDPROC
ex_expr::exp_return_type convInt64ToAscii(char *target,
Lng32 targetLen,
Lng32 targetPrecision, // max. characters
Lng32 targetScale,
Int64 source,
Lng32 scale,
char * varCharLen,
Lng32 varCharLenSize,
char filler,
NABoolean leadingSign,
NABoolean leftPad,
NABoolean srcIsUInt64,
CollHeap *heap,
ComDiagsArea** diagsArea) {
Lng32 digitCnt = 0;
ULng32 flags = 0;
NABoolean negative = (srcIsUInt64 ? FALSE : (source < 0));
NABoolean fixRightMost = FALSE; // True if need to fix the rightmost digit.
Int16 trgType;
if (varCharLenSize)
trgType = REC_BYTE_V_ASCII;
else
trgType = REC_BYTE_F_ASCII;
Lng32 padLen = targetLen;
Lng32 targetChars = targetLen;
Lng32 requiredDigits = 0;
Lng32 leftMost; // leftmost digit.
Lng32 rightMost; // rightmost digit.
Lng32 sign = 0;
// Int64 newSource = (negative ? -source : source);
UInt64 newSource = 0;
if (targetPrecision)
{
// target has a max. number of characters which may be smaller than
// the target length
targetChars = targetPrecision;
padLen = targetPrecision;
assert(targetLen >= targetPrecision);
}
if ((negative) && (source == 0x8000000000000000LL)) // = -2 ** 63
{
newSource = 0x7fffffffffffffffLL;
// 123456789012345
digitCnt = 19;
fixRightMost = TRUE;
}
else
{
newSource = (UInt64) (negative ? -source : source);
digitCnt = getDigitCount(newSource);
}
if (leadingSign || negative) {
sign = 1;
padLen--;
}
// No truncation allowed.
requiredDigits = digitCnt;
// Add extra zero's.
if (scale > requiredDigits)
requiredDigits += (scale - requiredDigits);
padLen -= requiredDigits;
if (scale)
padLen--; // decimal point
if (padLen < 0) {
// target string is not long enough - overflow
ExRaiseDetailSqlError(heap, diagsArea, EXE_STRING_OVERFLOW,
(char*)&source,
sizeof(Int64), REC_BIN64_SIGNED, scale, trgType,
flags,
targetLen, targetScale,
targetPrecision);
return ex_expr::EXPR_ERROR;
}
if (varCharLenSize) {
// we do not pad. Instead, we adjust the targetLen
leftPad = FALSE;
targetChars -= padLen;
targetLen = targetChars;
padLen = 0;
}
else if (targetChars < targetLen) {
// Fill out the unused bytes after targetChars with blanks.
str_pad(&target[targetChars], targetLen-targetChars, ' ');
}
if (leftPad) {
leftMost = padLen + sign;
}
else {
leftMost = sign;
}
Lng32 currPos;
// Add filler.
rightMost = currPos = targetChars - 1;
if (padLen) {
Lng32 start;
if (leftPad) { // Pad to the left.
start = sign;
}
else { // Pad to the right
start = targetChars - padLen;
rightMost = currPos = start - 1;
}
str_pad(&target[start], padLen, filler);
}
// Convert the fraction part and add decimal point.
if (scale) {
Lng32 low = (currPos - scale);
for (; currPos > low; currPos--) {
target[currPos] = (char)((newSource % 10) + '0');
newSource /= 10;
}
target[currPos--] = '.';
}
// Convert the integer part.
for (; currPos >= leftMost; currPos--) {
target[currPos] = (char)((newSource % 10) + '0');
newSource /= 10;
}
// Add sign.
if (leadingSign) {
if (negative)
target[0] = '-';
else
target[0] = '+';
}
else if (negative)
target[currPos] = '-';
// Fix the rightmost digit for -2 ** 63.
if (fixRightMost && target[rightMost] == '7')
target[rightMost] = '8';
if (newSource != 0 || currPos < -1)
{ // Sanity check fails.
ExRaiseDetailSqlError(heap, diagsArea, EXE_STRING_OVERFLOW,
(char*)&source,
sizeof(Int64), REC_BIN64_SIGNED, scale, trgType,
flags, targetLen, targetScale);
return ex_expr::EXPR_ERROR;
}
// Set varchar length field for varchar.
if (varCharLenSize)
if (varCharLenSize == sizeof(Lng32))
str_cpy_all(varCharLen, (char *) &targetLen, sizeof(Lng32));
else {
short VCLen = (short) targetLen;
str_cpy_all(varCharLen, (char *) &VCLen, sizeof(short));
};
return ex_expr::EXPR_OK;
};
//////////////////////////////////////////////////////////////////
// function to convert an FLOAT64 to an ASCII string
// Trailing '\0' is not set!
// This routine assumes that targetLen is at least
// SQL_REAL_MIN_DISPLAY_SIZE:
// 1 byte sign
// 1 byte for digit in front of decimal point
// 1 byte decimal point
// 1 byte for at least one digit after decimal point
// 5 bytes for exponent (E+DDD)
///////////////////////////////////////////////////////////////////
NA_EIDPROC
short convFloat64ToAscii(char *target,
Lng32 targetLen,
Lng32 targetPrecision, // max. characters
Lng32 targetScale,
double source,
// maximum # of fraction digits
Lng32 digits,
char * varCharLen,
Lng32 varCharLenSize,
NABoolean leftPad) {
short err = 0;
Lng32 displaySize = digits + 8; // Mantissa = digits + 3, E = 1, Exponent = 4
Lng32 targetChars = targetLen;
assert(displaySize <= SQL_DOUBLE_PRECISION_DISPLAY_SIZE);
char tempTarget[SQL_DOUBLE_PRECISION_DISPLAY_SIZE + 1];
//char format[8];
if (targetPrecision)
{
// target allows fewer characters than targetLen
assert(targetLen >= targetPrecision);
targetChars = targetPrecision;
}
// the fraction has always between 1 and "digits" digits
if ((targetChars - 8) < digits)
{
digits = targetChars - 8;
if (digits < 1)
return -1;
}
Lng32 usedTargetLen = MINOF(displaySize, targetChars);
if (isinf(source)) {
source = 0;
}
double absSource = source;
NABoolean neg = FALSE;
if (source < 0)
{
absSource = -source;
neg = TRUE;
}
Int64 expon = 0;
Int64 intMantissa = 0;
NABoolean expPos = TRUE;
if (absSource > 0)
{
double logTen = MathLog10(absSource, err);
if (err)
return -1;
if (logTen >= 0)
{
expPos = TRUE;
}
else
{
logTen = -logTen;
expPos = FALSE;
};
// replace with a faster way below (4 lines)
// while (logTen > 0)
// {
// expon++;
// logTen -= 1;
// }
expon = (Int32) logTen;
logTen -= expon;
if (logTen > 0.0)
expon++;
if ((expPos) && (logTen != 0))
expon--;
NABoolean reduceExpon = FALSE;
short reduceExponBy = 0;
if (expon >= DBL_MAX_10_EXP)
{
// if expon is greater than MAX exponent allowed, then reduce it
// the diff between expon and DBL_MAX_10_EXP.
// This is needed so the next MathPow call doesn't return
// an error when it tries to do 10 ** DBL_MAX_10_EXP
// (which will make it greater than the max double value).
reduceExponBy = (short)(expon - DBL_MAX_10_EXP + 1);
expon -= reduceExponBy;
reduceExpon = TRUE;
}
double TenPowerExpon =
((expPos == FALSE) ? MathPow(10.0, (double)expon, err) : MathPow(10.0, (double)-expon, err));
if (err)
return -1;
if (isinf(TenPowerExpon))
return -1;
double mantissa = absSource * TenPowerExpon;
if (reduceExpon)
{
// now fix mantissa by multiplying or dividing by 10.
double tempMathPow = MathPow(10.0, reduceExponBy, err);
if (isinf(tempMathPow))
return -1;
if (expPos == FALSE)
mantissa = mantissa * tempMathPow;
else
mantissa = mantissa / tempMathPow;
if (err)
return -1;
// and increase expon to its original value
expon += reduceExponBy;
}
// The multiplication and casting to an Int64 below has caused several
// problems on Linux. Performing the multiplication and casting to Int64
// on seperate lines seems to fix this problem.
double doubleIntMantissa = MathPow(10.0,(double)digits,err);
if (isinf(doubleIntMantissa))
return -1;
doubleIntMantissa = mantissa * doubleIntMantissa;
if (err)
return -1;
intMantissa = (Int64)doubleIntMantissa;
}
short error;
error =
convInt64ToAscii(tempTarget, digits+3, 0, targetScale,
(neg ? -intMantissa : intMantissa),
digits, NULL, 0, ' ',
neg, TRUE, FALSE, NULL, NULL);
if (error)
return -1;
// If the mantissa is 0, *or* if the digit before the decimal point is still
// a space char (i.e. mantissa is < 0), then be sure to initialize the digit
// to 0 - callers are dependent on the fact that this space is initialized.
if ((intMantissa == 0) || (tempTarget[1] == ' '))
{
// add a 0 before the decimal point of mantissa
tempTarget[1] = '0';
}
tempTarget[digits+3] = 'E';
error =
convInt64ToAscii(&tempTarget[digits+4], 4, 0, targetScale,
(expPos ? expon : -expon),
0, NULL, 0, '0',
TRUE, TRUE, FALSE, NULL, NULL);
if (error)
return -1;
char *pch = tempTarget;
while (*pch == ' ') {
usedTargetLen--;
pch++;
}
if (varCharLenSize) {
// the target is a varChar. Just move the data left adjusted and
// set the length field.
str_cpy_all(target, pch, usedTargetLen);
if (varCharLenSize == sizeof(Lng32))
str_cpy_all(varCharLen, (char *) &usedTargetLen, sizeof(Lng32));
else {
short VCLen = (short) usedTargetLen;
str_cpy_all(varCharLen, (char *) &VCLen, sizeof(short));
};
}
else {
// if target is larger than usedTargetLen, fill in blanks.
Lng32 padLen = targetLen - usedTargetLen;
if (leftPad) {
str_pad(target, padLen, ' ');
str_cpy_all(&target[padLen], pch, usedTargetLen);
}
else {
str_cpy_all(target, pch, usedTargetLen);
str_pad(&target[usedTargetLen], padLen, ' ');
}
};
return 0;
}
//////////////////////////////////////////////////////////////////
// function to convert an Int64 to a Big Num
///////////////////////////////////////////////////////////////////
NA_EIDPROC
ex_expr::exp_return_type convInt64ToBigNum(char *target,
Lng32 targetLen,
Int64 source,
NAMemory *heap,
ComDiagsArea** diagsArea,
ULng32 flags) {
short retCode = BigNumHelper::ConvInt64ToBigNumWithSignHelper(targetLen,
source,
target,
FALSE);
if (retCode == -1) {
// target is not long enough - overflow
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,(char*)&source,
sizeof(Int64), REC_BIN64_SIGNED, 0, REC_NUM_BIG_SIGNED,
flags);
return ex_expr::EXPR_ERROR;
};
return ex_expr::EXPR_OK;
};
//////////////////////////////////////////////////////////////////
// function to convert a UInt64 to a Big Num
///////////////////////////////////////////////////////////////////
NA_EIDPROC
ex_expr::exp_return_type convUInt64ToBigNum(char *target,
Lng32 targetLen,
UInt64 source,
NAMemory *heap,
ComDiagsArea** diagsArea,
ULng32 flags) {
short retCode = BigNumHelper::ConvInt64ToBigNumWithSignHelper(targetLen,
source,
target,
TRUE);
if (retCode == -1) {
// target is not long enough - overflow
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,(char*)&source,
sizeof(Int64), REC_BIN64_UNSIGNED, 0, REC_NUM_BIG_SIGNED,
flags);
return ex_expr::EXPR_ERROR;
};
return ex_expr::EXPR_OK;
};
//////////////////////////////////////////////////////////////////
// function to convert BIGNUM to LARGEDEC
///////////////////////////////////////////////////////////////////
NA_EIDPROC
ex_expr::exp_return_type convBigNumToLargeDec(char *target,
Lng32 targetLen,
char *source,
Lng32 sourceLen,
NAMemory *heap,
ComDiagsArea** diagsArea,
ULng32 flags) {
// Convert the Big Num (with sign) into a BCD representation by calling
// a BigNumHelper method
short retCode = BigNumHelper::ConvBigNumWithSignToBcdHelper(sourceLen,
targetLen,
source,
target,
heap);
if (retCode == -1) {
// target is not long enough - overflow
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, REC_NUM_BIG_SIGNED, 0,
REC_DECIMAL_LSE, flags);
return ex_expr::EXPR_ERROR;
};
return ex_expr::EXPR_OK;
}
//////////////////////////////////////////////////////////////////
// function to convert a LARGEDEC to an ASCII string
// Trailing '\0' is not set!
//
// For fixed char target, left pad blanks if leftPad is TRUE, or
// right pad blanks otherwise.
//
// For varchar target, left-justify string without blank pads
// to the right.
//
// convDoIt sets leftPad to TRUE if callers pass in a
// CONV_UNKNOWN_LEFTPAD to convDoIt.
///////////////////////////////////////////////////////////////////
NA_EIDPROC
ex_expr::exp_return_type convLargeDecToAscii(char *target,
Lng32 targetLen,
Lng32 targetPrecision, // max chars
char *source,
Lng32 sourceLen,
Lng32 sourceScale,
char * varCharLen,
Lng32 varCharLenSize,
NABoolean leftPad,
CollHeap *heap,
ComDiagsArea** diagsArea) {
ULng32 flags = 0;
Lng32 targetLenInChars = ( targetPrecision ? targetPrecision : targetLen );
Int16 trgType;
if (varCharLenSize)
trgType = REC_BYTE_V_ASCII;
else
trgType = REC_BYTE_F_ASCII;
if(source[0] < 2)
{
unsigned short realSource[256];
// LCOV_EXCL_START
str_cpy_all((char *)realSource, source, sourceLen);
if(realSource[0]) source[0] = '-';
else source[0] = '+';
Int32 realLength = 1+(sourceLen-2)/5;
for(Int32 srcPos=sourceLen-1; srcPos; srcPos--)
{
ULng32 r = 0;
for(Int32 i=1; i<=realLength; i++)
{
ULng32 q = (realSource[i] + r) / 10;
r = (r + realSource[i]) - 10 * q;
realSource[i] = (short)q;
r <<= 16;
}
source[srcPos] = (char)(r >>= 16);
// LCOV_EXCL_STOP
}
}
if (varCharLenSize)
leftPad = FALSE;
// skip leading zeros; start with index == 1; index == 0 is sign
// stop looking one position before the decimal point. This
// position is sourceLen - sourceScale - 1
Lng32 currPos = 1;
while ((currPos < (sourceLen - sourceScale - 1)) && source[currPos] == 0)
currPos++;
Lng32 padLen = targetLenInChars;
if (source[0] == '-')
padLen--;
Lng32 requiredDigits = sourceLen - currPos; // - sourceScale;
padLen -= requiredDigits;
if (sourceScale)
padLen--; //decimal point
if (padLen < 0)
{
// target string is not long enough - overflow
ExRaiseDetailSqlError(heap, diagsArea, EXE_STRING_OVERFLOW,
source, sourceLen, REC_DECIMAL_LSE,
sourceScale, trgType, flags);
return ex_expr::EXPR_ERROR;
}
Lng32 targetPos = 0;
// if target is fixed length and leftPad, left pad blanks
if (leftPad) {
for (; targetPos < padLen; targetPos++)
target[targetPos] = ' ';
}
// fill in sign
if (source[0] == '-')
target[targetPos++] = '-';
// fill in digits
Lng32 i = 0;
for (i = 0; i < (requiredDigits-sourceScale); i++, targetPos++, currPos++)
#pragma nowarn(1506) // warning elimination
target[targetPos] = source[currPos] + '0';
#pragma warn(1506) // warning elimination
// if we have a scale, add decimal point and some digits
if (sourceScale) {
target[targetPos++] = '.';
for (i = 0; i < sourceScale; i++, targetPos++, currPos++)
#pragma nowarn(1506) // warning elimination
target[targetPos] = source[currPos] + '0';
#pragma warn(1506) // warning elimination
};
// Right pad blanks for fixed char.
if (!varCharLenSize)
while (targetPos < targetLen)
target[targetPos++] = ' ';
// set length field for variable length targets
if (varCharLenSize) {
if (varCharLenSize == sizeof(Lng32))
str_cpy_all(varCharLen, (char *) &targetPos, sizeof(Lng32));
else {
short VCLen = (short) targetPos;
str_cpy_all(varCharLen, (char *) &VCLen, sizeof(short));
};
};
return ex_expr::EXPR_OK;
};
//////////////////////////////////////////////////////////////////
// function to convert a BIGNUM to an ASCII string
// Trailing '\0' is not set!
//
// This function first converts the BIGNUM to an intermediate
// LARGEDEC, then calls the previous function convLargeDecToAscii()
///////////////////////////////////////////////////////////////////
NA_EIDPROC
ex_expr::exp_return_type convBigNumToAscii(char *target,
Lng32 targetLen,
Lng32 targetPrecision, // max chars
char *source,
Lng32 sourceLen,
Lng32 sourcePrecision,
Lng32 sourceScale,
char * varCharLen,
Lng32 varCharLenSize,
NABoolean leftPad,
NAMemory *heap,
ComDiagsArea** diagsArea,
ULng32 flags)
{
const Int32 tempSpaceLen = 257; // one extra byte for the sign.
char tempIntermediateLargeDec[tempSpaceLen];
char* intermediateLargeDec = tempIntermediateLargeDec;
// If heap exists, allocate temp through it. Otherwise use static temp space.
if (heap)
intermediateLargeDec = new (heap) char[sourcePrecision + 1]; // + 1 for sign
else {
if ( targetLen > tempSpaceLen )
return ex_expr::EXPR_ERROR;
}
if (convBigNumToLargeDec(intermediateLargeDec,
sourcePrecision + 1,
source,
sourceLen,
heap,
diagsArea,
flags | CONV_INTERMEDIATE_CONVERSION) != ex_expr::EXPR_OK) {
return ex_expr::EXPR_ERROR;
}
ex_expr::exp_return_type retValue = convLargeDecToAscii(target,
targetLen,
targetPrecision,
intermediateLargeDec,
sourcePrecision + 1,
sourceScale,
varCharLen,
varCharLenSize,
leftPad,
heap,
diagsArea);
if (heap)
NADELETEBASIC(intermediateLargeDec, (heap));
return retValue;
};
// convDatetimeToAscii() ============================================
// This function converts datetime values to ASCII string values in
// the DEFAULT format (yyyy-mm-dd hh:mm:ss.msssss). Only those fields
// present in the datetime value are formated. If the datetime value
// has a fraction portion of the SECOND field, it will be formatted
// according to how much space is available in the destination string
// value. If the target is a fixed size, available trailing space is
// padded with ' ' (space) characters.
//
// This method has been modified as part of the MP Datetime
// Compatibility project. It has been modified to handle non-standard
// datetime types and all combinations of conversions.
// ===================================================================
//
NA_EIDPROC
ex_expr::exp_return_type convDatetimeToAscii(char *target,
Lng32 targetLen,
Lng32 targetPrecision, // tgt length in char or 0
char *source,
Lng32 sourceLen,
REC_DATETIME_CODE code,
short fractionPrecision,
char * varCharLen,
Lng32 varCharLenSize,
NABoolean leftPad,
CollHeap *heap,
ComDiagsArea** diagsArea)
{
// Declare attributes to make use of ExpDatetime convDatetimeToASCII
//
ExpDatetime srcDatetimeOpType;
Lng32 targetLenInChars = ( targetPrecision ? targetPrecision : targetLen );
// Setup attribute for the source.
//
srcDatetimeOpType.setPrecision(code);
srcDatetimeOpType.setScale(fractionPrecision);
// Convert the datetime value to ASCII in the DEFAULT format.
//
Lng32 realTargetLen =
srcDatetimeOpType.convDatetimeToASCII(source,
target,
targetLenInChars,
ExpDatetime::DATETIME_FORMAT_DEFAULT,
NULL,
heap,
diagsArea);
if (realTargetLen < 0) {
return ex_expr::EXPR_ERROR;
}
// if target is fixed length, leftpad or right pad.
//
if ((!varCharLenSize) &&
(realTargetLen < targetLen))
{
if (leftPad && realTargetLen < targetLenInChars)
{
// right shift result
Int32 i;
for (i = 0; i < realTargetLen; i++)
{
target[targetLenInChars - (i+1)] = target[realTargetLen - (i+1)];
// target[targetLen - realTargetLen + i] = target[i];
}
// and blankpad on the left
for (i = 0; i < (targetLenInChars - realTargetLen); i++)
{
target[i] = ' ';
}
realTargetLen = targetLenInChars;
}
// blankpad on the right
if (realTargetLen < targetLen)
{
for (Int32 i = realTargetLen; i < targetLen; i++)
target[i] = ' ';
}
}
// set length field for variable length targets
//
if (varCharLenSize) {
if (varCharLenSize == sizeof(Lng32)) {
str_cpy_all(varCharLen, (char *) &realTargetLen, sizeof(Lng32));
} else {
short VCLen = (short) realTargetLen;
str_cpy_all(varCharLen, (char *) &VCLen, sizeof(short));
}
}
return ex_expr::EXPR_OK;
}
// convAsciiToDatetime() ============================================
// This function converts an ASCII string in any of the three
// (DEFAULT, EUROPEAN, or USA) formats, to the given datetime type.
// The string must have the same fields as the given datetime type.
// If the string has a fractional portion of the SECOND field and the
// datetime type has no fractional precision, the fraction portion of
// the string is ignored. If the datetime type has a fractional
// precision and the string has no fraction protion, then the fraction
// is set to zero. If the string has a fraction portion and the
// datetime type has a fractional precision, then the fraction portion
// of the string is scaled (up or down) to match the datetime type.
//
// This method has been modified as part of the MP Datetime
// Compatibility project. It has been modified to handle non-standard
// datetime types and all combinations of conversions.
//
// This method has been modified again as an interface to call
// methods in expDatetime class as part of the effort to improve
// IMPORT conversion performance.
// ===================================================================
//
NA_EIDPROC
ex_expr::exp_return_type convAsciiToDatetime(char *target,
Lng32 targetLen,
REC_DATETIME_CODE code,
short fractionPrecision,
char *source,
Lng32 sourceLen,
CollHeap *heap,
ComDiagsArea** diagsArea,
ULng32 flags)
{
// Declare attributes to make use of ExpDatetime convAsciiToDatetime
//
ExpDatetime dstOpType;
short ret;
// Setup attribute for the destination.
//
dstOpType.setPrecision(code);
dstOpType.setScale(fractionPrecision);
ret = dstOpType.convAsciiToDatetime(source,
sourceLen,
target,
targetLen,
ExpDatetime::DATETIME_FORMAT_NONE,
heap,
diagsArea,
flags);
if (ret < 0)
return ex_expr::EXPR_ERROR;
return ex_expr::EXPR_OK;
}
// LCOV_EXCL_START
NA_EIDPROC
ex_expr::exp_return_type convUnicodeToDatetime(char *target,
Lng32 targetLen,
REC_DATETIME_CODE code,
short fractionPrecision,
char *source, // actually is NAWchar *
Lng32 sourceLen, // source length in bytes
CollHeap *heap,
ComDiagsArea** diagsArea
)
{
const NAWcharBuf wBuf((NAWchar*)source, sourceLen/BYTES_PER_NAWCHAR, heap);
charBuf *cBuf = NULL;
cBuf = unicodeToISO88591(wBuf, heap, cBuf);
if (cBuf) {
Int32 convertedLen = cBuf -> getStrLen();
if ( convertedLen == sourceLen/BYTES_PER_NAWCHAR ) {
ex_expr::exp_return_type ok =
convAsciiToDatetime(target,
targetLen,
code,
fractionPrecision,
(char*)cBuf->data(),
cBuf->getStrLen(),
heap,
diagsArea,
0);
NADELETE(cBuf, charBuf, heap);
return ok;
}
}
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_DATETIME_ERROR, NULL, NULL, NULL, NULL, stringToHex(hexstr, sizeof(hexstr) , source, sourceLen ));
return ex_expr::EXPR_ERROR;
}
// LCOV_EXCL_STOP
// convDatetimeDatetime() ============================================
// This function supports any datetime to datetime conversions with
// missing leading fields coming from the current timestamp and
// missing trailing fields being padded with their minimum value (1
// for date fields and 0 for time fields). Note that the compiler
// (type synthesis) only allows conversions in which the source and
// destination share some fields. If the dataConversionErrorFlag is
// non-NULL and data is lost when scaling the fractional portion of
// the source value to match the destination fractional precision,
// then the dataConversionErrorFlag is set to
// CONV_RESULT_ROUNDED_DOWN.
//
// This method has been modified as part of the MP Datetime
// Compatibility project. It has been modified to handle non-standard
// datetime types and all combinations of conversions.
// ===================================================================
//
NA_EIDPROC
ex_expr::exp_return_type convDatetimeDatetime(char * target,
Lng32 targetLen,
REC_DATETIME_CODE targetCode,
Lng32 targetScale,
char * source,
Lng32 sourceLen,
REC_DATETIME_CODE sourceCode,
Lng32 sourceScale,
CollHeap *heap,
ComDiagsArea** diagsArea,
short validateFlag,
Lng32 *dataConversionErrorFlag) {
if (dataConversionErrorFlag)
// assume success
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_OK;
// Declare attributes to make use of ExpDatetime convDatetimeDatetime
//
ExpDatetime srcDatetimeOpType;
// Setup attribute for the source.
//
srcDatetimeOpType.setPrecision(sourceCode);
srcDatetimeOpType.setScale((short)sourceScale);
rec_datetime_field dstStartField;
rec_datetime_field dstEndField;
// Get the start and end fields of the given Datetime type.
//
if (ExpDatetime::getDatetimeFields(targetCode,
dstStartField,
dstEndField) != 0) {
ExRaiseSqlError(heap, diagsArea, EXE_INTERNAL_ERROR);
return ex_expr::EXPR_ERROR;
}
// init variable roundedDown to FALSE.
// case 10-020917-7718 RG: Build MX020910, Select incorrect rows with
// param '00:00:10' in predicate.
//
// With optimization turned on (c89, level 2), this variable is not initialized.
// Consequently, it can take a value which is not 0 (TRUE). Since this flag may not
// get set inside srcDatetimeOpType.convDatetimeDatetime(), this var
// maintains this random value after the call. This incorrectly sets the
// dataConversionErroFlag to ex_conv_clause::CONV_RESULT_ROUNDED_DOWN, and can turn
// off the range-serach exclusion flag. As a result, more rows are turned.
//
NABoolean roundedDown = FALSE;
// Convert the source datetime value to the destination datetime
// type.
//
if (srcDatetimeOpType.convDatetimeDatetime(source,
dstStartField,
dstEndField,
(short)targetScale,
target,
targetLen,
validateFlag,
&roundedDown) != 0) {
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_DATETIME_ERROR,NULL,NULL,NULL,NULL,stringToHex(hexstr, sizeof(hexstr), source, sourceLen ));
return ex_expr::EXPR_ERROR;
}
// roundedDown is TRUE when data is lost when scaling the source
// fractional portion of the SECOND field to match the destination
// fractional precision.
//
if (roundedDown == TRUE && dataConversionErrorFlag)
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
return ex_expr::EXPR_OK;
};
///////////////////////////////////////////////////////////////////
// function to convert an ASCII string to double
// The function assumes that source is at least
// sourceLen long. Trailing '\0' is not recongnized
///////////////////////////////////////////////////////////////////
NA_EIDPROC
ex_expr::exp_return_type convAsciiToFloat64(char * target,
char *source,
Lng32 sourceLen,
CollHeap *heap,
ComDiagsArea** diagsArea,
ULng32 flags) {
short err = 0;
double ptarget;
// skip leading and trailing blanks and adjust source and sourceLen
// accordingly
Lng32 i = 0;
for (; i < sourceLen && *source == ' '; i++)
source++;
if (i == sourceLen) {
if ((target) && (flags & CONV_TREAT_ALL_SPACES_AS_ZERO))
{
ptarget = 0;
str_cpy_all(target, (char*)&ptarget, sizeof(double));
return ex_expr::EXPR_OK;
}
// string contains only blanks.
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_STRING_ERROR,NULL,NULL,NULL,NULL,stringToHex(hexstr, sizeof(hexstr), source, sourceLen ));
return ex_expr::EXPR_ERROR;
};
sourceLen -= i;
// we know that we found at least one non-blank character.
// so we just decrement sourceLen till we scanned all
// trailing blanks
while (source[sourceLen - 1] == ' ') {
sourceLen--;
};
enum State {START, SKIP_BLANKS, MANT_BEFORE_SIGN, MANT_AFTER_SIGN,
EXP_START, EXPONENT, ERROR};
Int32 cp = 0;
double mantissa = 0;
double exponent = 0;
NABoolean negMantissa = FALSE;
NABoolean negExponent = FALSE;
Int32 numScale = 0;
NABoolean validNum = FALSE;
State state = START;
NABoolean skipChar;
while (cp < sourceLen)
{
skipChar = FALSE;
// cout << "state = " << state << endl;
switch (state)
{
case START:
if ((source[cp] == '+') || (source[cp] == '-'))
{
if (source[cp] == '-')
negMantissa = TRUE;
state = SKIP_BLANKS;
skipChar = TRUE;
}
else
state = MANT_BEFORE_SIGN;
break;
case SKIP_BLANKS:
if (source[cp] != ' ')
state = MANT_BEFORE_SIGN;
else
skipChar = TRUE;
break;
case MANT_BEFORE_SIGN:
if (source[cp] == '.')
{
state = MANT_AFTER_SIGN;
}
else if ((source[cp] == 'E') || (source[cp] == 'e'))
{
validNum = FALSE;
state = EXP_START;
}
else if ((source[cp] < '0') || (source[cp] > '9'))
state = ERROR;
else
{
if (safe_add_digit_to_double(mantissa,
source[cp] - '0',
&mantissa) != 0)
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, REC_BYTE_F_ASCII,
SQLCHARSETCODE_ISO88591,
REC_FLOAT64, flags);
return ex_expr::EXPR_ERROR;
}
validNum = TRUE;
}
skipChar = TRUE;
break;
case MANT_AFTER_SIGN:
if ((source[cp] == 'E') || (source[cp] == 'e'))
{
if (NOT validNum)
state = ERROR;
else
{
validNum = FALSE;
state = EXP_START;
}
}
else if ((source[cp] < '0') || (source[cp] > '9'))
state = ERROR;
else
{
numScale++;
if (safe_add_digit_to_double(mantissa,
source[cp] - '0',
&mantissa) != 0)
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, REC_BYTE_F_ASCII,
SQLCHARSETCODE_ISO88591,
REC_FLOAT64, flags);
return ex_expr::EXPR_ERROR;
}
validNum = TRUE;
}
skipChar = TRUE;
break;
case EXP_START:
{
if ((source[cp] == '+') || (source[cp] == '-'))
{
if (source[cp] == '-')
negExponent = TRUE;
skipChar = TRUE;
}
state = EXPONENT;
}
break;
case EXPONENT:
{
if ((source[cp] < '0') || (source[cp] > '9'))
state = ERROR;
else
{
if (safe_add_digit_to_double(exponent,
source[cp] - '0',
&exponent) != 0)
{
ExRaiseDetailSqlError(heap, diagsArea,
EXE_NUMERIC_OVERFLOW, source,
sourceLen,
REC_BYTE_F_ASCII,
SQLCHARSETCODE_ISO88591,
REC_FLOAT64, flags);
return ex_expr::EXPR_ERROR;
}
validNum = TRUE;
}
skipChar = TRUE;
}
break;
case ERROR:
{
// string contains only blanks.
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_STRING_ERROR,NULL,NULL,NULL,NULL,stringToHex(hexstr, sizeof(hexstr), source, sourceLen ));
return ex_expr::EXPR_ERROR;
};
break;
default:
state = ERROR;
break;
} // switch state
if ((state != ERROR) && (skipChar))
cp++;
} // while
if (NOT validNum)
{
// LCOV_EXCL_START
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_STRING_ERROR,NULL,NULL,NULL,NULL,stringToHex(hexstr, sizeof(hexstr), source, sourceLen ));
return ex_expr::EXPR_ERROR;
// LCOV_EXCL_STOP
};
double scale = MathPow(10.0, (double)numScale, err);
if (isinf(scale))
{
// LCOV_EXCL_START
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, REC_BYTE_F_ASCII,
SQLCHARSETCODE_ISO88591, REC_FLOAT64, flags);
return ex_expr::EXPR_ERROR;
// LCOV_EXCL_STOP
}
if (err)
{
// LCOV_EXCL_START
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, REC_BYTE_F_ASCII,
SQLCHARSETCODE_ISO88591,REC_FLOAT64, flags);
return ex_expr::EXPR_ERROR;
// LCOV_EXCL_STOP
}
if (negMantissa)
mantissa = - mantissa;
mantissa = mantissa / scale;
if (negExponent)
exponent = - exponent;
exponent = MathPow(10.0, exponent, err);
if (isinf(exponent))
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, REC_BYTE_F_ASCII,
SQLCHARSETCODE_ISO88591,REC_FLOAT64, flags);
return ex_expr::EXPR_ERROR;
}
if (err)
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, REC_BYTE_F_ASCII,
SQLCHARSETCODE_ISO88591,REC_FLOAT64, flags);
return ex_expr::EXPR_ERROR;
}
short ov;
ptarget = MathReal64Mul(mantissa, exponent, &ov);
if (ov)
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, REC_BYTE_F_ASCII,
SQLCHARSETCODE_ISO88591,REC_FLOAT64, flags);
return ex_expr::EXPR_ERROR;
}
if (target)
{
str_cpy_all(target, (char*)&ptarget, sizeof(double));
}
// conversion was OK
return ex_expr::EXPR_OK;
};
NABoolean isNegative(char *source, Lng32 sourceLen, Lng32 &currPos)
{
// skip leading blanks and look for leading sign
NABoolean done = FALSE;
NABoolean negative = FALSE;
while ((NOT done) && (currPos < sourceLen))
{
if ((source[currPos] == '+') || (source[currPos] == '-'))
{
negative = (source[currPos] == '-');
done = TRUE;
currPos++; // skip pass sign
}
else if (source[currPos] == ' ')
currPos++;
else
done = TRUE;
}
return negative;
}
ex_expr::exp_return_type convAsciiToUInt64base(UInt64 &target,
Lng32 targetScale,
char *source,
Lng32 sourceLen,
CollHeap *heap,
ComDiagsArea** diagsArea,
ULng32 flags)
{
NABoolean SignFound = FALSE; // did we find a sign (+/-)
NABoolean DigitsAllowed = TRUE;
NABoolean negative = FALSE; // default is a positive value
NABoolean pointFound = FALSE; // did we find a decimal point
Lng32 currPos = 0; // current position in the string
short digitCnt = 0; // digits found so far
Lng32 sourceScale = 0; // default is a scale of 0
target = 0;
while (currPos < sourceLen)
{
if ((source[currPos] >= '0') && (source[currPos] <= '9'))
{ // process digits
if (!DigitsAllowed)
{
// syntax error in the input
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_STRING_ERROR,NULL,NULL,NULL,NULL,stringToHex(hexstr, sizeof(hexstr), source, sourceLen ));
return ex_expr::EXPR_ERROR;
}
digitCnt++;
// if we've read enough source characters to achieve the needed
// targetScale, then stop appending digits to the target value.
// They would only be thrown away later.
if ( !pointFound || sourceScale < targetScale )
{ // this digit needs to be processed.
// if we found a decimal point before, another digit increases
// the source scale
if (pointFound)
sourceScale++;
Int32 thisDigit = source[currPos] - '0';
if (digitCnt > 18)
{
// check overflow/underflow
if (target > (ULLONG_MAX / 10))
{ // next power of 10 causes an overflow
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, REC_BYTE_F_ASCII,
SQLCHARSETCODE_ISO88591,
REC_BIN64_SIGNED, flags);
return ex_expr::EXPR_ERROR;
}
target *= 10;
Int64 tempMax = ULLONG_MAX;
tempMax -= thisDigit;
// if (target > (LLONG_MAX - thisDigit));
if (target > tempMax)
{ // adding this digit causes an overflow
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, REC_BYTE_F_ASCII,
SQLCHARSETCODE_ISO88591,
REC_BIN64_SIGNED, flags);
return ex_expr::EXPR_ERROR;
}
target = target + (Int64)thisDigit;
} // if digitCnt > 18, check overflow or underflow
else
{
// at this point we never consider overflow
// and target is alway potitive or absolute value
target = target * 10 + thisDigit;
}
} // fi ( sourceScale < targetScale )
}
else if (source[currPos] == ' ')
{ // process blanks
if (digitCnt || pointFound)
// we found already some digits or a decimal point. A blank now
// means, that from now on we should not see any digits anymore.
DigitsAllowed = FALSE;
}
else if ((source[currPos] == '+') || (source[currPos] == '-'))
{ // process sign
// we found already a sign or we found already digits
// or we found a point already.
// A sign is an error now!
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_STRING_ERROR,NULL,NULL,NULL,NULL,stringToHex(hexstr, sizeof(hexstr), source, sourceLen ));
return ex_expr::EXPR_ERROR;
}
else if (source[currPos] == '.')
{ // process decimal point
if (pointFound || !DigitsAllowed)
{
// we found a second decimal point. This is an error
// we are already not allowing anymore digits because of illegal
// blank space(s)
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_STRING_ERROR,NULL,NULL,NULL,NULL,stringToHex(hexstr, sizeof(hexstr), source, sourceLen ));
return ex_expr::EXPR_ERROR;
}
pointFound = TRUE;
}
else
{ // process illegal characters
// if the illegal character is a 'E' or 'e', the input
// might be a float value. Try to convert the input
// to double and then to Int64
if ((source[currPos] == 'E') || (source[currPos] == 'e'))
{
if (currPos == 0)
{
// 'E' alone is not a valid numeric.
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_STRING_ERROR,NULL,NULL,NULL,NULL,stringToHex(hexstr, sizeof(hexstr), source, sourceLen ));
return ex_expr::EXPR_ERROR;
}
double intermediate;
if (convAsciiToFloat64((char*)&intermediate,
source,
sourceLen,
heap,
diagsArea,
flags | CONV_INTERMEDIATE_CONVERSION) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
// scale the intermediate
for (Lng32 i = 0; i < targetScale; i++)
intermediate *= 10.0;
target = (UInt64) intermediate;
return ex_expr::EXPR_OK;
}
else
{
// illegal character in this input string
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_STRING_ERROR,NULL,NULL,NULL,NULL,stringToHex(hexstr, sizeof(hexstr), source, sourceLen ));
return ex_expr::EXPR_ERROR;
}
}
currPos++;
}
// if we didn't find any digits, it is an error
if (!digitCnt)
{
if ((flags & CONV_TREAT_ALL_SPACES_AS_ZERO) &&
(NOT (pointFound || SignFound)))
{
target = 0;
return ex_expr::EXPR_OK;
}
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_STRING_ERROR,NULL,NULL,NULL,NULL,stringToHex(hexstr, sizeof(hexstr), source, sourceLen ));
return ex_expr::EXPR_ERROR;
}
// up- or downscale
if (sourceScale < targetScale)
{
for (Int32 i = 0; i < (targetScale - sourceScale); i++)
{
if (target > (ULLONG_MAX / 10))
{ // next power of 10 causes an overflow
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, REC_BYTE_F_ASCII,
SQLCHARSETCODE_ISO88591,REC_BIN64_SIGNED,
flags);
return ex_expr::EXPR_ERROR;
}
target *= 10;
}
}
else
{
for (Int32 i = 0; i < sourceScale - targetScale; i++)
target /= 10;
}
return ex_expr::EXPR_OK;
}
///////////////////////////////////////////////////////////////////
// function to convert an ASCII string to UInt64
// The function assumes that source is at least
// sourceLen long. Trailing '\0' is not recognized
///////////////////////////////////////////////////////////////////
ex_expr::exp_return_type convAsciiToUInt64(UInt64 &target,
Lng32 targetScale,
char *source,
Lng32 sourceLen,
CollHeap *heap,
ComDiagsArea** diagsArea,
ULng32 flags)
{
NABoolean negative = FALSE; // default is a positive value
Lng32 currPos = 0; // current position in the string
negative = isNegative(source, sourceLen, currPos);
if (negative)
{
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
ex_expr::exp_return_type ert =
convAsciiToUInt64base(target, targetScale, &source[currPos],
sourceLen - currPos,
heap, diagsArea, flags);
if (ert == ex_expr::EXPR_ERROR)
return ert;
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type convAsciiToInt64(Int64 &target,
Lng32 targetScale,
char *source,
Lng32 sourceLen,
CollHeap *heap,
ComDiagsArea** diagsArea,
ULng32 flags)
{
Lng32 currPos = 0; // current position in the string
NABoolean negative = FALSE; // default is a positive value
negative = isNegative(source, sourceLen, currPos);
UInt64 tempTgt = 0;
ex_expr::exp_return_type ert =
convAsciiToUInt64base(tempTgt, targetScale, &source[currPos],
sourceLen - currPos,
heap, diagsArea, flags);
if (ert == ex_expr::EXPR_ERROR)
return ert;
UInt64 maxLongPlus1 = LLONG_MAX ;
maxLongPlus1 ++; // min 64bit long integer is -9223372036854775808
// max 64bit long integer is 9223372036854775807
// so if negative value convert to non-negative value, should check with LLONG_MAX + 1
if ((tempTgt > LLONG_MAX && NOT negative) || (tempTgt > maxLongPlus1) )
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, REC_BYTE_F_ASCII,
SQLCHARSETCODE_ISO88591,
REC_BIN64_SIGNED, flags);
return ex_expr::EXPR_ERROR;
}
if (NOT negative)
{
target = (Int64)tempTgt;
return ex_expr::EXPR_OK;
}
/* remove below code according to discussion in github
* https://github.com/apache/incubator-trafodion/pull/706
* with above validation, below checking is no longer needed
* comment out
if (-(Int64)tempTgt < LLONG_MIN)
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, REC_BYTE_F_ASCII,
SQLCHARSETCODE_ISO88591,
REC_BIN64_SIGNED, flags);
return ex_expr::EXPR_ERROR;
}
*/
target = - (Int64)tempTgt;
return ex_expr::EXPR_OK;
}
//////////////////////////////////////////////////////////////////
// function to convert an Int64 to Decimal
///////////////////////////////////////////////////////////////////
NA_EIDPROC
ex_expr::exp_return_type convInt64ToDec(char *target,
Lng32 targetLen,
Int64 source,
CollHeap *heap,
ComDiagsArea** diagsArea) {
ULng32 flags = 0;
NABoolean negative = (source < 0);
Lng32 currPos = targetLen - 1;
if (negative && (currPos >= 0)) {
if (source == LLONG_MIN) {
// before we can convert this to a positive number, we have to
// work on the first digit. Otherwise, we would cause an overflow.
Int32 temp = (Int32)(source % 10);
target[currPos--] = (char)('0' + (temp < 0 ? -temp: temp));
source /= 10;
};
// now make source positive
source = -source;
};
while (source != 0) {
if (currPos < 0) {
// target is not long enough - overflow
ExRaiseDetailSqlError(heap, diagsArea, EXE_STRING_OVERFLOW,
(char*)&source,
sizeof(Int64), REC_BIN64_SIGNED, 0, REC_DECIMAL_LSE, flags);
return ex_expr::EXPR_ERROR;
};
#pragma nowarn(1506) // warning elimination
target[currPos--] = '0' + (char)(source % 10);
#pragma warn(1506) // warning elimination
source /= 10;
};
// zero pad the leading spaces
while (currPos >= 0)
target[currPos--] = '0';
if (negative)
target[0] |= 0200;
return ex_expr::EXPR_OK;
}
///////////////////////////////////////////////////////////////////
// function to convert an ASCII string to DEC.
// Conversion is ASCII -> DEC, and caller has to pass
// &target[0], targetLen
// Also, this function always sets the sign bit for DEC if the
// source is negative.
// The function assumes that source is at least
// sourceLen long. Trailing '\0' is not recongnized
///////////////////////////////////////////////////////////////////
NA_EIDPROC
ex_expr::exp_return_type convAsciiToDec(char *target,
Lng32 targetType,
Lng32 targetLen,
Lng32 targetScale,
char *source,
Lng32 sourceLen,
char offset,
CollHeap *heap,
ComDiagsArea** diagsArea,
ULng32 flags) {
NABoolean negative = FALSE; // default is a positive value
Lng32 sourceStart = 0; // start of source after skipping 0 and ' '
Lng32 sourceScale = 0; // by default the scale is 0
Lng32 targetPos = targetLen - 1; // current positon in the target
// skip leading blanks
while ((sourceStart < sourceLen) && (source[sourceStart] == ' '))
sourceStart++;
// only blanks found, error
if (sourceStart == sourceLen) {
// LCOV_EXCL_START
if (flags & CONV_TREAT_ALL_SPACES_AS_ZERO)
{
// pad the target with zeros
while (targetPos >= 0)
#pragma nowarn(1506) // warning elimination
target[targetPos--] = '0' - offset;
#pragma warn(1506) // warning elimination
return ex_expr::EXPR_OK;
}
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_STRING_ERROR,NULL,NULL,NULL,NULL,stringToHex(hexstr, sizeof(hexstr), source, sourceLen ));
return ex_expr::EXPR_ERROR;
};
// LCOV_EXCL_STOP
// skip trailing blanks. We know that we found already some
// non-blank character, thus sourceLen is always > sourceStart
while (source[sourceLen - 1] == ' ')
sourceLen--;
// if the string contains 'e' or 'E' it actually represents
// a float value. Do a ASCII -> DOUBLE -> DEC
// use a for-loop to find the 'e'. If we find one, we do the
// described conversion and return. If we do not find one,
// we go on with this function.
// Also, start at the end of the string, if we have an 'e' it
// is probably closer to the end.
for (Lng32 i = sourceLen - 1; i >= sourceStart; i--) {
if (source[i] == 'E' || source[i] == 'e') {
// found a float representation.
double intermediate;
if (convAsciiToFloat64((char*)&intermediate,
&source[sourceStart],
sourceLen - sourceStart,
heap,
diagsArea,
flags | CONV_INTERMEDIATE_CONVERSION) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
// scale the intermediate
for (Lng32 j = 0; j < targetScale; j++) {
// LCOV_EXCL_START
intermediate *= 10.0;
if ((intermediate < LLONG_MIN) || (intermediate > LLONG_MAX)) {
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, REC_BYTE_F_ASCII,
SQLCHARSETCODE_ISO88591,
REC_DECIMAL_UNSIGNED, flags);
return ex_expr::EXPR_ERROR;
// LCOV_EXCL_STOP
};
}
if (convInt64ToDec(target,
targetLen,
(Int64) intermediate,
heap,
diagsArea) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
return ex_expr::EXPR_OK;
}
}
// the string does not represent a float value. Go on with
// the processing
Lng32 sourcePos = sourceLen - 1; // current position in the string
// check for sign
if (source[sourceStart] == '+')
sourceStart++;
else if (source[sourceStart] == '-') {
negative = TRUE;
sourceStart++;
};
// skip leading zeros
while((source[sourceStart] == '0') && (sourceStart < sourceLen))
sourceStart++;
// only zeros found, target is 0
if (sourceStart == sourceLen) {
#pragma nowarn(1506) // warning elimination
str_pad(target, targetLen, '0' - offset);
#pragma warn(1506) // warning elimination
return ex_expr::EXPR_OK;
};
// determine the scale of the source
Lng32 index = sourceStart;
Lng32 pointPos = -1;
while ((index < sourceLen) && pointPos < 0) {
if (source[index] == '.')
pointPos = index;
else
index++;
};
if (pointPos >= 0)
// determine sourceScale
sourceScale = sourceLen - pointPos - 1;
NABoolean raiseOverflowWarning = FALSE;
// procress digits, start from end
while ((sourcePos >= sourceStart) && (targetPos >= 0)) {
// add zeros to adjust scale
if (targetScale > sourceScale) {
#pragma nowarn(1506) // warning elimination
target[targetPos--] = '0' - offset;
#pragma warn(1506) // warning elimination
targetScale--;
}
else if (targetScale < sourceScale) {
// skip source digits
// but at least one of the digits skipped is not a '0', then
// a EXE_NUMERIC_OVERFLOW warning needs to be raised
if (source[sourcePos] != '0')
raiseOverflowWarning = TRUE;
sourcePos--;
sourceScale--;
}
else if (sourcePos == pointPos) {
// simply skip the decimal point
sourcePos--;
}
else {
// if source is not a digit, we have an error
if (source[sourcePos] < '0' || source[sourcePos] > '9') {
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_STRING_ERROR,NULL,NULL,NULL,NULL,stringToHex(hexstr, sizeof(hexstr), source, sourceLen ));
return ex_expr::EXPR_ERROR;
};
// copy source to target
#pragma nowarn(1506) // warning elimination
target[targetPos--] = source[sourcePos--] - offset;
#pragma warn(1506) // warning elimination
};
};
if (raiseOverflowWarning)
ExRaiseSqlWarning(heap, diagsArea, EXE_NUMERIC_OVERFLOW);
// we might be right on the decimal point. Skip it before test for
// overflow
if (sourcePos == pointPos)
sourcePos--;
// if we couldn't copy all digits, we had an overflow
if (sourcePos >= sourceStart) {
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, REC_BYTE_F_ASCII,
SQLCHARSETCODE_ISO88591, (short)targetType,
flags);
return ex_expr::EXPR_ERROR;
};
// left pad the target with zeros
while (targetPos >= 0)
#pragma nowarn(1506) // warning elimination
target[targetPos--] = '0' - offset;
#pragma warn(1506) // warning elimination
// add sign
if (negative)
target[0] |= 0200;
return ex_expr::EXPR_OK;
};
///////////////////////////////////////////////////////////////////
// function to convert a DOUBLE to BIGNUM.
///////////////////////////////////////////////////////////////////
NA_EIDPROC
ex_expr::exp_return_type convDoubleToBigNum(char *target,
Lng32 targetLen,
Lng32 targetType,
Lng32 targetPrecision,
Lng32 targetScale,
double source,
CollHeap *heap,
ComDiagsArea** diagsArea)
{
SimpleType sourceAttr(REC_FLOAT64, sizeof(double), 0, 0,
ExpTupleDesc::SQLMX_FORMAT,
8, 0, 0, 0, Attributes::NO_DEFAULT, 0);
char * opData[2];
opData[0] = target;
opData[1] = (char*)&source;
NABoolean isSigned = (targetType == REC_NUM_BIG_SIGNED);
BigNum bn(targetLen, targetPrecision, (short)targetScale, isSigned);
bn.setTempSpaceInfo(ITM_CAST, 0, targetLen);
if (bn.castFrom(&sourceAttr, opData, heap, diagsArea) != 0)
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
(char*)&source,
8, REC_FLOAT64, 0, targetType, 0 /* flags */);
return ex_expr::EXPR_ERROR;
}
return ex_expr::EXPR_OK;
}
///////////////////////////////////////////////////////////////////
// function to convert an ASCII string to BIGNUM.
//
// First convert from ASCII to LARGEDEC, then convert from LARGEDEC
// to BIGNUM
///////////////////////////////////////////////////////////////////
NA_EIDPROC
ex_expr::exp_return_type convAsciiToBigNum(char *target,
Lng32 targetLen,
Lng32 targetType,
Lng32 targetPrecision,
Lng32 targetScale,
char *source,
Lng32 sourceLen,
NAMemory *heap,
ComDiagsArea** diagsArea,
ULng32 flags)
{
// if the string contains 'e' or 'E' it actually represents
// a float value. Do a ASCII -> DOUBLE -> BIGNUM.
// use a for-loop to find the 'e'. If we find one, we do the
// described conversion and return. If we do not find one,
// we go on with this function.
// Also, start at the end of the string, if we have an 'e' it
// is probably closer to the end.
for (Lng32 i = sourceLen - 1; i >= 0; i--) {
if (source[i] == 'E' || source[i] == 'e') {
// found a float representation.
// convert ascii to DOUBLE.
double intermediateDouble;
if (convDoIt(source, sourceLen, REC_BYTE_F_ASCII, 0, 0,
(char*)&intermediateDouble, 8, REC_FLOAT64, 0, 0,
NULL, 0, heap, diagsArea) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
if ((targetType == REC_NUM_BIG_UNSIGNED) &&
(intermediateDouble < 0))
{
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
// convert DOUBLE to bignum
SimpleType sourceAttr(REC_FLOAT64, sizeof(double), 0, 0,
ExpTupleDesc::SQLMX_FORMAT,
8, 0, 0, 0, Attributes::NO_DEFAULT, 0);
char * opData[2];
opData[0] = target;
opData[1] = (char*)&intermediateDouble;
BigNum bn(targetLen, targetPrecision, (short)targetScale,
(targetType == REC_NUM_BIG_UNSIGNED ? 1 : 0));
bn.setTempSpaceInfo(ITM_CAST, 0, targetLen);
if (bn.castFrom(&sourceAttr, opData, heap, diagsArea) != 0) {
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
(char*)&intermediateDouble,
8, REC_FLOAT64, 0, (short)targetType, flags);
return ex_expr::EXPR_ERROR;
}
return ex_expr::EXPR_OK;
}
} // for
// Convert from ASCII to an intermediate LARGEDEC, using the function convAsciiToDec().
// To understand this function call, it will be helpful to review the
// comments in its definition earlier.
char * intermediateLargeDec = new (heap) char[targetPrecision + 1];
if (convAsciiToDec(intermediateLargeDec + 1,
targetType,
targetPrecision,
targetScale,
source,
sourceLen,
'0',
heap,
diagsArea,
flags | CONV_INTERMEDIATE_CONVERSION) != ex_expr::EXPR_OK) {
NADELETEBASIC(intermediateLargeDec, (heap));
return ex_expr::EXPR_ERROR;
}
if ((targetType == REC_NUM_BIG_UNSIGNED) &&
(intermediateLargeDec[1] &0200))
{
NADELETEBASIC(intermediateLargeDec, (heap));
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
// Set the sign byte in the intermediate LARGEDEC.
if (intermediateLargeDec[1] &0200) {
// reset the bit
intermediateLargeDec[1] &= 0177;
intermediateLargeDec[0] = '-';
}
else
intermediateLargeDec[0] = '+';
// Convert from the intermediate LARGEDEC to BIGNUM using a BigNumHelper method.
short retCode = BigNumHelper::ConvBcdToBigNumWithSignHelper(targetPrecision + 1,
targetLen,
intermediateLargeDec,
target);
NADELETEBASIC(intermediateLargeDec, (heap));
if (retCode == -1) {
// target is not long enough - overflow
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, REC_BYTE_F_ASCII,
SQLCHARSETCODE_ISO88591,(short)targetType,
flags);
return ex_expr::EXPR_ERROR;
};
return ex_expr::EXPR_OK;
}
static rec_datetime_field getIntervalStartField(Lng32 datatype)
{
switch (datatype) {
case REC_INT_YEAR: return REC_DATE_YEAR;
case REC_INT_MONTH: return REC_DATE_MONTH;
case REC_INT_YEAR_MONTH: return REC_DATE_YEAR;
case REC_INT_DAY: return REC_DATE_DAY;
case REC_INT_HOUR: return REC_DATE_HOUR;
case REC_INT_DAY_HOUR: return REC_DATE_DAY;
case REC_INT_MINUTE: return REC_DATE_MINUTE;
case REC_INT_HOUR_MINUTE: return REC_DATE_HOUR;
case REC_INT_DAY_MINUTE: return REC_DATE_DAY;
case REC_INT_SECOND: return REC_DATE_SECOND;
case REC_INT_MINUTE_SECOND: return REC_DATE_MINUTE;
case REC_INT_HOUR_SECOND: return REC_DATE_HOUR;
case REC_INT_DAY_SECOND: return REC_DATE_DAY;
default:
break;
}
return REC_DATE_YEAR;
}
NA_EIDPROC
static rec_datetime_field getIntervalEndField(Lng32 datatype)
{
switch (datatype) {
case REC_INT_YEAR: return REC_DATE_YEAR;
case REC_INT_MONTH: return REC_DATE_MONTH;
case REC_INT_YEAR_MONTH: return REC_DATE_MONTH;
case REC_INT_DAY: return REC_DATE_DAY;
case REC_INT_HOUR: return REC_DATE_HOUR;
case REC_INT_DAY_HOUR: return REC_DATE_HOUR;
case REC_INT_MINUTE: return REC_DATE_MINUTE;
case REC_INT_HOUR_MINUTE: return REC_DATE_MINUTE;
case REC_INT_DAY_MINUTE: return REC_DATE_MINUTE;
case REC_INT_SECOND: return REC_DATE_SECOND;
case REC_INT_MINUTE_SECOND: return REC_DATE_SECOND;
case REC_INT_HOUR_SECOND: return REC_DATE_SECOND;
case REC_INT_DAY_SECOND: return REC_DATE_SECOND;
default:
break;
}
return REC_DATE_YEAR;
}
///////////////////////////////////////////////////////////////////
// function to convert interval field ASCII string to Int64
// The function reads at most sourceLen number of characters.
// Or until it encounters a non-digit character and sets the
// sourceLen to the actual length of the string read if it is
// smaller than sourceLen.
// This function is used for ASCII to INTERVAL conversions only.
// Blanks and sign are already removed.
///////////////////////////////////////////////////////////////////
NA_EIDPROC
ex_expr::exp_return_type convAsciiFieldToInt64(Int64 &target,
Lng32 targetScale,
char *source,
Lng32 &sourceLen,
CollHeap *heap,
ComDiagsArea** diagsArea,
ULng32 flags)
{
Lng32 currPos = 0; // current position in the string
target = 0; // result
while ((currPos < sourceLen) && ((source[currPos] >= '0') &&
(source[currPos] <= '9')))
{
#pragma nowarn(1506) // warning elimination
short thisDigit = source[currPos] - '0';
#pragma warn(1506) // warning elimination
if (target > (LLONG_MAX / 10))
{ // next power of 10 causes an overflow
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, REC_BYTE_F_ASCII,
SQLCHARSETCODE_ISO88591, REC_BIN64_SIGNED,
flags);
return ex_expr::EXPR_ERROR;
}
target *= 10;
if (target > LLONG_MAX - thisDigit)
{ // adding this digit causes an overflow
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, REC_BYTE_F_ASCII,
SQLCHARSETCODE_ISO88591, REC_BIN64_SIGNED,
flags);
return ex_expr::EXPR_ERROR;
}
target += thisDigit;
currPos++;
}
if (!currPos)
{
// No digits were found
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_STRING_ERROR,NULL,NULL,NULL,NULL,stringToHex(hexstr, sizeof(hexstr), source, sourceLen ));
return ex_expr::EXPR_ERROR;
}
// return the number of digits read
sourceLen = currPos;
return ex_expr::EXPR_OK;
};
///////////////////////////////////////////////////////////////////
// function to convert an ASCII string to an interval datatype.
///////////////////////////////////////////////////////////////////
NA_EIDPROC
ex_expr::exp_return_type convAsciiToInterval(char *target,
Lng32 targetLen,
Lng32 targetDatatype,
Lng32 leadingPrecision,
Lng32 fractionPrecision,
char *source,
Lng32 sourceLen,
NABoolean allowSignInInterval,
CollHeap *heap,
ComDiagsArea** diagsArea,
ULng32 flags)
{
// skip leading and trailing blanks and adjust source and sourceLen
// accordingly
while ((sourceLen > 0) && (*source == ' '))
{
source++;
sourceLen--;
}
if (!sourceLen)
{
// string contains no digits
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_INTERVAL_ERROR);
return ex_expr::EXPR_ERROR;
};
NABoolean negInterval = FALSE;
if ((source[0] == '-') || (source[0] == '+')) {
if (NOT allowSignInInterval)
{
// string starts with a sign - not allowed
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_INTERVAL_ERROR);
return ex_expr::EXPR_ERROR;
}
else
{
if (source[0] == '-')
negInterval = TRUE;
source += 1;
sourceLen -= 1;
}
}
// we know that we found at least one non-blank character.
// so we just decrement sourceLen till we scanned all
// trailing blanks
while (source[sourceLen - 1] == ' ')
sourceLen--;
char delimiter[] = "^-^:::";
unsigned short maxFieldValue[] = { 0, 11, 0, 23, 59, 59 };
rec_datetime_field start = getIntervalStartField(targetDatatype);
rec_datetime_field end = getIntervalEndField(targetDatatype);
// convert the first field
Int64 intermediate;
Lng32 fieldLen = leadingPrecision;
if (fieldLen > sourceLen)
fieldLen = sourceLen; // so we don't read garbage past end of string
if (convAsciiFieldToInt64(intermediate,
0, // targetScale
source,
fieldLen,
heap,
diagsArea,
flags | CONV_INTERMEDIATE_CONVERSION) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
Lng32 strIndex = fieldLen;
Int64 fieldValue;
for (Int32 field = start+1; field <= end; field++)
{
Int32 index = field - REC_DATE_YEAR;
// Make sure there is still some string left before we look
// for the delimiter. The '+1' in the test also makes sure
// there is at least one character after the delimiter.
// Without the '+1', we get a strange string conversion
// error, EXE_CONVERT_STRING_ERROR, instead of the more
// reasonable interval conversion error,
// EXE_CONVERT_INTERVAL_ERROR, on interval strings like
// '20-'. Though interval strings like '20-hithere' will
// still get EXE_CONVERT_STRING_ERROR.
if (strIndex + 1 >= sourceLen)
{
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_INTERVAL_ERROR);
return ex_expr::EXPR_ERROR;
}
// get the delimiter preceding this field
if (source[strIndex] != delimiter[index])
{
// HOUR can be preceded by either ':' or ' '
if ((field != REC_DATE_HOUR) || (source[strIndex] != ' '))
{
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_INTERVAL_ERROR);
return ex_expr::EXPR_ERROR;
}
}
strIndex++; // step over delimiter
fieldLen = 2;
if (fieldLen > sourceLen - strIndex)
fieldLen = sourceLen - strIndex; // don't go off end of string
// convert the next field
if (convAsciiFieldToInt64(fieldValue,
0, // targetScale
&source[strIndex],
fieldLen,
heap,
diagsArea,
flags | CONV_INTERMEDIATE_CONVERSION) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
if (fieldValue > maxFieldValue[index])
{
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_INTERVAL_ERROR);
return ex_expr::EXPR_ERROR;
}
strIndex += fieldLen;
intermediate = intermediate * (maxFieldValue[index]+1) + fieldValue;
}
// adjust the value for fractionPrecision
for (short i = 0; i < fractionPrecision; i++)
{
intermediate *= 10;
}
// if the end field is SECOND, it may have a fractional part
if ((end == REC_DATE_SECOND) && (source[strIndex] == '.'))
{
Lng32 sourcePrecision = (sourceLen - strIndex - 1);
ULng32 fraction = 0;
if (sourcePrecision)
{
if (convDoIt(&source[strIndex+1],
sourcePrecision, // sourceLen
REC_BYTE_F_ASCII,
0, // sourcePrecision
0, // sourceScale
(char *) &fraction,
4, // targetLen
REC_BIN32_UNSIGNED,
0, // targetPrecision
0, // targetScale
NULL, // varCharLen
0, // varCharLenSize
heap,
diagsArea,
CONV_ASCII_BIN32U,
0,
flags | CONV_INTERMEDIATE_CONVERSION) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
};
// scale up or down if necessary
while (sourcePrecision < fractionPrecision)
{
fraction *= 10;
sourcePrecision++;
}
ULng32 oldFraction = fraction;
ULng32 scaleDownValue = 1;
while (sourcePrecision > fractionPrecision)
{
fraction /= 10;
scaleDownValue *= 10;
sourcePrecision--;
}
// Detect if meaningful scale truncation has occured. If so, raise an error
if (oldFraction > (fraction * scaleDownValue)) {
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_INTERVAL_ERROR);
return ex_expr::EXPR_ERROR;
}
intermediate += fraction;
}
else
{
// check if the string is completely converted
if (strIndex != sourceLen)
{
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_INTERVAL_ERROR);
return ex_expr::EXPR_ERROR;
}
}
switch (targetLen)
{
case SQL_SMALL_SIZE:
if ((intermediate < SHRT_MIN) || (intermediate > SHRT_MAX))
{
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_INTERVAL_ERROR);
return ex_expr::EXPR_ERROR;
};
if (negInterval)
#pragma nowarn(1506) // warning elimination
*(Target<short> *)target = -(short)intermediate;
#pragma warn(1506) // warning elimination
else
*(Target<short> *)target = (short)intermediate;
break;
case SQL_INT_SIZE:
if ((intermediate < INT_MIN) || (intermediate > INT_MAX))
{
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_INTERVAL_ERROR);
return ex_expr::EXPR_ERROR;
};
if (negInterval)
*(Target<Int32> *)target = -(Int32)intermediate;
else
*(Target<Int32> *)target = (Int32)intermediate;
break;
case SQL_LARGE_SIZE:
if (negInterval)
*(Target<Int64> *)target = -intermediate;
else
*(Target<Int64> *)target = intermediate;
break;
default:
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_INTERVAL_ERROR);
return ex_expr::EXPR_ERROR;
}
return ex_expr::EXPR_OK;
};
///////////////////////////////////////////////////////////////////
// function to convert a INTERVAL to a string.
///////////////////////////////////////////////////////////////////
NA_EIDPROC
ex_expr::exp_return_type convIntervalToAscii(char *source,
Lng32 sourceLen,
Lng32 leadingPrecision,
Lng32 fractionPrecision,
short sourceType,
char *inTarget,
Lng32 inTargetLen,
Lng32 inTargetPrecision, // max chars allowed
char *varCharLen,
Lng32 varCharLenSize,
NABoolean leftPad,
CollHeap *heap,
ComDiagsArea** diagsArea)
{
ULng32 flags = 0;
char delimiter[] = "^-^ ::";
unsigned short maxFieldValue[] = { 0, 11, 0, 23, 59, 59 };
Lng32 realTargetLen;
Lng32 inTargetChars = inTargetLen;
Int16 trgType;
if (varCharLenSize)
trgType = REC_BYTE_V_ASCII;
else
trgType = REC_BYTE_F_ASCII;
rec_datetime_field startField = getIntervalStartField(sourceType);
rec_datetime_field endField = getIntervalEndField(sourceType);
Int64 value;
switch (sourceLen)
{
case SQL_SMALL_SIZE:
{
short temp;
str_cpy_all((char *) &temp, source, sourceLen);
value = temp;
break;
}
case SQL_INT_SIZE:
{
Lng32 temp;
str_cpy_all((char *) &temp, source, sourceLen);
value = temp;
break;
}
case SQL_LARGE_SIZE:
str_cpy_all((char *) &value, source, sourceLen);
break;
default:
return ex_expr::EXPR_ERROR;
}
char sign = '+';
if (value < 0)
{
sign = '-';
value = -value;
}
// 1 for -ve sign, each field is 2 + delimiter
realTargetLen = (sign == '-' ? 1 : 0)
+ leadingPrecision + (endField - startField) * 3;
short targetIndex = (short) realTargetLen;
if (fractionPrecision)
realTargetLen += fractionPrecision + 1; // 1 for '.'
if (inTargetPrecision)
{
assert(inTargetPrecision <= inTargetLen);
inTargetChars = inTargetPrecision;
}
if (inTargetChars < realTargetLen)
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_STRING_OVERFLOW,
source, sourceLen, sourceType, fractionPrecision, trgType, flags
);
return ex_expr::EXPR_ERROR;
}
Lng32 targetLen = inTargetChars;
char * target = inTarget;
if ((leftPad) && (targetLen > realTargetLen))
{
// left blankpad the target.
for (Int32 i = 0; i < (targetLen - realTargetLen); i++)
{
target[i] = ' ';
}
// switch target and targetLen to be equal to realTargetLen.
target = inTarget + (targetLen - realTargetLen);
targetLen = realTargetLen;
}
Int64 factor = 1;
Int64 fieldVal = 0;
if (fractionPrecision)
{
// realTargetLen += fractionPrecision + 1; // 1 for '.'
for (UInt32 i = fractionPrecision; i > 0; i--)
{
factor *= 10;
}
fieldVal = value;
value = value / factor;
fieldVal -= value * factor;
}
while (targetLen < realTargetLen)
{
// cut fraction till it fits. At this point we know that
// precision = 0 will fit
fieldVal /= 10;
fractionPrecision--;
realTargetLen--;
if (!fractionPrecision)
realTargetLen--; // remove '.'
};
// if target is fixed length, fill target string flushed right
if (!varCharLenSize) {
for (Int32 i = 0; i < (targetLen - realTargetLen); i++, target++)
*target = ' ';
// If target is actually UTF8, we must put filler spaces in rest of target
if ( target < (inTarget + inTargetLen) )
str_pad(target, inTarget + inTargetLen - target, ' ');
};
// convert fraction part if any. targetIndex was set earlier
if (fractionPrecision)
{
targetIndex += 1; // 1 for '.'
str_pad(target+targetIndex, fractionPrecision, '0');
if (convInt64ToAscii(target + targetIndex,
fractionPrecision, // targetLen
0,
0,
(Int64) fieldVal,
0, // scale,
NULL, // varCharLen
0, // varCharLenSize
'0', // filler character
FALSE,
TRUE, // leftPad
FALSE,
heap,
diagsArea) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
targetIndex--;
target[targetIndex] = '.';
};
// Now rest of the fields except leading field...
for (Int32 field = endField; field > startField; field--)
{
Int32 index = field - REC_DATE_YEAR; // zero-based array index!
factor = (short)maxFieldValue[index]+1;
fieldVal = value;
value = value / factor;
fieldVal -= value * factor;
targetIndex -= 2;
if (convInt64ToAscii(target + targetIndex,
2, // targetLen
0,
0,
(Int64) fieldVal,
0, // scale,
NULL, // varCharLen
0, // varCharLenSize
'0', // filler character
FALSE,
TRUE, // leftPad
FALSE,
heap,
diagsArea) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
targetIndex--;
target[targetIndex] = delimiter[index];
};
// leading field
if (convInt64ToAscii(target + (sign == '-' ? 1 : 0),
leadingPrecision, // targetLen
0,
0,
(Int64) value,
0, // scale,
NULL, // varCharLen
0, // varCharLenSize
' ', // filler character
FALSE,
TRUE, // leftPad
FALSE,
heap,
diagsArea) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
if (sign == '-')
{
// Sign goes here.
// convInt64ToAscii() writes getDigitCount(value) number of digits
// space padded on the left, between target + 1 and
// target + leadingPrecision character positions.
// the following is one position to the left of the most significant
// digit and this is where sign should be.
char *sp = (target + leadingPrecision - getDigitCount(value));
*sp = '-';
// Further to the left of the sign there can only be just one more
// character (because we pass target + 1 to convInt64ToAscii). When
// the sign is to the right of the target, there is this extra character
// which may contain garbage, so we need to clear it.
if (sp > target)
*target = ' ';
}
// else
// {
// target[0] = ' ';
// }
// set length field for variable length targets
if (varCharLenSize)
{
if (varCharLenSize == sizeof(Lng32))
str_cpy_all(varCharLen, (char *) &realTargetLen, sizeof(Lng32));
else
{
short VCLen = (short) realTargetLen;
str_cpy_all(varCharLen, (char *) &VCLen, sizeof(short));
};
};
return ex_expr::EXPR_OK;
};
///////////////////////////////////////////////////////////////////
// function to convert a BIGNUM to Int64
///////////////////////////////////////////////////////////////////
NA_EIDPROC
ex_expr::exp_return_type convBigNumToInt64(Int64 *target,
char *source,
Lng32 sourceLen,
NAMemory *heap,
ComDiagsArea** diagsArea,
ULng32 flags)
{
short retCode = BigNumHelper::ConvBigNumWithSignToInt64Helper(sourceLen,
source,
(void*)target,
FALSE);
if (retCode == -1) {
// target is not long enough - overflow
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, REC_NUM_BIG_SIGNED, 0, REC_BIN64_SIGNED,
flags);
return ex_expr::EXPR_ERROR;
};
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type convBigNumToUInt64(UInt64 *target,
char *source,
Lng32 sourceLen,
NAMemory *heap,
ComDiagsArea** diagsArea,
ULng32 flags)
{
short retCode = BigNumHelper::ConvBigNumWithSignToInt64Helper(sourceLen,
source,
(void*)target,
TRUE);
if (retCode == -1) {
// target is not long enough - overflow
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, REC_NUM_BIG_SIGNED, 0, REC_BIN64_UNSIGNED,
flags);
return ex_expr::EXPR_ERROR;
};
return ex_expr::EXPR_OK;
}
///////////////////////////////////////////////////////////////////
// function to convert a BIGNUM to Int64 and scale it, returning
// information about the conversion to the caller (e.g. truncations,
// overflows). The conversion status information is returned in the
// return code instead of in the ComDiagsArea; if the caller wishes
// an exception, then the caller must convert the return code to
// an appropriate exception. In the event of overflow, a maximum
// or minimum value is returned.
///////////////////////////////////////////////////////////////////
NA_EIDPROC
ex_conv_clause::ConvResult convBigNumToInt64AndScale(Int64 *target,
char *source,
Lng32 sourceLen,
Lng32 exponent,
NAMemory * heap)
{ short retCode = BigNumHelper::ConvBigNumWithSignToInt64AndScaleHelper(sourceLen,
source,
target,
exponent,
heap);
// The retCode can have 5 possible values (see the helper method for details):
// 0: the conversion was ok
// 1: the result was rounded up to LLONG_MIN
// 2: the result was rounded down to LLONG_MAX
// 3: the result was rounded up
// 4: the result was rounded down
switch (retCode) {
case 1: return ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
case 2: return ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
case 3: return ex_conv_clause::CONV_RESULT_ROUNDED_UP;
case 4: return ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
default:// retCode == 0
return ex_conv_clause::CONV_RESULT_OK;
}
}
///////////////////////////////////////////////////////////////////
// function to convert a LARGEDEC to DEC (signed or unsigned),
// with scaling -- returns a return code indicating whether
// the result is equal to the original or if rounding occurred
///////////////////////////////////////////////////////////////////
NA_EIDPROC
SQLEXP_LIB_FUNC
ex_conv_clause::ConvResult convLargeDecToDecAndScale(char *target,
Lng32 targetLen,
char *source,
Lng32 sourceLen,
NABoolean resultUnsigned,
Lng32 exponent)
{
ex_conv_clause::ConvResult rc =
ex_conv_clause::CONV_RESULT_OK; // assume success
NABoolean negative = (source[0] == '-');
if ((resultUnsigned) && (negative))
{
// we are trying to convert a negative number to an
// unsigned target - set to minimum (unsigned) value
str_pad(target, targetLen, '0');
return ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
// at this point, we know that the source is non-negative or
// that the target is signed
// if we are scaling up, truncate the source; remember if any
// non-zero digits were truncated
NABoolean significantTruncationOccurred = FALSE;
if (exponent < 0)
{
Lng32 truncatedLen = -exponent;
if (truncatedLen >= sourceLen)
truncatedLen = sourceLen - 1; // everything was truncated!
sourceLen -= truncatedLen;
char *truncatedPart = &source[sourceLen];
// look for a non-zero digit in the truncated part (anywhere)
Lng32 i = truncatedLen-1;
for (; (i >= 0) && (truncatedPart[i] == 0); i--) ;
if (i >= 0) // if we found one...
significantTruncationOccurred = TRUE;
exponent = 0; // to make later logic easier
}
// determine length of source (skip leading zeros)
Lng32 sourcePos = 1;
while ((sourcePos < sourceLen) && (source[sourcePos] == 0))
sourcePos++;
Lng32 copyLen = sourceLen - sourcePos;
// if source is still too big, overflow
if (copyLen > targetLen - exponent)
{
// set target to maximum (or minimum) value
str_pad(target,targetLen, '9');
if (negative) // if source is negative
{
// note that we know target is signed in this case,
// so the minimum value is simply -(maximum value)
target[0] |= 0200; // turn on sign bit
return ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
// else we know it's the maximum
return ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
// source fits in target, copy and left-pad target with zero if
// necessary
Lng32 targetPos = targetLen - copyLen - exponent;
str_pad(target, targetPos, '0');
while (sourcePos < sourceLen)
#pragma nowarn(1506) // warning elimination
target[targetPos++] = source[sourcePos++] + '0';
#pragma warn(1506) // warning elimination
// do any scaling down needed
while (exponent > 0)
{
target[targetPos++] = '0';
exponent--;
}
if (negative) // if source was negative
target[0] |= 0200; // turn on sign bit
// change return code if significant truncation occurred
if (significantTruncationOccurred)
{
if (negative)
rc = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
else
rc = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
return rc;
};
///////////////////////////////////////////////////////////////////
// function to convert a BIGNUM to DEC (signed or unsigned),
// with scaling -- returns a return code indicating whether
// the result is equal to the original or if rounding occurred
//
// We first convert from BIGNUM to LARGEDEC, then convert from LARGEDEC
// to DEC and scale
///////////////////////////////////////////////////////////////////
NA_EIDPROC
SQLEXP_LIB_FUNC
ex_conv_clause::ConvResult convBigNumToDecAndScale(char *target,
Lng32 targetLen,
char *source,
Lng32 sourceLen,
Lng32 sourcePrecision,
NABoolean resultUnsigned,
Lng32 exponent,
NAMemory * heap)
{
char * intermediateLargeDec = new (heap) char[sourcePrecision + 1]; // one extra byte for the sign.
BigNumHelper::ConvBigNumWithSignToBcdHelper(sourceLen,
sourcePrecision + 1,
source,
intermediateLargeDec,
heap);
// Convert from large dec to dec and scale.
ex_conv_clause::ConvResult retValue = convLargeDecToDecAndScale(target,
targetLen,
intermediateLargeDec,
sourcePrecision + 1,
resultUnsigned,
exponent);
NADELETEBASIC(intermediateLargeDec, (heap));
return retValue;
}
///////////////////////////////////////////////////////////////////
// function to convert a BIGNUM to BIGNUM
///////////////////////////////////////////////////////////////////
NA_EIDPROC
ex_expr::exp_return_type convBigNumToBigNum(char *target,
Lng32 targetLen,
Lng32 targetType,
Lng32 targetPrecision,
char *source,
Lng32 sourceLen,
Lng32 sourceType,
Lng32 sourcePrecision,
NAMemory *heap,
ComDiagsArea** diagsArea,
ULng32 flags) {
short retCode = ex_expr::EXPR_OK;
if (sourcePrecision > targetPrecision)
{
// return an error if source precision is greater than target precision
// and source will not fit into target.
// For now, do this by first converting source to char and then
// convert char to target.
// Need to optimize this so ConvBigNumWithSignToBigNumWithSignHelper
// can return this error instead of going through the char conversion.
Lng32 intermediateLen = sourcePrecision + 1; // +1 for sign
char * intermediate = (char *)heap->allocateMemory(intermediateLen);
retCode = convBigNumToAscii(intermediate,
sourcePrecision+1,
0,
source,
sourceLen,
sourcePrecision,
0,
NULL, 0,
0,
heap,
diagsArea,
0);
if (retCode == ex_expr::EXPR_OK)
{
// now convert intermediate to target
retCode = convAsciiToBigNum(target,
targetLen,
targetType,
targetPrecision,
0,
intermediate,
sourcePrecision+1,
heap,
diagsArea,
0);
}
heap->deallocateMemory((void *)intermediate);
if (retCode != ex_expr::EXPR_OK)
{
// overflow error. diagsArea already contains the error.
return ex_expr::EXPR_ERROR;
}
};
if (targetType == REC_NUM_BIG_UNSIGNED)
{
char sign = BIGN_GET_SIGN(source, sourceLen);
if (sign)
{
// LCOV_EXCL_START
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
// LCOV_EXCL_STOP
}
}
retCode = BigNumHelper::ConvBigNumWithSignToBigNumWithSignHelper(sourceLen,
targetLen,
source,
target);
if (retCode== -1) {
// target is not long enough - overflow
// LCOV_EXCL_START
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, REC_NUM_BIG_SIGNED, 0, REC_NUM_BIG_SIGNED,
flags);
return ex_expr::EXPR_ERROR;
// LCOV_EXCL_STOP
};
return ex_expr::EXPR_OK;
}
//////////////////////////////////////////////////////////////////
// function to convert Decimal to Int64
///////////////////////////////////////////////////////////////////
NA_EIDPROC
ex_expr::exp_return_type convDecToInt64(Int64 &target,
char *source,
Lng32 sourceLen,
CollHeap *heap,
ComDiagsArea** diagsArea,
ULng32 flags) {
//
// The first bit of the first byte of the decimal value is the sign bit.
// If the bit is set, the decimal value is a negative number. Reset
// the bit before converting the value to binary.
//
target = '0' - (source[0] & 0177);
Lng32 currPos = 1;
// skip leading zeros only if first byte was zero
if (!target) {
while ((source[currPos] == '0') && (currPos < sourceLen))
currPos++;
};
// Convert the value to a negative binary number. Check for overflow.
while (currPos < sourceLen) {
if (source[currPos] < '0' || source[currPos] > '9') {
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_STRING_ERROR,NULL,NULL,NULL,NULL,stringToHex(hexstr, sizeof(hexstr), source, sourceLen ));
return ex_expr::EXPR_ERROR;
};
target *= 10;
target -= source[currPos++] - '0';
if (target > 0) {
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, REC_DECIMAL_LSE, 0, REC_BIN64_SIGNED,
flags);
return ex_expr::EXPR_ERROR;
};
};
// If the decimal value was positive, negate the value. Check for overflow.
if (!(source[0] & 0200)) {
target = - target;
if (target < 0) {
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, REC_DECIMAL_LSE, 0, REC_BIN64_SIGNED,
flags);
return ex_expr::EXPR_ERROR;
};
};
return ex_expr::EXPR_OK;
};
//////////////////////////////////////////////////////////////////
// function to convert Decimal to Decimal
///////////////////////////////////////////////////////////////////
// LCOV_EXCL_START
NA_EIDPROC
ex_expr::exp_return_type convDecToDec(char *target,
Lng32 targetLen,
char *source,
Lng32 sourceLen,
CollHeap *heap,
ComDiagsArea** diagsArea) {
if (targetLen >= sourceLen) {
Lng32 targetIndex = targetLen - sourceLen;
str_pad(target, (Int32) targetIndex, '0');
str_cpy_all(&target[targetIndex], source, sourceLen);
// Clear the sign bit that was moved to target[targetIndex].
target[targetIndex] &= 0177;
}
else {
if ((source[0] & 0177) != '0') {
// target string is not long enough - overflow
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_STRING_ERROR,NULL,NULL,NULL,NULL,stringToHex(hexstr, sizeof(hexstr), source, sourceLen ));
return ex_expr::EXPR_ERROR;
};
Lng32 sourceIndex = sourceLen - targetLen;
for (Lng32 i = 1; i < sourceIndex; i++)
if (source[i] != '0') {
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_STRING_ERROR,NULL,NULL,NULL,NULL,stringToHex(hexstr, sizeof(hexstr), source, sourceLen ));
return ex_expr::EXPR_ERROR;
};
str_cpy_all(target, &source[sourceIndex], targetLen);
}
//
// If the source is negative, set the sign bit in the target.
//
if (source[0] & 0200)
target[0] |= 0200;
return ex_expr::EXPR_OK;
};
//////////////////////////////////////////////////////////////////
// function to convert DecimalLS to ASCII
///////////////////////////////////////////////////////////////////
NA_EIDPROC
ex_expr::exp_return_type convDecLStoAscii(char *target,
Lng32 targetLen,
Lng32 targetPrecision, // num chars in tgt
char *source,
Lng32 sourceLen,
Lng32 sourceScale,
CollHeap *heap,
ComDiagsArea** diagsArea,
ULng32 flags) {
Lng32 curPos = sourceLen - 1;
Lng32 targetLenInChars = ( targetPrecision ? targetPrecision : targetLen );
Lng32 targetPos = targetLenInChars - 1;
// skip blanks, start from end
while (source[curPos] == ' ' && curPos >= 0)
curPos--;
if (curPos < 0) {
// only blanks: Error
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, REC_DECIMAL_LS, sourceScale,
REC_BYTE_F_ASCII, flags);
return ex_expr::EXPR_ERROR;
};
// move data from source to target, put in decimal point where
// required
Int32 digitCnt = 0;
while ((curPos >= 0) &&
(source[curPos] >= '0') && (source[curPos] <= '9')) {
// another digit. Make sure we have space in the target
digitCnt++;
if (targetPos < 0) {
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, REC_DECIMAL_LS, sourceScale,
REC_BYTE_F_ASCII,
flags);
return ex_expr::EXPR_ERROR;
};
// move digit
target[targetPos--] = source[curPos--];
// insert scale
if (sourceScale == digitCnt) {
// make sure we have space for scale
if (targetPos < 0) {
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, REC_DECIMAL_LS, sourceScale,
REC_BYTE_F_ASCII,
flags);
return ex_expr::EXPR_ERROR;
};
// put decimal point in target
target[targetPos--] = '.';
};
};
// if we have a scale and did not insert the decimal point yet,
// add zeros until we can put in the point
while (digitCnt < sourceScale) {
// Make sure we have space in the target
if (targetPos < 0) {
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, REC_DECIMAL_LS, sourceScale,
REC_BYTE_F_ASCII,
flags);
return ex_expr::EXPR_ERROR;
};
// put in zero
target[targetPos--] = '0';
digitCnt++;
// insert scale
if (sourceScale == digitCnt) {
// make sure we have space for scale
if (targetPos < 0) {
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, REC_DECIMAL_LS, sourceScale,
REC_BYTE_F_ASCII,
flags);
return ex_expr::EXPR_ERROR;
};
// put decimal point in target
target[targetPos--] = '.';
};
};
// add negative sign, if we have one
if((curPos >= 0) && (source[curPos] == '-')) {
// make sure we have space for sign
if (targetPos < 0) {
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, REC_DECIMAL_LS, sourceScale,
REC_BYTE_F_ASCII,
flags);
return ex_expr::EXPR_ERROR;
};
// put sign in target
target[targetPos--] = '-';
};
// left pad target with blanks
while (targetPos >= 0)
target[targetPos--] = ' ';
// right pad, if targetLenInChars < targetLen
targetPos = targetLenInChars;
while (targetPos < targetLen)
target[targetPos++] = ' ';
return ex_expr::EXPR_OK;
};
// LCOV_EXCL_STOP
//////////////////////////////////////////////////////////////////
// This function returns an int64 with the minimum value that
// can be represented in a decimal type with the characteristics
// specified by the arguements.
// The function assumes that targetLen is 0 to 18, inclusive.
// The function assumes that targetType is one of the following:
// REC_DECIMAL_UNSIGNED (150)
// REC_DECIMAL_LSE (152).
///////////////////////////////////////////////////////////////////
NA_EIDPROC
Int64 getMinDecValue(Lng32 targetLen,
short targetType)
{
static const Int64 decValue[] = {0,
-9,
-99,
-999,
-9999,
-99999,
-999999,
-9999999,
-99999999,
-999999999,
//SQ_LINUX #ifndef NA_HSC
-9999999999LL,
-99999999999LL,
-999999999999LL,
-9999999999999LL,
-99999999999999LL,
-999999999999999LL,
-9999999999999999LL,
-99999999999999999LL,
-999999999999999999LL};
if (targetType == REC_DECIMAL_UNSIGNED)
{ // Target is unsigned so the minimum value is zero.
return 0;
}
else
{ // Target is signed so get the minimum value from the array.
return decValue[targetLen];
}
}
//////////////////////////////////////////////////////////////////
// This function returns an int64 with the minimum value that
// can be represented in an interval type with the characteristics
// specified by the arguements.
// The function assumes that targetLen is 0 to 18, inclusive.
// The function assumes that targetType is in the range:
// 195 - 207
// - MARIA - 11/06/98
///////////////////////////////////////////////////////////////////
NA_EIDPROC
Int64 getMinIntervalValue(Lng32 targetPrecision,
short targetType) {
targetType -= REC_MIN_INTERVAL; //REC_MIN_INTERVAL should be 195
// a table of all possible minimum interval values grouped by
// interval type
// Note: The minimum signed 64-bit value is -9223372036854775808,
// (which we code as 0x8000000000000000 to avoid compiler whining)
// so where a target type and precision would demand a value
// smaller than this, we use this minimum instead.
//SQ_LINUX #ifndef NA_HSC
static const Int64 MinValue[][19] =
{
{0, -9, -99, -999, -9999, -99999, -999999, -9999999, -99999999,
-999999999LL, -9999999999LL, -99999999999LL, -999999999999LL,
-9999999999999LL, -99999999999999LL, -999999999999999LL,
-9999999999999999LL, -99999999999999999LL,
-999999999999999999LL}, //REC_INT_YEAR 195
{0, -9, -99, -999, -9999, -99999, -999999, -9999999, -99999999, -999999999,
-9999999999LL, -99999999999LL, -999999999999LL, -9999999999999LL,
-99999999999999LL, -999999999999999LL, -9999999999999999LL,
-99999999999999999LL,
-999999999999999999LL}, //REC_INT_MONTH 196
{0, -119, -1199, -11999, -119999, -1199999, -11999999, -119999999,
-1199999999LL, -11999999999LL, -119999999999LL, -1199999999999LL,
-11999999999999LL, -119999999999999LL, -1199999999999999LL,
-11999999999999999LL, -119999999999999999LL, -1199999999999999999LL,
0x8000000000000000LL}, //REC_INT_YEAR_MONTH 197
{0, -9, -99, -999, -9999, -99999, -999999, -9999999, -99999999,
-999999999LL, -9999999999LL, -99999999999LL, -999999999999LL,
-9999999999999LL, -99999999999999LL, -999999999999999LL,
-9999999999999999LL, -99999999999999999LL,
-999999999999999999LL}, //REC_INT_DAY 198
{0, -9, -99, -999, -9999, -99999, -999999, -9999999, -99999999,
-999999999LL, -9999999999LL, -99999999999LL, -999999999999LL,
-9999999999999LL, -99999999999999LL, -999999999999999LL,
-9999999999999999LL, -99999999999999999LL,
-999999999999999999LL}, //REC_INT_HOUR 199
{0, -239, -2399, -23999, -239999, -2399999, -23999999, -239999999,
-(Int64)(2399999999LL), -23999999999LL, -239999999999LL,
-2399999999999LL, -23999999999999LL, -239999999999999LL,
-2399999999999999LL, -23999999999999999LL,
-239999999999999999LL, -2399999999999999999LL,
0x8000000000000000LL}, // REC_INT_DAY_HOUR 200
{0, -9, -99, -999, -9999, -99999, -999999, -9999999, -99999999,
-999999999LL, -9999999999LL, -99999999999LL, -999999999999LL,
-9999999999999LL, -99999999999999LL, -999999999999999LL,
-9999999999999999LL, -99999999999999999LL,
-999999999999999999LL}, //REC_INT_MINUTE 201
{0, -599, -5999, -59999, -599999, -5999999, -59999999, -599999999,
-5999999999LL, -59999999999LL, -599999999999LL, -5999999999999LL,
-59999999999999LL, -599999999999999LL, -5999999999999999LL,
-59999999999999999LL, -599999999999999999LL, -5999999999999999999LL,
0x8000000000000000LL}, //REC_INT_HOUR_MINUTE 202
{0, -14399, -143999, -1439999, -14399999, -143999999, -1439999999,
-14399999999LL, -143999999999LL, -1439999999999LL, -14399999999999LL,
-143999999999999LL, -1439999999999999LL, -14399999999999999LL,
-143999999999999999LL, -1439999999999999999LL, 0x8000000000000000LL,
0x8000000000000000LL, 0x8000000000000000LL}, //REC_INT_DAY_MINUTE 203
{0, -9, -99, -999, -9999, -99999, -999999, -9999999, -99999999,
-999999999LL, -9999999999LL, -99999999999LL, -999999999999LL,
-9999999999999LL, -99999999999999LL, -999999999999999LL,
-9999999999999999LL, -99999999999999999LL,
-999999999999999999LL}, //REC_INT_SECOND 204
{0, -599, -5999, -59999, -599999, -5999999, -59999999, -599999999,
-5999999999LL, -59999999999LL, -599999999999LL, -5999999999999LL,
// 0123456789 01234567890 012345678901
-59999999999999LL, -599999999999999LL, -5999999999999999LL,
// 0123456789012 01234567890123 012345678901234
-59999999999999999LL, -599999999999999999LL, -5999999999999999999LL,
// 0123456789012345 01234567890123456 012345678901234567
0x8000000000000000LL
// 0123012301230123
}, //REC_INT_MINUTE_SECOND 205
{0, -35999, -359999, -3599999, -35999999, -359999999, -(Int64)(3599999999LL),
-35999999999LL, -359999999999LL, -3599999999999LL, -35999999999999LL,
// 012345678901
-359999999999999LL, -3599999999999999LL, -35999999999999999LL,
// 0123456789012 01234567890123 012345678901234
-359999999999999999LL, -3599999999999999999LL, 0x8000000000000000LL,
// 0123456789012345 01234567890123456 0123012301230123
0x8000000000000000LL, 0x8000000000000000LL
}, //REC_INT_HOUR_SECOND 206
{0, -863999, -8639999, -86399999, -863999999, -8639999999LL, -86399999999LL,
-863999999999LL, -8639999999999LL, -86399999999999LL, -863999999999999LL,
// 012345678 0123456789 01234567890 012345678901
-8639999999999999LL, -86399999999999999LL, -863999999999999999LL,
// 0123456789012 01234567890123 012345678901234
-8639999999999999999LL, 0x8000000000000000LL, 0x8000000000000000LL,
// 0123456789012345 0123012301230123
0x8000000000000000LL, 0x8000000000000000LL
} // REC_INT_DAY_SECOND 207
};
return MinValue[targetType][targetPrecision];
}
//////////////////////////////////////////////////////////////////
// This function count the number of digits in a non-negative Int64.
// The function assumes that targetLen is 1 to 19, inclusive.
///////////////////////////////////////////////////////////////////
NA_EIDPROC
Lng32 getDigitCount(UInt64 value)
{
static const UInt64 decValue[] = {0,
9,
99,
999,
9999,
99999,
999999,
9999999,
99999999,
999999999,
9999999999ULL,
99999999999ULL,
999999999999ULL,
9999999999999ULL,
99999999999999ULL,
999999999999999ULL,
9999999999999999ULL,
99999999999999999ULL,
999999999999999999ULL,
9999999999999999999ULL};
for (Int32 i = 4; i <= 16; i += 4)
if (value <= decValue[i]) {
if (value <= decValue[i-3])
return(i-3);
if (value <= decValue[i-2])
return(i-2);
if (value <= decValue[i-1])
return(i-1);
else return i;
}
if (value <= decValue[17])
return 17;
if (value <= decValue[18])
return 18;
if (value <= decValue[19])
return 19;
return 20;
}
//////////////////////////////////////////////////////////////////
// This function returns an int64 with the maximum value that
// can be represented in a decimal type with the characteristics
// specified by the arguement.
// The function assumes that targetLen is 0 to 18, inclusive.
///////////////////////////////////////////////////////////////////
NA_EIDPROC
Int64 getMaxDecValue(Lng32 targetLen)
{
static const Int64 decValue[] = {0,
9,
99,
999,
9999,
99999,
999999,
9999999,
99999999,
999999999,
//SQ_LINUX #ifndef NA_HSC
9999999999LL,
99999999999LL,
999999999999LL,
9999999999999LL,
99999999999999LL,
999999999999999LL,
9999999999999999LL,
99999999999999999LL,
999999999999999999LL};
return decValue[targetLen];
}
//////////////////////////////////////////////////////////////////
// This function returns an int64 with the maximum value that
// can be represented in an interval type with the characteristics
// specified by the arguement.
// The function assumes that targetLen is 0 to 18, inclusive.
// The function also assumes that the targetType is between 195-207
// - MARIA - 11/06/98
///////////////////////////////////////////////////////////////////
NA_EIDPROC
Int64 getMaxIntervalValue(Lng32 targetPrecision,
short targetType) {
targetType -= REC_MIN_INTERVAL; //REC_MIN_INTERVAL should be 195
// a table of all possible maximum interval values grouped by
// interval type
// Note: The maximum signed 64-bit value is 9223372036854775807,
// so where a target type and precision would demand a value
// larger than this, we use this maximum instead.
//SQ_LINUX #ifndef NA_HSC
static const Int64 MaxValue[][19] =
{
{0, 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999,
999999999, 9999999999LL, 99999999999LL, 999999999999LL, 9999999999999LL,
99999999999999LL, 999999999999999LL, 9999999999999999LL, 99999999999999999LL,
999999999999999999LL}, //REC_INT_YEAR 195
{0, 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999,
9999999999LL, 99999999999LL, 999999999999LL, 9999999999999LL, 99999999999999LL,
999999999999999LL, 9999999999999999LL, 99999999999999999LL,
999999999999999999LL}, //REC_INT_MONTH 196
{0, 119, 1199, 11999, 119999, 1199999, 11999999, 119999999,
1199999999LL, 11999999999LL, 119999999999LL, 1199999999999LL, 11999999999999LL,
119999999999999LL, 1199999999999999LL, 11999999999999999LL, 119999999999999999LL,
1199999999999999999LL, 9223372036854775807LL}, //REC_INT_YEAR_MONTH 197
{0, 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999,
9999999999LL, 99999999999LL, 999999999999LL, 9999999999999LL, 99999999999999LL,
999999999999999LL, 9999999999999999LL, 99999999999999999LL,
999999999999999999LL}, //REC_INT_DAY 198
{0, 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999,
9999999999LL, 99999999999LL, 999999999999LL, 9999999999999LL, 99999999999999LL,
999999999999999LL, 9999999999999999LL, 99999999999999999LL,
999999999999999999LL}, //REC_INT_HOUR 199
{0, 239, 2399, 23999, 239999, 2399999, 23999999, 239999999, 2399999999LL,
23999999999LL, 239999999999LL, 2399999999999LL, 23999999999999LL,
239999999999999LL, 2399999999999999LL, 23999999999999999LL,
239999999999999999LL, 2399999999999999999LL,
9223372036854775807LL}, // REC_INT_DAY_HOUR 200
{0, 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999LL,
9999999999LL, 99999999999LL, 999999999999LL, 9999999999999LL, 99999999999999LL,
999999999999999LL, 9999999999999999LL, 99999999999999999LL,
999999999999999999LL}, //REC_INT_MINUTE 201
{0, 599, 5999, 59999, 599999, 5999999, 59999999, 599999999, 5999999999LL,
59999999999LL, 599999999999LL, 5999999999999LL, 59999999999999LL, 599999999999999LL,
5999999999999999LL, 59999999999999999LL, 599999999999999999LL,
5999999999999999999LL, 9223372036854775807LL}, //REC_INT_HOUR_MINUTE 202
{0, 14399, 143999, 1439999, 14399999, 143999999, 1439999999LL,
14399999999LL, 143999999999LL, 1439999999999LL, 14399999999999LL,
143999999999999LL, 1439999999999999LL, 14399999999999999LL, 143999999999999999LL,
1439999999999999999LL, 9223372036854775807LL, 9223372036854775807LL,
9223372036854775807LL}, //REC_INT_DAY_MINUTE 203
{0, 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999LL,
9999999999LL, 99999999999LL, 999999999999LL, 9999999999999LL, 99999999999999LL,
999999999999999LL, 9999999999999999LL, 99999999999999999LL,
999999999999999999LL}, //REC_INT_SECOND 204
{0, 599, 5999, 59999, 599999, 5999999, 59999999, 599999999, 5999999999LL,
59999999999LL, 599999999999LL, 5999999999999LL,
// 0123456789 01234567890 012345678901
59999999999999LL, 599999999999999LL, 5999999999999999LL,
// 0123456789012 01234567890123 012345678901234
59999999999999999LL, 599999999999999999LL, 5999999999999999999LL,
// 0123456789012345 01234567890123456 012345678901234567
9223372036854775807LL
// 0123456789012345678
}, //REC_INT_MINUTE_SECOND 205
{0, 35999, 359999, 3599999, 35999999, 359999999, 3599999999LL,
35999999999LL, 359999999999LL, 3599999999999LL, 35999999999999LL,
// 012345678901
359999999999999LL, 3599999999999999LL, 35999999999999999LL,
//0123456789012 01234567890123 012345678901234
359999999999999999LL, 3599999999999999999LL, 9223372036854775807LL,
//0123456789012345 01234567890123456 012345678901234567
9223372036854775807LL, 9223372036854775807LL
}, //REC_INT_HOUR_SECOND 206
{0, 863999, 8639999, 86399999, 863999999, 8639999999LL, 86399999999LL,
863999999999LL, 8639999999999LL, 86399999999999LL, 863999999999999LL,
// 012345678 0123456789 01234567890 012345678901
8639999999999999LL, 86399999999999999LL, 863999999999999999LL,
// 0123456789012 01234567890123 012345678901234
8639999999999999999LL, 9223372036854775807LL, 9223372036854775807LL,
// 0123456789012345 01234567890123456
9223372036854775807LL, 9223372036854775807LL
} // REC_INT_DAY_SECOND 207
};
return MaxValue[targetType][targetPrecision];
}
/////////////////////////////////////////////////////////////////////
// Check that the source value will fit in the target in
// the following cases:
//
// Source Target
// ---------- ----------
// INTEGER NUMERIC(n)
// NUMERIC(m) NUMERIC(n), where m > n
// FLOAT NUMERIC(n)
//////////////////////////////////////////////////////////////////////
NA_EIDPROC
ex_expr::exp_return_type checkPrecision(Int64 source,
Lng32 sourceLen,
short sourceType,
Lng32 sourcePrecision,
Lng32 sourceScale,
short targetType,
Lng32 targetPrecision,
Lng32 targetScale,
CollHeap *heap,
ComDiagsArea** diagsArea,
ULng32 flags)
{
if (targetPrecision > 0) { //special case - don't check precision
// If the source is not an interval and the target is not an interval
// nor an integer and the source is either a float, integer, or bigger
if ((sourceType >= REC_MIN_NUMERIC) &&
(sourceType <= REC_MAX_NUMERIC) &&
(targetType >= REC_MIN_BINARY) &&
(targetType <= REC_MAX_BINARY) &&
((sourceType < REC_MIN_BINARY) ||
(sourceType > REC_MAX_BINARY) ||
(sourcePrecision == 0) ||
(sourcePrecision > targetPrecision))) {
//
// We've satisfied the above criteria. Check that the source value
// will fit in the target NUMERIC.
//
if (targetPrecision <= 18)
if ((source < getMinDecValue(targetPrecision, targetType)) ||
(source > getMaxDecValue(targetPrecision)) ) {
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
(char*)&source, sizeof(Int64), sourceType,
sourceScale, targetType, flags);
return ex_expr::EXPR_ERROR;
}
}
else
if (((sourceType >= REC_MIN_INTERVAL) &&
(sourceType <= REC_MAX_INTERVAL) &&
(targetType >= REC_MIN_INTERVAL) &&
(targetType <= REC_MAX_INTERVAL)) ) {
// Always validate interval-to-interval conversions. It is
// possible that the source was produced by an arithmetic
// operator. Arithmetic operators do not validate their
// results, so the cast of the result must do so even if
// the source and target types, precisions and scales are
// identical.
// Do not validate interval-interval conversion if source and target
// attributes are the same and the source value is MAX or MIN for
// its binary storage datatype(ex. SHRT_MIN for 2 byte storage).
// This is done to 'fix' a problem where the source values are
// sometimes set up to be binary MIN or MAX values when keys
// are being built. The validation out here treats them to be
// invalid values and the query fails. This case can happen
// when partitioning keys are being built to access sql/mp table
// partitions.
// Do not validate if the contents are binary MIN or MAX.
// The contents need to be checked before doing the scale down.
// This whole check is kind of a half kludge and
// maybe we can come up with a better solution at a later time.
if (sourcePrecision == targetPrecision &&
sourceScale == targetScale &&
sourceType == targetType) {
switch (sourceLen) {
case SQL_SMALL_SIZE:
if (source == SHRT_MIN || source == SHRT_MAX)
return ex_expr::EXPR_OK;
break;
case SQL_INT_SIZE:
if (source == INT_MIN || source == INT_MAX)
return ex_expr::EXPR_OK;
break;
case SQL_LARGE_SIZE:
if (source == LLONG_MIN || source == LLONG_MAX)
return ex_expr::EXPR_OK;
break;
default:
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
(char*)&source, sourceLen, sourceType,
sourceScale, targetType, flags);
return ex_expr::EXPR_ERROR;
}
}
Int64 scaleDownValue = 1;
for (Int32 i = 1; i<=sourceScale; i++)
scaleDownValue *= 10;
if (((source/scaleDownValue) <
getMinIntervalValue(targetPrecision, targetType)) ||
((source/scaleDownValue) >
getMaxIntervalValue(targetPrecision, targetType))) {
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
(char*)&source, sourceLen, sourceType,
sourceScale, targetType, flags);
return ex_expr::EXPR_ERROR;
}
}
//
// Numeric to Interval
//
if (((sourceType >= REC_MIN_NUMERIC) &&
(sourceType <= REC_MAX_NUMERIC) &&
(targetType >= REC_MIN_INTERVAL) &&
(targetType <= REC_MAX_INTERVAL)) &&
((sourceType < REC_MIN_BINARY) || // ??
(sourceType > REC_MAX_BINARY) || // ??
(sourcePrecision == 0) || // ??
(sourcePrecision > ((targetType == REC_INT_SECOND) ?
(targetPrecision + targetScale) : targetPrecision)))) {
//(sourcePrecision > targetPrecision))) {
if (targetType == REC_INT_SECOND) {
// The precision of INTERVAL SECOND type is only for the integer
// part, while the precision of other interval type is the number
// of digits for entire value. Since interval is represented as
// numeric, the conversion is really an assignment. Thus, add
// target precision scale to check for overflow. See
// IntervalType::getPrecision().
// Don't get confused, which I did, if you see that the source scale
// does not match to the target scale. The source could get its
// scale from the original value at codeGen,
// see ExpGenerator::matchScales() and ExpGenerator::scaleBy10x().
// Because of the up or down scaling, the source should have the
// right scale and can be assigned to target directly by now.
// Maybe we should use target scale at codeGen instead.
targetPrecision += targetScale;
}
// if hit, either invalid precision or need to expand the matrix
// in getMinIntervalValue() and getMaxIntervalValue()
assert(targetPrecision >= 0 && targetPrecision < 19);
if ((source < getMinIntervalValue(targetPrecision, targetType)) ||
(source > getMaxIntervalValue(targetPrecision, targetType)) ) {
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
(char*)&source, sourceLen, sourceType,
sourceScale, targetType, flags);
return ex_expr::EXPR_ERROR;
}
}
//
// Interval to Numeric
//
if ((sourceType >= REC_MIN_INTERVAL) &&
(sourceType <= REC_MAX_INTERVAL) &&
(targetType >= REC_MIN_BINARY) &&
(targetType <= REC_MAX_BINARY) &&
(sourcePrecision > targetPrecision)) {
if ((source < getMinDecValue(targetPrecision, targetType)) ||
(source > getMaxDecValue(targetPrecision)) ) {
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
(char*)&source, sourceLen, sourceType,
sourceScale, targetType, flags);
return ex_expr::EXPR_ERROR;
}
}
}
return ex_expr::EXPR_OK;
}
//////////////////////////////////////////////////////////////////
// This function sets the minimum decimal value. It looks at
// targetType to determine if the target is signed or unsigned.
// If signed, the routine generates a string of 9's and the
// sign bit is set. If unsigned, a string of 0's is generated.
// The function assumes that targetType is one of the following:
// REC_DECIMAL_UNSIGNED (150)
// REC_DECIMAL_LSE (152).
///////////////////////////////////////////////////////////////////
NA_EIDPROC
void setMinDecValue(char *target,
Lng32 targetLen,
short targetType)
{
Lng32 currPos = 0;
if (targetType == REC_DECIMAL_UNSIGNED)
{ // Target is unsigned so generate zeros.
while (currPos < targetLen)
{
target[currPos++] = '0';
}
}
else
{ // Assume target is signed so generate nines and set the sign bit.
while (currPos < targetLen)
{
target[currPos++] = '9';
}
target[0] |= 0200;
}
}
//////////////////////////////////////////////////////////////////
// This function sets the maximum value that can fit into a
// decimal type specified by the arguement.
///////////////////////////////////////////////////////////////////
NA_EIDPROC
void setMaxDecValue(char *target,
Lng32 targetLen)
{
Lng32 currPos = 0;
while (currPos < targetLen)
{
target[currPos++] = '9';
}
}
//////////////////////////////////////////////////////////////////
// Function to convert an exact numeric to decimal. Actually,
// the function converts those exact numerics that will fit into an
// int64 to decimal.
///////////////////////////////////////////////////////////////////
NA_EIDPROC
ex_expr::exp_return_type convExactToDec(char *target,
Lng32 targetLen,
short targetType,
Int64 source,
CollHeap *heap,
ComDiagsArea** diagsArea,
Lng32 * dataConversionErrorFlag,
ULng32 flags)
{
if (source < getMinDecValue(targetLen, targetType))
{
if (dataConversionErrorFlag != 0)
{
setMinDecValue(target, targetLen, targetType);
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
if (targetType == REC_DECIMAL_UNSIGNED)
{
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
(char*)&source, sizeof(source),
REC_BIN64_SIGNED, 0, targetType, flags);
}
return ex_expr::EXPR_ERROR;
}
}
else if (source > getMaxDecValue(targetLen))
{
if (dataConversionErrorFlag != 0)
{
setMaxDecValue(target, targetLen);
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
(char*)&source, sizeof(source),
REC_BIN64_SIGNED, 0, targetType, flags);
return ex_expr::EXPR_ERROR;
}
}
else
{
// Set target to source.
if (convInt64ToDec(target,
targetLen,
source,
heap,
diagsArea) != ex_expr::EXPR_OK)
{
return ex_expr::EXPR_ERROR;
}
}
return ex_expr::EXPR_OK;
}
///////////////////////////////////////////////
// find the first non blank character
///////////////////////////////////////////////
NA_EIDPROC
char * str_find_first_nonblank(char *s, Lng32 len) {
for (Lng32 i = 0; i < len; i++)
if (s[i] != ' ')
return &s[i];
return 0;
};
///////////////////////////////////////////////
// find the first non blank wide character
///////////////////////////////////////////////
NA_EIDPROC
NAWchar * wc_str_find_first_nonblank(NAWchar *s, Lng32 len) {
for (Lng32 i = 0; i < len; i++)
if (s[i] != unicode_char_set::space_char())
return &s[i];
return 0;
};
////////////////////////////////////////////////
// find the first non zero(character 0) character
////////////////////////////////////////////////
// LCOV_EXCL_START
NA_EIDPROC
char* str_find_first_nonzero(char* s, Lng32 len) {
for (Lng32 i = 0; i< len; i++)
if (s[i] != '0')
return &s[i];
return 0;
}
// LCOV_EXCL_STOP
NA_EIDPROC
void setVCLength(char * VCLen, Lng32 VCLenSize, ULng32 value) {
if (VCLenSize == sizeof(short)) {
assert(value <= USHRT_MAX);
unsigned short temp = (unsigned short)value;
str_cpy_all(VCLen, (char *) &temp, VCLenSize);
}
else
str_cpy_all(VCLen, (char *) &value, VCLenSize);
};
////////////////////////////////////////////////////////////////////
// the global conversion routine
////////////////////////////////////////////////////////////////////
typedef charBuf* (*unicodeToChar_FP)(
const NAWcharBuf&,
CollHeap*,
charBuf*&, NABoolean, NABoolean);
///////////////////////////////////////////////
// Unicode to single byte string
///////////////////////////////////////////////
NA_EIDPROC
ex_expr::exp_return_type
unicodeToSByteTarget(
unicodeToChar_FP conv_func, // convert function pointer
char * source,
Lng32 sourceLen,
char * target,
Lng32 targetLen,
char * varCharLen, // NULL if the target is of fix length
Lng32 varCharLenSize,
CollHeap *heap,
ComDiagsArea** diagsArea,
Lng32 * dataConversionErrorFlag,
NABoolean allowInvalidCodePoint = TRUE,
NABoolean padSpace = FALSE
)
{
ex_expr::exp_return_type retcode = ex_expr::EXPR_OK;
Lng32 copyLen, convertedLen;
const NAWcharBuf wBuf((NAWchar*)source, sourceLen/BYTES_PER_NAWCHAR, heap);
charBuf *cBuf = NULL;
cBuf = (*conv_func)(wBuf, heap, cBuf, TRUE, allowInvalidCodePoint);
if (cBuf) {
convertedLen = cBuf -> getStrLen();
copyLen = (convertedLen < targetLen) ? convertedLen : targetLen;
str_cpy_all(target, (const char*)cBuf->data(), copyLen);
NADELETE(cBuf, charBuf, heap);
} else {
convertedLen = 0;
copyLen = 0;
if ( allowInvalidCodePoint == FALSE )
{
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_INVALID_CHAR_IN_TRANSLATE_FUNC,NULL,NULL,NULL,NULL,"UNICODE","ISO88591",stringToHex(hexstr,sizeof(hexstr),source,sourceLen));
retcode = ex_expr::EXPR_ERROR;
}
}
if ( varCharLen )
setVCLength(varCharLen, varCharLenSize, copyLen);
if (targetLen < convertedLen )
{
NAWchar* first_nonblank = wc_str_find_first_nonblank(
(NAWchar*)(&source[targetLen*BYTES_PER_NAWCHAR]),
sourceLen/BYTES_PER_NAWCHAR - targetLen);
if (first_nonblank) // if truncated portion isn't all blanks
{
// LCOV_EXCL_START
if (dataConversionErrorFlag) // want conversion flag instead of warning?
{
// yes - determine whether target is greater than or less than source
if (*first_nonblank < unicode_char_set::space_char() )
// note assumption: UNICODE character set
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
else
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
// LCOV_EXCL_STOP
}
else
// no - raise a warning
ExRaiseSqlWarning(heap, diagsArea, EXE_STRING_OVERFLOW);
}
} else {
if ( padSpace == TRUE && targetLen > convertedLen )
str_pad(&target[convertedLen], targetLen - convertedLen, ' ');
}
return retcode;
}
///////////////////////////////////////////////
// Unicode to multiple byte string
///////////////////////////////////////////////
NA_EIDPROC
ex_expr::exp_return_type
unicodeToMByteTarget(
unicodeToChar_FP conv_func, // conversion function pointer
char * source,
Lng32 sourceLen,
char * target,
Lng32 targetLen,
Lng32 targetPrecision,
Lng32 targetScale,
char * varCharLen, // NULL if the target is of fix length
Lng32 varCharLenSize,
CollHeap *heap,
ComDiagsArea** diagsArea,
Lng32 * dataConversionErrorFlag,
NABoolean allowInvalidCodePoint = TRUE,
NABoolean padSpace = FALSE
)
{
ex_expr::exp_return_type retcode = ex_expr::EXPR_OK;
Lng32 copyLen = 0, convertedLen = 0;
Lng32 num_input_chars = sourceLen/BYTES_PER_NAWCHAR;
const NAWcharBuf wBuf((NAWchar*)source, num_input_chars, heap);
charBuf *cBuf = NULL;
cBuf = (conv_func)(wBuf, heap, cBuf, FALSE, allowInvalidCodePoint);
if (cBuf) {
convertedLen = cBuf -> getStrLen();
copyLen = (convertedLen < targetLen) ? convertedLen : targetLen;
if ( targetScale == SQLCHARSETCODE_UTF8 )
{
// Call lightValidateUTF8Str() to ensure we don't copy partial chars
// or more chars than specified by target precision.
Lng32 max_num_out_chars = copyLen;
if ( targetPrecision && (targetPrecision < num_input_chars) )
max_num_out_chars = targetPrecision;
copyLen = lightValidateUTF8Str((const char*)cBuf->data(),
copyLen, max_num_out_chars, FALSE);
}
str_cpy_all(target, (const char*)cBuf->data(), copyLen);
NADELETE(cBuf, charBuf, heap);
} else {
// LCOV_EXCL_START
convertedLen = 0;
copyLen = 0;
if ( allowInvalidCodePoint == FALSE )
{
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_INVALID_CHAR_IN_TRANSLATE_FUNC);
if( *diagsArea ) {
if ( targetScale == SQLCHARSETCODE_UTF8 )
*(*diagsArea) << DgString0("UNICODE") << DgString1("UTF8") << DgString2(stringToHex(hexstr,sizeof(hexstr),source,sourceLen));
else
*(*diagsArea) << DgString0("UNICODE") << DgString1("SJIS") << DgString2(stringToHex(hexstr,sizeof(hexstr),source,sourceLen));
}
retcode = ex_expr::EXPR_ERROR;
// LCOV_EXCL_STOP
}
}
if ( varCharLen )
setVCLength(varCharLen, varCharLenSize, copyLen);
if (copyLen < convertedLen)
{
// Since WideCharToMultiByte() does not tell how many characters
// are converted, we simply report a rounded error. We can not tell
// if it is rounded up or down. 5/10/98
// TBD - if needed some day: If only blanks are truncated, don't
// generate an error.
// LCOV_EXCL_START
if (dataConversionErrorFlag)
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED;
else
ExRaiseSqlWarning(heap, diagsArea, EXE_STRING_OVERFLOW);
// LCOV_EXCL_STOP
}
// If requested, blank pad so we don't leave garbage at end of target buf
if ( padSpace == TRUE && targetLen > copyLen )
str_pad(&target[copyLen], targetLen - copyLen, ' ');
return retcode;
}
// helper method to convert from one single byte or variable-length encoding
// to another single byte or variable-length encoding. This method does not
// handle UCS2 sources or targets (it's also not designed for UTF-16, if
// we ever support that). It does handle things like ISO8859-1 to UTF-8
// and UTF-8 to UTF-8.
NA_EIDPROC
ex_expr::exp_return_type convCharToChar(
char *source,
Lng32 sourceLen,
short sourceType,
Lng32 sourcePrecision,
Lng32 sourceScale,
char *target,
Lng32 targetLen,
short targetType,
Lng32 targetPrecision,
Lng32 targetScale,
CollHeap *heap,
ComDiagsArea** diagsArea,
Lng32 *dataConversionErrorFlag,
Lng32 *actualTargetLen,
Lng32 blankPadResult,
Lng32 ignoreTrailingBlanksInSource,
Lng32 allowInvalidCodePoint)
{
char *intermediateStr = NULL;
Lng32 intermediateStrLen = 0;
const int stackBufferLen = 512;
char stackBuffer[stackBufferLen];
char *firstUntranslatedChar = NULL;
UInt32 outputDataLen = 0;
UInt32 translatedCharCnt = 0;
Lng32 overflowWarningRaised = 0;
if (sourceScale == SQLCHARSETCODE_UNKNOWN ||
targetScale == SQLCHARSETCODE_UNKNOWN)
{
// can't convert from or to an unknown charset
ExRaiseSqlError(heap, diagsArea, EXE_INTERNAL_ERROR);
return ex_expr::EXPR_ERROR;
}
if (sourceScale != SQLCHARSETCODE_UTF8 &&
targetScale != SQLCHARSETCODE_UTF8)
{
// neither source nor target are UTF-8, we need to do an
// intermediate conversion to UTF-8
intermediateStrLen =
CharInfo::getMaxConvertedLenInBytes((CharInfo::CharSet) sourceScale,
sourceLen,
CharInfo::UTF8);
if (intermediateStrLen <= stackBufferLen)
intermediateStr = stackBuffer;
else
intermediateStr = new (heap) char[intermediateStrLen];
}
if (sourceScale != SQLCHARSETCODE_UTF8)
{
// convert from source to intermediate UTF-8 string or directly
// to the UTF8 output buffer
char *utf8Tgt = target;
Lng32 utf8TgtLen = targetLen;
if (intermediateStr)
{
utf8Tgt = intermediateStr;
utf8TgtLen = intermediateStrLen;
}
int rc = 0;
char * input_to_scan = source;
Lng32 input_length = sourceLen;
if (sourceLen == 0)
firstUntranslatedChar = source;
else
rc = LocaleToUTF8(cnv_version1,
source,
sourceLen,
utf8Tgt,
utf8TgtLen,
convertCharsetEnum(sourceScale),
firstUntranslatedChar,
&outputDataLen,
FALSE,
&translatedCharCnt);
if (rc && rc != CNV_ERR_BUFFER_OVERRUN)
{
// LCOV_EXCL_START
ExeErrorCode errCode = EXE_INVALID_CHAR_IN_TRANSLATE_FUNC;
if (rc != CNV_ERR_INVALID_CHAR)
errCode = EXE_INTERNAL_ERROR;
ExRaiseSqlError(heap, diagsArea, errCode);
if(errCode == EXE_INVALID_CHAR_IN_TRANSLATE_FUNC)
{
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
*(*diagsArea) << DgString0(scaleToString(sourceScale)) << DgString1(scaleToString(targetScale)) << DgString2(stringToHex(hexstr,sizeof(hexstr),source,sourceLen));
}
if (intermediateStr && intermediateStr != stackBuffer)
NADELETEBASIC(intermediateStr, heap);
return ex_expr::EXPR_ERROR;
// LCOV_EXCL_STOP
}
if (rc || (targetPrecision && targetPrecision < (Lng32) translatedCharCnt))
{
Lng32 canIgnoreOverflowChars = FALSE;
Lng32 remainingScanStringLen = 0;
if (rc == 0)
{
// We failed because the target has too many characters. Find
// the first offending character.
input_to_scan = utf8Tgt;
input_length = outputDataLen;
outputDataLen = lightValidateUTF8Str(utf8Tgt,
(Int32)outputDataLen,
(Int32)targetPrecision,
ignoreTrailingBlanksInSource);
assert((Int32)outputDataLen >= 0); //LCOV_EXCL_LINE : rfi
firstUntranslatedChar = &utf8Tgt[outputDataLen];
}
else
{
assert(rc == CNV_ERR_BUFFER_OVERRUN);
}
if (ignoreTrailingBlanksInSource)
{
// check whether the characters from firstUntranslatedChar onwards are all blanks
// LCOV_EXCL_START
remainingScanStringLen = input_length - (firstUntranslatedChar - input_to_scan);
canIgnoreOverflowChars =
!(str_find_first_nonblank(firstUntranslatedChar, remainingScanStringLen));
// LCOV_EXCL_STOP
}
if (!canIgnoreOverflowChars)
if (dataConversionErrorFlag) // want conversion flag instead of warning?
{
// yes - determine whether target is greater than or less than source
if (*(unsigned char *)firstUntranslatedChar < ' ') // note assumption: ASCII blank is used
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
else
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
else
{
// no - raise a warning
ExRaiseSqlWarning(heap, diagsArea, EXE_STRING_OVERFLOW);
overflowWarningRaised = 1;
}
}
if (intermediateStr)
intermediateStrLen = outputDataLen;
else if (actualTargetLen)
*actualTargetLen = outputDataLen;
} // end sourceScale != SQLCHARSETCODE_UTF8
if (targetScale != SQLCHARSETCODE_UTF8)
{
// convert from intermediate UTF-8 string or directly from
// source to a non-UTF8 target
char *src2 = (intermediateStr ? intermediateStr : source);
Lng32 src2Len = (intermediateStr ? intermediateStrLen : sourceLen);
if ( sourceScale == SQLCHARSETCODE_UTF8 )
src2Len = Attributes::trimFillerSpaces( src2
, sourcePrecision
, src2Len
, (CharInfo::CharSet)sourceScale
);
int rc = 0;
if (src2Len == 0)
{
outputDataLen = translatedCharCnt = 0;
firstUntranslatedChar = src2;
}
else
rc = UTF8ToLocale(cnv_version1,
src2,
src2Len,
target,
targetLen,
convertCharsetEnum(targetScale),
firstUntranslatedChar,
&outputDataLen,
FALSE,
allowInvalidCodePoint,
&translatedCharCnt,
(allowInvalidCodePoint ?
CharInfo::getReplacementCharacter((CharInfo::CharSet) targetScale) : NULL));
if (rc)
{
Lng32 canIgnoreOverflowChars = FALSE;
if (ignoreTrailingBlanksInSource && rc == CNV_ERR_BUFFER_OVERRUN)
{
Lng32 remainingSourceStringLen = src2Len - (firstUntranslatedChar - src2);
// check whether the characters from firstUntranslatedChar onwards are all blanks
canIgnoreOverflowChars =
!(str_find_first_nonblank(firstUntranslatedChar, remainingSourceStringLen));
}
if (!canIgnoreOverflowChars)
{
// want conversion flag instead of warning?
if (dataConversionErrorFlag && (rc == CNV_ERR_BUFFER_OVERRUN ||
rc == CNV_ERR_INVALID_CHAR))
{
// yes - determine whether target is greater than or less than source
if (*(unsigned char *)firstUntranslatedChar < ' ') // note assumption: ASCII blank is used
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
else
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
else
{
// no, raise error or warning
if (rc == CNV_ERR_BUFFER_OVERRUN)
{
if (!overflowWarningRaised)
ExRaiseSqlWarning(heap, diagsArea, EXE_STRING_OVERFLOW);
}
else
{
ExeErrorCode errCode = EXE_INVALID_CHAR_IN_TRANSLATE_FUNC;
if (rc != CNV_ERR_INVALID_CHAR)
errCode = EXE_INTERNAL_ERROR;
ExRaiseSqlError(heap, diagsArea, errCode);
if(errCode == EXE_INVALID_CHAR_IN_TRANSLATE_FUNC)
{
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN ];
*(*diagsArea) << DgString0(scaleToString(sourceScale)) << DgString1(scaleToString(targetScale)) << DgString2(stringToHex(hexstr,sizeof(hexstr),source,sourceLen));
}
if (intermediateStr && intermediateStr != stackBuffer)
NADELETEBASIC(intermediateStr, heap);
return ex_expr::EXPR_ERROR;
}
}
}
}
if (intermediateStr && intermediateStr != stackBuffer)
NADELETEBASIC(intermediateStr, heap);
// max. char count should be enforced only for UTF-8 data values for now
// and the target is not a UTF-8 value, validate this assumption here
assert (!(targetPrecision && targetPrecision < (Lng32) translatedCharCnt));
} // end targetScale != SQLCHARSETCODE_UTF8
else if (sourceScale == SQLCHARSETCODE_UTF8)
{
// both source and target charsets are UTF-8; do a byte copy, but also check
// character length semantics, if necessary
outputDataLen = targetLen;
if (sourceLen < targetLen)
outputDataLen = sourceLen;
NABoolean needToIgnoreFillerBlanksInSource =
(sourcePrecision && DFS2REC::isSQLFixedChar(sourceType) &&
DFS2REC::isAnyVarChar(targetType));
Int32 precisionToCheck = sourcePrecision ? sourcePrecision : targetPrecision;
if ( targetPrecision && targetPrecision < sourcePrecision )
precisionToCheck = targetPrecision;
if ( needToIgnoreFillerBlanksInSource )
{
if ( precisionToCheck > 0 )
outputDataLen = lightValidateUTF8Str(source,
outputDataLen,
precisionToCheck,
ignoreTrailingBlanksInSource);
if ((Int32)outputDataLen < 0)
{
// source string is not valid UTF-8
ExRaiseSqlError(heap, diagsArea, EXE_INVALID_CHAR_IN_TRANSLATE_FUNC);
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
*(*diagsArea) << DgString0(scaleToString(sourceScale)) << DgString1(scaleToString(targetScale)) << DgString2(stringToHex(hexstr,sizeof(hexstr),source,sourceLen));
return ex_expr::EXPR_ERROR;
}
}
str_cpy_all(target, source, outputDataLen);
if (targetLen < sourceLen ||
(targetPrecision && targetPrecision < (sourcePrecision ? sourcePrecision : sourceLen)))
{
// Check for truncation of whole or partial characters and for violation of
// a max. number of characters in the target
Lng32 relevantCharsGotTruncated = FALSE;
if ( ! needToIgnoreFillerBlanksInSource ) // If we didn't call this before now
outputDataLen = lightValidateUTF8Str(target,
outputDataLen,
precisionToCheck,
ignoreTrailingBlanksInSource);
if ((Lng32) outputDataLen < sourceLen)
{
if ((Int32)outputDataLen < 0)
{
// source string is not valid UTF-8
ExRaiseSqlError(heap, diagsArea, EXE_INVALID_CHAR_IN_TRANSLATE_FUNC);
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
*(*diagsArea) << DgString0(scaleToString(sourceScale)) << DgString1(scaleToString(targetScale)) << DgString2(stringToHex(hexstr,sizeof(hexstr),source,sourceLen));
return ex_expr::EXPR_ERROR;
}
// not all bytes of the source got copied, check whether any relevant
// information got truncated
if (ignoreTrailingBlanksInSource)
{
Lng32 remainingSourceStringLen = sourceLen - outputDataLen;
// check whether the characters from first truncated char onwards are all blanks
relevantCharsGotTruncated =
(str_find_first_nonblank(&(source[outputDataLen]),
remainingSourceStringLen) != NULL);
}
else
relevantCharsGotTruncated = TRUE;
}
if (relevantCharsGotTruncated)
{
if (dataConversionErrorFlag) // want conversion flag instead of warning?
{
char *firstUntranslatedChar = &source[outputDataLen];
// yes - determine whether target is greater than or less than source
if (*(unsigned char *)firstUntranslatedChar < ' ') // note assumption: ASCII blank is used
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
else
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
else
{
// no - raise a warning
ExRaiseSqlWarning(heap, diagsArea, EXE_STRING_OVERFLOW);
}
}
}
} // end both source and target are UTF-8
// blank-pad and set remaining output parameters
if (blankPadResult && (Lng32) outputDataLen < targetLen)
{
str_pad(&target[outputDataLen], targetLen-(Lng32)outputDataLen, ' ');
outputDataLen = targetLen;
}
if (actualTargetLen)
*actualTargetLen = outputDataLen;
return ex_expr::EXPR_OK;
}
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// //
// the global conversion routine //
// //
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
#pragma warning (disable : 4101) //warning elimination
NA_EIDPROC SQLEXP_LIB_FUNC
ex_expr::exp_return_type
convDoIt(char * source,
Lng32 sourceLen,
short sourceType,
Lng32 sourcePrecision,
Lng32 sourceScale,
char * target,
Lng32 targetLen,
short targetType,
Lng32 targetPrecision,
Lng32 targetScale,
char * varCharLen, // NULL if not a varChar
Lng32 varCharLenSize, // 0 if not a varChar
CollHeap *heap,
ComDiagsArea** diagsArea,
ConvInstruction index,
Lng32 * dataConversionErrorFlag,
ULng32 flags) {
UInt32 rc;
// convDoIt main code
static const unsigned short limits[] = { 1, 3, 7, 15, 31,
63, 127, 255, 511, 1023,
2047, 4095, 8191, 16383, 32767};
// To compute 10^scale . scale is the fractional precision for Intervals,
// valid range 0-6 (the trailing zeroes would "assert" on invalid values)
static const Int64 tenToPowerOf[] = { 1, 10, 100, 1000, 10000,
100000, 1000000, 0, 0, 0, 0 };
// variable used for float operation. Specified in "pragma refligned..."
float *floatSrcPtr, *floatTgtPtr;
double *doubleSrcPtr, *doubleTgtPtr;
floatSrcPtr = (float *)source;
doubleSrcPtr = (double *)source;
floatTgtPtr = (float *)target;
doubleTgtPtr = (double *)target;
NABoolean leftPad = FALSE;
NABoolean allowSignInInterval = FALSE;
ULng32 tempFlags = 0;
if (flags)
{
if (flags & CONV_LEFT_PAD)
leftPad = TRUE;
if (flags & CONV_ALLOW_SIGN_IN_INTERVAL)
allowSignInInterval = TRUE;
//tempFlags must be passed to any recursive calls to convdoit
//within this method and methods that call ExRaiseDetailSqlError.
//Also must be passed to ExRaiseDetailedSqlError.
if(flags & CONV_CONTROL_LOOPING)
tempFlags = CONV_CONTROL_LOOPING;
if(flags & CONV_INTERMEDIATE_CONVERSION)
tempFlags |= CONV_INTERMEDIATE_CONVERSION;
if(flags & CONV_TREAT_ALL_SPACES_AS_ZERO)
tempFlags |= CONV_TREAT_ALL_SPACES_AS_ZERO;
}
if (index == CONV_UNKNOWN ||
index == CONV_UNKNOWN_LEFTPAD) {
ex_conv_clause tempClause;
if (index == CONV_UNKNOWN_LEFTPAD)
leftPad = TRUE;
index = tempClause.findInstruction(sourceType,
sourceLen,
targetType,
targetLen,
sourceScale-targetScale);
};
switch (index) {
case CONV_BPINTU_BPINTU:
{
if (*(unsigned short *)source > limits[targetPrecision-1])
{
if (dataConversionErrorFlag != 0)
{
*(unsigned short *)target = limits[targetPrecision-1];
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
*(unsigned short *)target = *(unsigned short *)source;
}
}
break;
case CONV_BIN16S_BPINTU:
{
if (*(short *)source < 0)
{
if (dataConversionErrorFlag != 0)
{
*(unsigned short *)target = 0;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
}
else if (*(unsigned short *)source > limits[targetPrecision-1])
{
if (dataConversionErrorFlag != 0)
{
*(unsigned short *)target = limits[targetPrecision-1];
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
*(unsigned short *)target = (unsigned short) *(short *)source;
}
}
case CONV_BIN8S_BIN8S:
{
if (dataConversionErrorFlag != 0)
{
*(Int8 *)target = *(Int8 *)source;
}
else
{
if (checkPrecision((Int64)*(Int8 *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(Int8 *)target = *(Int8 *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
break;
case CONV_BIN8U_BIN8U:
{
if (dataConversionErrorFlag != 0)
{
*(UInt8 *)target = *(UInt8 *)source;
}
else
{
if (checkPrecision((Int64)*(UInt8 *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(UInt8 *)target = *(UInt8 *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
break;
case CONV_BIN8S_BIN8U:
{
if (*(Int8 *)source < 0)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(UInt8 *)target = 0;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{
*(UInt8 *)target = *(Int8 *)source;
}
else
{
if (checkPrecision((Int64)*(Int8 *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(UInt8 *)target = *(Int8 *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
}
break;
case CONV_BIN8U_BIN8S:
{
if (*(UInt8 *)source > CHAR_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(Int8 *)target = CHAR_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{ // Set the target value.
*(Int8 *)target = *(UInt8 *)source;
}
else
{ // Check target precision. Then set target value.
if (checkPrecision((Int64)*(UInt8 *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(Int8 *)target = *(UInt8 *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
}
break;
case CONV_BIN8S_BIN16S:
{
*(Int16 *)target = *(Int8 *)source;
}
break;
case CONV_BIN8U_BIN16U:
{
*(UInt16 *)target = *(UInt8 *)source;
}
break;
case CONV_BIN8U_BIN16S:
{
*(Int16 *)target = *(UInt8 *)source;
}
break;
case CONV_BIN8S_BIN32S:
{
*(Int32 *)target = *(Int8 *)source;
}
break;
case CONV_BIN8S_BIN64S:
{
*(Int64 *)target = *(Int8 *)source;
}
break;
case CONV_BIN8U_BIN32U:
{
*(UInt32 *)target = *(UInt8 *)source;
}
break;
case CONV_BIN8U_BIN64U:
{
*(UInt64 *)target = *(UInt8 *)source;
}
break;
case CONV_BIN16U_BIN8S:
{
if (*(UInt16 *)source > CHAR_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(Int8 *)target = CHAR_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{ // Set the target value.
*(Int8 *)target = (Int8) *(UInt16 *)source;
}
else
{ // Check target precision. Then set target value.
if (checkPrecision((Int64)*(UInt16 *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(Int8 *)target = (Int8) *(UInt16 *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
}
break;
case CONV_BIN16S_BIN8U:
{
if (*(Int16 *)source < 0)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(UInt8 *)target = 0;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
}
else if (*(Int16 *)source > UCHAR_MAX)
{
if (dataConversionErrorFlag != 0)
{
*(UInt8 *)target = UCHAR_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{
*(UInt8 *)target = (UInt8) *(Int16 *)source;
}
else
{
if (checkPrecision((Int64)*(Int16 *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(UInt8 *)target = (UInt8) *(Int16 *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
}
break;
case CONV_BIN16S_BIN8S:
{
if (*(Int16 *)source < CHAR_MIN)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(Int8 *)target = CHAR_MIN;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else if (*(Int16 *)source > CHAR_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(Int8 *)target = CHAR_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{ // Set the target value.
*(Int8 *)target = (Int8) *(Int16 *)source;
}
else
{ // Check target precision. Then set target value.
if (checkPrecision((Int64)*(Int16 *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(Int8 *)target = (Int8) *(Int16 *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
}
break;
case CONV_BIN16U_BIN8U:
{
if (*(UInt16 *)source > UCHAR_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(UInt8 *)target = UCHAR_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{ // Set the target value.
*(UInt8 *)target = (UInt8) *(UInt16 *)source;
}
else
{ // Check target precision. Then set target value.
if (checkPrecision((Int64)*(UInt16 *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(UInt8 *)target = (UInt8) *(UInt16 *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
}
break;
case CONV_NUMERIC_BIN8S:
case CONV_NUMERIC_BIN8U:
{
// convert source to smallint and detect data conversion error.
if (dataConversionErrorFlag)
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_OK;
Int16 temp;
ex_expr::exp_return_type rc =
convDoIt(source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
(char*)&temp,
sizeof(Int16),
(index == CONV_NUMERIC_BIN8S
? REC_BIN16_SIGNED : REC_BIN16_UNSIGNED),
targetPrecision,
targetScale,
NULL, // varCharLen
0, // varCharLenSize
heap,
diagsArea,
CONV_UNKNOWN,
dataConversionErrorFlag,
0);
if (rc == ex_expr::EXPR_ERROR)
return ex_expr::EXPR_ERROR;
if ((! dataConversionErrorFlag) ||
(*dataConversionErrorFlag == ex_conv_clause::CONV_RESULT_OK))
{
// no conversion error when converting to smallint.
// Now check to see if there is an error converting to tinyint.
rc = convDoIt((char*)&temp,
sizeof(Int16),
(index == CONV_NUMERIC_BIN8S
? REC_BIN16_SIGNED : REC_BIN16_UNSIGNED),
targetPrecision,
targetScale,
target,
targetLen,
targetType,
targetPrecision,
targetScale,
NULL, // varCharLen
0, // varCharLenSize
heap,
diagsArea,
CONV_UNKNOWN,
dataConversionErrorFlag,
0);
if (rc == ex_expr::EXPR_ERROR)
return ex_expr::EXPR_ERROR;
}
else // data conversion error. Move tinyint max/min to target.
{
if (*dataConversionErrorFlag == ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN)
{
if (index == CONV_NUMERIC_BIN8S)
*(Int8 *)target = CHAR_MIN;
else
*(UInt8 *)target = 0;
}
else if (*dataConversionErrorFlag == ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX)
{
if (index == CONV_NUMERIC_BIN8S)
*(Int8 *)target = CHAR_MAX;
else
*(UInt8 *)target = UCHAR_MAX;
}
}
}
break;
case CONV_BIN8S_ASCII: {
if (convInt64ToAscii(target,
targetLen,
targetPrecision,
targetScale,
(Int64) *(Int8 *)source,
sourceScale,
varCharLen,
varCharLenSize,
' ', // filler character
FALSE,
leftPad,
FALSE,
heap,
diagsArea) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
};
break;
case CONV_BIN8U_ASCII: {
if (convInt64ToAscii(target,
targetLen,
targetPrecision,
targetScale,
(Int64) *(UInt8 *)source,
sourceScale,
varCharLen,
varCharLenSize,
' ', // filler character
FALSE,
leftPad,
FALSE,
heap,
diagsArea) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
};
break;
case CONV_BIN16S_BIN16S:
{
if (dataConversionErrorFlag != 0)
{
*(short *)target = *(short *)source;
}
else
{
if (checkPrecision((Int64)*(short *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(short *)target = *(short *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
break;
case CONV_BIN16S_BIN16U:
{
if (*(short *)source < 0)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(unsigned short *)target = 0;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{ // Set the target value.
*(unsigned short *)target = *(short *)source;
}
else
{ // Check target precision. Then set target value.
if (checkPrecision((Int64)*(short *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(unsigned short *)target = *(short *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
}
break;
case CONV_BIN16S_BIN32S:
{
*(Lng32 *)target = *(short *)source;
}
break;
case CONV_BIN16S_BIN32U:
{
if (*(short *)source < 0)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(ULng32 *)target = 0;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
}
else
{ // Set the target value.
*(ULng32 *)target = *(short *)source;
}
}
break;
case CONV_BIN16S_BIN64S:
{
*(Int64 *)target = *(short *)source;
}
break;
case CONV_BIN16S_DECU:
case CONV_BIN16S_DECS:
{
if (convExactToDec(target,
targetLen,
targetType,
(Int64) *(short *)source,
heap,
diagsArea,
dataConversionErrorFlag,
tempFlags) != ex_expr::EXPR_OK)
{
return ex_expr::EXPR_ERROR;
}
}
break;
case CONV_BIN16S_FLOAT32:
{
// *(float *)target = *(short *)source;
*floatTgtPtr = *(short *)source;
}
break;
case CONV_BIN16S_FLOAT64:
{
// *(double *)target = *(short *)source;
*doubleTgtPtr = *(short *)source;
}
break;
case CONV_BIN16S_BIGNUMU: {
if (*(short *)source < 0) {
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
};
};
// no break! from here on CONV_BIN16S_BIGNUMU is identical with
// CONV_BIN16S_BIGNUM
case CONV_BIN16S_BIGNUM: {
return convInt64ToBigNum(target,
targetLen,
(Int64)*(short *)source,
heap,
diagsArea,
tempFlags);
};
break;
case CONV_BIN16S_ASCII: {
if (convInt64ToAscii(target,
targetLen,
targetPrecision,
targetScale,
(Int64) *(short *)source,
sourceScale,
varCharLen,
varCharLenSize,
' ', // filler character
FALSE,
leftPad,
FALSE,
heap,
diagsArea) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
};
break;
case CONV_BIN16U_BPINTU:
{
if (*(unsigned short *)source > limits[targetPrecision-1])
{
// LCOV_EXCL_START
if (dataConversionErrorFlag != 0)
{
*(unsigned short *)target = limits[targetPrecision-1];
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
// LCOV_EXCL_STOP
}
}
else
{
*(unsigned short *)target = *(unsigned short *)source;
}
}
break;
case CONV_BIN16U_BIN16S:
{
if (*(unsigned short *)source > SHRT_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
// LCOV_EXCL_START
*(short *)target = SHRT_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
// LCOV_EXCL_STOP
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{ // Set the target value.
#pragma nowarn(1506) // warning elimination
*(short *)target = *(unsigned short *)source;
#pragma warn(1506) // warning elimination
}
else
{ // Check target precision. Then set target value.
if (checkPrecision((Int64)*(unsigned short *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
#pragma nowarn(1506) // warning elimination
*(short *)target = *(unsigned short *)source;
#pragma warn(1506) // warning elimination
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
}
break;
case CONV_BIN16U_BIN16U:
{
if (dataConversionErrorFlag != 0)
{
*(unsigned short *)target = *(unsigned short *)source;
}
else
{
if (checkPrecision((Int64)*(unsigned short *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(unsigned short *)target = *(unsigned short *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
break;
case CONV_BIN16U_BIN32S: {
*(Lng32 *)target = *(unsigned short *)source;
};
break;
case CONV_BIN16U_BIN32U: {
// LCOV_EXCL_START
*(ULng32 *)target = *(unsigned short *)source;
};
break;
// LCOV_EXCL_STOP
case CONV_BIN16U_BIN64S: {
*(Int64 *)target = *(unsigned short *)source;
};
break;
case CONV_BIN16U_DECS:
// covers conversion to DECS and DECU (see exp_fixup.cpp)
{
if (convExactToDec(target,
targetLen,
targetType,
(Int64) *(unsigned short *)source,
heap,
diagsArea,
dataConversionErrorFlag,
tempFlags) != ex_expr::EXPR_OK)
{
return ex_expr::EXPR_ERROR;
}
}
break;
case CONV_BIN16U_FLOAT32: {
*floatTgtPtr = *(unsigned short *)source;
};
break;
case CONV_BIN16U_FLOAT64: {
*doubleTgtPtr = *(unsigned short *)source;
};
break;
case CONV_BIN16U_BIGNUM: {
return convInt64ToBigNum(target,
targetLen,
(Int64)*(unsigned short *)source,
heap,
diagsArea,
tempFlags);
};
break;
case CONV_BIN16U_ASCII: {
if (convInt64ToAscii(target,
targetLen,
targetPrecision,
targetScale,
(Int64) *(unsigned short *)source,
sourceScale,
varCharLen,
varCharLenSize,
' ', // filler character
FALSE,
leftPad,
FALSE,
heap,
diagsArea) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
};
break;
case CONV_BIN32S_BIN16S:
{
if (*(Lng32 *)source < SHRT_MIN)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(short *)target = SHRT_MIN;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else if (*(Lng32 *)source > SHRT_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(short *)target = SHRT_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{ // Set the target value.
*(short *)target = (short) *(Lng32 *)source;
}
else
{ // Check target precision. Then set target value.
if (checkPrecision((Int64)*(Lng32 *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(short *)target = (short) *(Lng32 *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
}
break;
case CONV_BIN32S_BPINTU:
{
if (*(Lng32 *)source < 0)
{
// LCOV_EXCL_START
if (dataConversionErrorFlag != 0)
{
*(unsigned short *)target = 0;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
// LCOV_EXCL_STOP
}
else if (*(Lng32 *)source > (Lng32)limits[targetPrecision-1])
{
// LCOV_EXCL_START
if (dataConversionErrorFlag != 0)
{
*(unsigned short *)target = limits[targetPrecision-1];
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
// LCOV_EXCL_STOP
}
}
else
{
*(unsigned short *)target = (unsigned short) *(Lng32 *)source;
}
}
break;
case CONV_BIN32S_BIN16U:
{
if (*(Lng32 *)source < 0)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(unsigned short *)target = 0;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
}
else if (*(Lng32 *)source > USHRT_MAX)
{
if (dataConversionErrorFlag != 0)
{
*(unsigned short *)target = USHRT_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{
*(unsigned short *)target = (unsigned short) *(Lng32 *)source;
}
else
{
if (checkPrecision((Int64)*(Lng32 *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(unsigned short *)target = (unsigned short) *(Lng32 *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
}
break;
case CONV_BIN32S_BIN32S:
{
if (dataConversionErrorFlag != 0)
{
*(Lng32 *)target = *(Lng32 *)source;
}
else
{
if (checkPrecision((Int64)*(Lng32 *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(Lng32 *)target = *(Lng32 *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
break;
case CONV_BIN32S_BIN32U:
{
if (*(Lng32 *)source < 0)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(ULng32 *)target = 0;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{
*(ULng32 *)target = *(Lng32 *)source;
}
else
{
if (checkPrecision((Int64)*(Lng32 *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(ULng32 *)target = *(Lng32 *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
}
break;
case CONV_BIN32S_BIN64S:
{
*(Int64 *)target = *(Lng32 *)source;
}
break;
case CONV_BIN32S_DECU:
case CONV_BIN32S_DECS:
{
if (convExactToDec(target,
targetLen,
targetType,
(Int64) *(Lng32 *)source,
heap,
diagsArea,
dataConversionErrorFlag,
tempFlags) != ex_expr::EXPR_OK)
{
return ex_expr::EXPR_ERROR;
}
}
break;
case CONV_BIN32S_FLOAT32: {
*floatTgtPtr = (float)*(Lng32 *)source;
};
break;
case CONV_BIN32S_FLOAT64: {
*doubleTgtPtr = (double)*(Lng32 *)source;
};
break;
case CONV_BIN32S_BIGNUMU: {
if (*(Lng32 *)source < 0) {
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
};
};
// no break! from here on CONV_BIN32S_BIGNUMU is identical with
// CONV_BIN32S_BIGNUM
case CONV_BIN32S_BIGNUM: {
return convInt64ToBigNum(target,
targetLen,
(Int64)*(Lng32 *)source,
heap,
diagsArea,
tempFlags);
};
break;
case CONV_BIN32S_ASCII: {
if (convInt64ToAscii(target,
targetLen,
targetPrecision,
targetScale,
(Int64) *(Lng32 *)source,
sourceScale,
varCharLen,
varCharLenSize,
' ', // filler character
FALSE,
leftPad,
FALSE,
heap,
diagsArea) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
};
break;
case CONV_BIN32U_BPINTU:
{
// LCOV_EXCL_START
if (*(ULng32 *)source > (ULng32)limits[targetPrecision-1])
{
if (dataConversionErrorFlag != 0)
{
*(unsigned short *)target = limits[targetPrecision-1];
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
*(unsigned short *)target = (unsigned short) *(ULng32 *)source;
}
}
break;
// LCOV_EXCL_STOP
case CONV_BIN32U_BIN16S:
{
if (*(ULng32 *)source > SHRT_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(short *)target = SHRT_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{ // Set the target value.
*(short *)target = (short) *(ULng32 *)source;
}
else
{ // Check target precision. Then set target value.
if (checkPrecision((Int64)*(ULng32 *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(short *)target = (short) *(ULng32 *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
}
break;
case CONV_BIN32U_BIN16U:
{
if (*(ULng32 *)source > USHRT_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(unsigned short *)target = USHRT_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{ // Set the target value.
*(unsigned short *)target = (unsigned short) *(ULng32 *)source;
}
else
{ // Check target precision. Then set target value.
if (checkPrecision((Int64)*(ULng32 *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(unsigned short *)target = (unsigned short) *(ULng32 *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
}
break;
case CONV_BIN32U_BIN32S:
{
if (*(ULng32 *)source > INT_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(Lng32 *)target = INT_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{ // Set the target value.
#pragma nowarn(1506) // warning elimination
*(Lng32 *)target = *(ULng32 *)source;
#pragma warn(1506) // warning elimination
}
else
{ // Check target precision. Then set target value.
if (checkPrecision((Int64)*(ULng32 *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
#pragma nowarn(1506) // warning elimination
*(Lng32 *)target = *(ULng32 *)source;
#pragma warn(1506) // warning elimination
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
}
break;
case CONV_BIN32U_BIN32U:
{
if (dataConversionErrorFlag != 0)
{
*(ULng32 *)target = *(ULng32 *)source;
}
else
{
if (checkPrecision((Int64)*(ULng32 *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(ULng32 *)target = *(ULng32 *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
break;
case CONV_BIN32U_BIN64S:
{
*(Int64 *)target = (Int64)(*(ULng32 *)source);
}
break;
case CONV_BIN32U_DECS:
// covers conversion to DECS and DECU (see exp_fixup.cpp)
{
if (convExactToDec(target,
targetLen,
targetType,
(Int64) *(ULng32 *)source,
heap,
diagsArea,
dataConversionErrorFlag,
tempFlags) != ex_expr::EXPR_OK)
{
return ex_expr::EXPR_ERROR;
}
}
break;
case CONV_BIN32U_FLOAT32:
{
*floatTgtPtr = (float)*(ULng32 *)source;
}
break;
case CONV_BIN32U_FLOAT64:
{
*doubleTgtPtr = (double)*(ULng32 *)source;
}
break;
case CONV_BIN32U_BIGNUM:
{
return convInt64ToBigNum(target,
targetLen,
(Int64)*(ULng32 *)source,
heap,
diagsArea,
tempFlags);
}
break;
case CONV_BIN32U_ASCII: {
if (convInt64ToAscii(target,
targetLen,
targetPrecision,
targetScale,
(Int64) *(ULng32 *)source,
sourceScale,
varCharLen,
varCharLenSize,
' ', // filler character
FALSE,
leftPad,
FALSE,
heap,
diagsArea) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
};
break;
case CONV_BIN64S_BPINTU:
{
if (*(Int64 *)source < 0)
{
// LCOV_EXCL_START
if (dataConversionErrorFlag != 0)
{
*(unsigned short *)target = 0;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
}
// LCOV_EXCL_STOP
else if (*(Int64 *)source > (Int64)limits[targetPrecision-1])
{
// LCOV_EXCL_START
if (dataConversionErrorFlag != 0)
{
*(unsigned short *)target = limits[targetPrecision-1];
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
// LCOV_EXCL_STOP
}
}
else
{
*(unsigned short *)target = (unsigned short) *(Int64 *)source;
}
}
break;
case CONV_BIN64S_BIN16S:
{
if (*(Int64 *)source < SHRT_MIN)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(short *)target = SHRT_MIN;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else if (*(Int64 *)source > SHRT_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(short *)target = SHRT_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{ // Set the target value.
*(short *)target = (short) *(Int64 *)source;
}
else
{ // Check target precision. Then set target value.
if (checkPrecision(*(Int64 *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(short *)target = (short) *(Int64 *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
}
break;
case CONV_BIN64S_BIN16U:
{
if (*(Int64 *)source < 0)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(unsigned short *)target = 0;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
}
else if (*(Int64 *)source > USHRT_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(unsigned short *)target = USHRT_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{ // Set the target value.
*(unsigned short *)target = (unsigned short) *(Int64 *)source;
}
else
{ // Check target precision. Then set target value.
if (checkPrecision(*(Int64 *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(unsigned short *)target = (unsigned short) *(Int64 *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
}
break;
case CONV_BIN64S_BIN32S:
{
if (*(Int64 *)source < INT_MIN)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(Lng32 *)target = INT_MIN;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else if (*(Int64 *)source > INT_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(Lng32 *)target = INT_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{ // Set the target value.
*(Lng32 *)target = (Lng32) *(Int64 *)source;
}
else
{ // Check target precision. Then set target value.
if (checkPrecision(*(Int64 *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(Lng32 *)target = (Lng32) *(Int64 *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
}
break;
case CONV_BIN64S_BIN32U:
{
if (*(Int64 *)source < 0)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(ULng32 *)target = 0;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
}
else if (*(Int64 *)source > UINT_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(ULng32 *)target = UINT_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{ // Set the target value.
*(ULng32 *)target = (ULng32) *(Int64 *)source;
}
else
{ // Check target precision. Then set target value.
if (checkPrecision(*(Int64 *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(ULng32 *)target = (ULng32) *(Int64 *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
}
break;
case CONV_BIN64S_BIN64S:
{
if ((dataConversionErrorFlag != 0) ||
checkPrecision(*(Int64 *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(Int64 *)target = *(Int64 *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
break;
case CONV_BIN64S_BIN64U:
{
if (*(Int64 *)source < 0)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(UInt64 *)target = 0;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{
*(UInt64 *)target = *(Int64 *)source;
}
else
{
if (checkPrecision(*(Int64 *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(UInt64 *)target = *(Int64 *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
}
break;
case CONV_BIN64U_BIN64U:
{
if (dataConversionErrorFlag != 0)
{
*(UInt64 *)target = *(UInt64 *)source;
}
else
{
if (checkPrecision((Int64)*(UInt64 *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(UInt64 *)target = *(UInt64 *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
break;
case CONV_BIN64U_BIN64S:
{
if (*(UInt64 *)source > LLONG_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(Int64 *)target = LLONG_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{ // Set the target value.
*(Int64 *)target = *(UInt64 *)source;
}
else
{ // Check target precision. Then set target value.
if (checkPrecision((Int64)*(UInt64 *)source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{
*(Int64 *)target = *(UInt64 *)source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
}
break;
case CONV_BIN64S_DECU:
case CONV_BIN64S_DECS:
{
if (convExactToDec(target,
targetLen,
targetType,
*(Int64 *)source,
heap,
diagsArea,
dataConversionErrorFlag,
tempFlags) != ex_expr::EXPR_OK)
{
return ex_expr::EXPR_ERROR;
}
}
break;
case CONV_BIN64S_FLOAT32: {
*floatTgtPtr = (float) *(Int64 *)source;
};
break;
case CONV_BIN64S_FLOAT64: {
*doubleTgtPtr = (double) *(Int64 *)source;
};
break;
case CONV_BIN64U_FLOAT32: {
*floatTgtPtr = (float) *(UInt64 *)source;
};
break;
case CONV_BIN64U_FLOAT64: {
*doubleTgtPtr = (double) *(UInt64 *)source;
};
break;
case CONV_BIN64U_BIGNUM: {
return convUInt64ToBigNum(target,
targetLen,
*(UInt64 *) source,
heap,
diagsArea,
tempFlags);
};
break;
case CONV_BIN64S_BIGNUMU: {
if (*(Int64 *)source < 0) {
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
};
};
// no break! from here on CONV_BIN64S_BIGNUMU is identical with
// CONV_BIN64S_BIGNUM
case CONV_BIN64S_BIGNUM: {
return convInt64ToBigNum(target,
targetLen,
*(Int64 *) source,
heap,
diagsArea,
tempFlags);
};
break;
case CONV_BIN64S_ASCII: {
if (convInt64ToAscii(target,
targetLen,
targetPrecision,
targetScale,
*(Int64 *)source,
sourceScale,
varCharLen,
varCharLenSize,
' ', // filler character
FALSE,
leftPad,
FALSE,
heap,
diagsArea) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
};
break;
case CONV_BIN64U_ASCII: {
if (convInt64ToAscii(target,
targetLen,
targetPrecision,
targetScale,
*(Int64 *)source,
sourceScale,
varCharLen,
varCharLenSize,
' ', // filler character
FALSE,
leftPad,
TRUE,
heap,
diagsArea) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
};
break;
case CONV_DECS_BIN32U:
// This case covers conversions
// from {decu, decs}
// to {bpintu, bin16u, bin32u, bignum}
{
Int64 int64source;
if (convDecToInt64(int64source,
source,
sourceLen,
heap,
diagsArea,
tempFlags | CONV_INTERMEDIATE_CONVERSION) != ex_expr::EXPR_OK)
{
return ex_expr::EXPR_ERROR;
}
return convDoIt((char *) &int64source,
(Lng32) sizeof(Int64),
(short) REC_BIN64_SIGNED,
0, // sourcePrecision
0, // sourceScale
target,
targetLen,
targetType,
targetPrecision,
targetScale,
NULL, // varCharLen
0, // varCharLenSize
heap,
diagsArea,
CONV_UNKNOWN,
dataConversionErrorFlag,
tempFlags | CONV_INTERMEDIATE_CONVERSION);
}
break;
case CONV_DECS_BIN32S:
// This case covers conversions
// from {decu, decs}
// to {bin16s, bin32s}
{
Int64 int64source;
if (convDecToInt64(int64source,
source,
sourceLen,
heap,
diagsArea,
tempFlags | CONV_INTERMEDIATE_CONVERSION) != ex_expr::EXPR_OK)
{
return ex_expr::EXPR_ERROR;
}
return convDoIt((char *) &int64source,
(Lng32) sizeof(Int64),
(short) REC_BIN64_SIGNED,
0, // sourcePrecision
0, // sourceScale
target,
targetLen,
targetType,
targetPrecision,
targetScale,
NULL, // varCharLen
0, // varCharLenSize
heap,
diagsArea,
CONV_UNKNOWN,
dataConversionErrorFlag,
tempFlags | CONV_INTERMEDIATE_CONVERSION);
}
break;
case CONV_DECS_BIN64S:
{
Int64 int64source;
if (convDecToInt64(int64source,
source,
sourceLen,
heap,
diagsArea,
tempFlags | CONV_INTERMEDIATE_CONVERSION) != ex_expr::EXPR_OK)
{
return ex_expr::EXPR_ERROR;
}
return convDoIt((char *) &int64source,
(Lng32) sizeof(Int64),
(short) REC_BIN64_SIGNED,
0, // sourcePrecision
0, // sourceScale
target,
targetLen,
targetType,
targetPrecision,
targetScale,
NULL, // varCharLen
0, // varCharLenSize
heap,
diagsArea,
CONV_BIN64S_BIN64S,
dataConversionErrorFlag,
tempFlags | CONV_INTERMEDIATE_CONVERSION);
}
break;
case CONV_DECS_DECU:
case CONV_DECS_DECS:
{
Int64 intermediate = 0;
if (convDecToInt64(intermediate,
source,
sourceLen,
heap,
diagsArea,
tempFlags | CONV_INTERMEDIATE_CONVERSION) != ex_expr::EXPR_OK)
{
return ex_expr::EXPR_ERROR;
}
if (convExactToDec(target,
targetLen,
targetType,
intermediate,
heap,
diagsArea,
dataConversionErrorFlag,
tempFlags | CONV_INTERMEDIATE_CONVERSION) != ex_expr::EXPR_OK)
{
return ex_expr::EXPR_ERROR;
}
}
break;
case CONV_DECS_FLOAT32: {
Int64 intermediate;
if (convDecToInt64(intermediate,
source,
sourceLen,
heap,
diagsArea,
tempFlags | CONV_INTERMEDIATE_CONVERSION) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
*floatTgtPtr = (float) intermediate;
};
break;
case CONV_DECS_FLOAT64: {
Int64 intermediate;
if (convDecToInt64(intermediate,
source,
sourceLen,
heap,
diagsArea,
tempFlags | CONV_INTERMEDIATE_CONVERSION) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
*doubleTgtPtr = (double) intermediate;
};
break;
case CONV_DECS_ASCII: {
Int64 intermediate;
if (convDecToInt64(intermediate,
source,
sourceLen,
heap,
diagsArea,
tempFlags | CONV_INTERMEDIATE_CONVERSION) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
if (convInt64ToAscii(target,
targetLen,
targetPrecision,
targetScale,
intermediate,
((targetType == REC_DECIMAL_LS) ? 0 : sourceScale),
varCharLen,
varCharLenSize,
((targetType == REC_DECIMAL_LS) ? '0' : ' '),
(targetType == REC_DECIMAL_LS),
((targetType == REC_DECIMAL_LS) ? TRUE : leftPad),
FALSE,
heap,
diagsArea) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
};
break;
case CONV_FLOAT32_BPINTU:
{
// LCOV_EXCL_START
float floatsource = *floatSrcPtr;
if (floatsource < 0)
{
if (dataConversionErrorFlag != 0)
{
*(unsigned short *)target = 0;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
}
else if (floatsource > limits[targetPrecision-1])
{
if (dataConversionErrorFlag != 0)
{
*(unsigned short *)target = limits[targetPrecision-1];
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
unsigned short unsignedShortSource = (unsigned short) floatsource;
if (dataConversionErrorFlag != 0)
{
// Convert back and check for a value change.
float floatsource2 = unsignedShortSource;
if (floatsource2 > floatsource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
}
else
{
if (floatsource2 < floatsource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
}
}
*(unsigned short *)target = unsignedShortSource;
}
}
break;
// LCOV_EXCL_STOP
case CONV_FLOAT32_BIN16S:
{
float floatsource = *floatSrcPtr;
if (floatsource < SHRT_MIN)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
// LCOV_EXCL_START
*(short *)target = SHRT_MIN;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
// LCOV_EXCL_STOP
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType,tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else if (floatsource > SHRT_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
// LCOV_EXCL_START
*(short *)target = SHRT_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
// LCOV_EXCL_STOP
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
Int64 int64source = (Int64) floatsource;
if (dataConversionErrorFlag != 0)
{
// Convert back and check for a value change.
#pragma warning (disable : 4244) //warning elimination
#pragma nowarn(1506) // warning elimination
float floatsource2 = int64source;
#pragma warn(1506) // warning elimination
#pragma warning (default : 4244) //warning elimination
if (floatsource2 > floatsource)
{
// LCOV_EXCL_START
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
// LCOV_EXCL_STOP
}
else
{
if (floatsource2 < floatsource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
}
}
if ((dataConversionErrorFlag != 0) ||
checkPrecision(int64source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{ // Set the target value.
*(short *)target = (short) int64source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
break;
case CONV_FLOAT32_BIN16U:
{
float floatsource = *floatSrcPtr;
if (floatsource < 0)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
// LCOV_EXCL_START
*(unsigned short *)target = 0;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
// LCOV_EXCL_STOP
}
else
{
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
}
else if (floatsource > USHRT_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
// LCOV_EXCL_START
*(unsigned short *)target = USHRT_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
// LCOV_EXCL_STOP
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
Int64 int64source = (Int64) floatsource;
if (dataConversionErrorFlag != 0)
{
// Convert back and check for a value change.
#pragma warning (disable : 4244) //warning elimination
#pragma nowarn(1506) // warning elimination
// LCOV_EXCL_START
float floatsource2 = int64source;
#pragma warn(1506) // warning elimination
#pragma warning (default : 4244) //warning elimination
if (floatsource2 > floatsource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
}
else
{
if (floatsource2 < floatsource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
// LCOV_EXCL_STOP
}
}
}
if ((dataConversionErrorFlag != 0) ||
checkPrecision(int64source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{ // Set the target value.
*(unsigned short *)target = (unsigned short) int64source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
break;
case CONV_FLOAT32_BIN32S:
{
float floatsource = *floatSrcPtr;
if (floatsource < INT_MIN)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
// LCOV_EXCL_START
*(Lng32 *)target = INT_MIN;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
// LCOV_EXCL_STOP
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else if (floatsource > INT_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
// LCOV_EXCL_START
*(Lng32 *)target = INT_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
// LCOV_EXCL_STOP
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
Int64 int64source = (Int64) floatsource;
if (dataConversionErrorFlag != 0)
{
// Convert back and check for a value change.
#pragma warning (disable : 4244) //warning elimination
#pragma nowarn(1506) // warning elimination
float floatsource2 = int64source;
#pragma warn(1506) // warning elimination
#pragma warning (default : 4244) //warning elimination
if (floatsource2 > floatsource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
}
else
{
if (floatsource2 < floatsource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
}
}
if ((dataConversionErrorFlag != 0) ||
checkPrecision(int64source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{ // Set the target value.
*(Lng32 *)target = (Lng32) int64source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
break;
case CONV_FLOAT32_BIN32U:
{
float floatsource = *floatSrcPtr;
if (floatsource < 0)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(ULng32 *)target = 0;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
}
else if (floatsource > UINT_MAX)
{
// LCOV_EXCL_START
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(ULng32 *)target = UINT_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
// LCOV_EXCL_STOP
}
}
else
{
Int64 int64source = (Int64) floatsource;
if (dataConversionErrorFlag != 0)
{
// Convert back and check for a value change.
#pragma warning (disable : 4244) //warning elimination
#pragma nowarn(1506) // warning elimination
float floatsource2 = int64source;
#pragma warn(1506) // warning elimination
#pragma warning (default : 4244) //warning elimination
if (floatsource2 > floatsource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
}
else
{
if (floatsource2 < floatsource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
}
}
if ((dataConversionErrorFlag != 0) ||
checkPrecision(int64source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{ // Set the target value.
*(ULng32 *)target = (ULng32) int64source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
break;
case CONV_FLOAT32_BIN64S:
{
float floatsource = *floatSrcPtr;
if (floatsource < LLONG_MIN)
{
// LCOV_EXCL_START
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(Int64 *)target = LLONG_MIN;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
// LCOV_EXCL_STOP
}
}
else if (floatsource > LLONG_MAX)
{
// LCOV_EXCL_START
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(Int64 *)target = LLONG_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
// LCOV_EXCL_STOP
}
else
{
Int64 int64source = (Int64) floatsource;
if (dataConversionErrorFlag != 0)
{
// Convert back and check for a value change.
#pragma warning (disable : 4244) //warning elimination
#pragma nowarn(1506) // warning elimination
// LCOV_EXCL_START
float floatsource2 = int64source;
#pragma warn(1506) // warning elimination
#pragma warning (default : 4244) //warning elimination
if (floatsource2 > floatsource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
}
else
{
if (floatsource2 < floatsource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
// LCOV_EXCL_STOP
}
}
if ((dataConversionErrorFlag != 0) ||
checkPrecision(int64source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{ // Set the target value.
*(Int64 *)target = int64source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
break;
case CONV_FLOAT32_BIN64U:
{
float floatsource = *floatSrcPtr;
if (floatsource < 0)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(UInt64 *)target = 0;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
}
else if (floatsource > ULLONG_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(UInt64 *)target = ULLONG_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
UInt64 int64source = (UInt64) floatsource;
if (dataConversionErrorFlag != 0)
{
// Convert back and check for a value change.
float floatsource2 = int64source;
if (floatsource2 > floatsource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
}
else
{
if (floatsource2 < floatsource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
}
}
if ((dataConversionErrorFlag != 0) ||
checkPrecision(int64source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{ // Set the target value.
*(UInt64 *)target = (UInt64) int64source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
break;
case CONV_FLOAT32_DECU:
case CONV_FLOAT32_DECS:
{
float floatsource = *floatSrcPtr;
#pragma nowarn(1506) // warning elimination
if (floatsource < getMinDecValue(targetLen, targetType))
#pragma warn(1506) // warning elimination
{
if (dataConversionErrorFlag != 0)
{
// LCOV_EXCL_START
setMinDecValue(target, targetLen, targetType);
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
// LCOV_EXCL_STOP
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
#pragma nowarn(1506) // warning elimination
else if (floatsource > getMaxDecValue(targetLen))
#pragma warn(1506) // warning elimination
{
if (dataConversionErrorFlag != 0)
{
setMaxDecValue(target, targetLen);
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
// LCOV_EXCL_START
Int64 int64source = (Int64) floatsource;
if (dataConversionErrorFlag != 0)
{
// Convert back and check for a value change.
#pragma warning (disable : 4244) //warning elimination
#pragma nowarn(1506) // warning elimination
float floatsource2 = int64source;
#pragma warn(1506) // warning elimination
#pragma warning (default : 4244) //warning elimination
if (floatsource2 > floatsource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
}
else
{
if (floatsource2 < floatsource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
}
}
if (convInt64ToDec(target,
targetLen,
int64source,
heap,
diagsArea) != ex_expr::EXPR_OK)
{
return ex_expr::EXPR_ERROR;
}
}
}
break;
// LCOV_EXCL_STOP
case CONV_FLOAT32_FLOAT32: {
*floatTgtPtr = *floatSrcPtr;
};
break;
case CONV_FLOAT32_FLOAT64: {
*doubleTgtPtr = (double)*floatSrcPtr;
};
break;
case CONV_FLOAT32_ASCII: {
if (targetLen < SQL_REAL_MIN_DISPLAY_SIZE) {
// LCOV_EXCL_START
ExRaiseDetailSqlError(heap, diagsArea, EXE_STRING_OVERFLOW,
source, sourceLen, sourceType, sourceScale, targetType, tempFlags);
return ex_expr::EXPR_ERROR;
// LCOV_EXCL_STOP
};
// double intermediate = (double) *(float *) source;
double intermediate = (double) *floatSrcPtr;
if (convFloat64ToAscii(target,
targetLen,
targetPrecision,
targetScale,
intermediate,
SQL_REAL_FRAG_DIGITS,
varCharLen,
varCharLenSize,
leftPad) != 0) {
// LCOV_EXCL_START
ExRaiseDetailSqlError(heap, diagsArea, EXE_STRING_OVERFLOW,
source, sourceLen, sourceType, sourceScale, targetType, tempFlags);
return ex_expr::EXPR_ERROR;
// LCOV_EXCL_STOP
}
};
break;
case CONV_FLOAT64_BPINTU:
{
double doublesource = *doubleSrcPtr;
if (doublesource < 0)
{
// LCOV_EXCL_START
if (dataConversionErrorFlag != 0)
{
*(unsigned short *)target = 0;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
// LCOV_EXCL_STOP
}
}
else if (doublesource > limits[targetPrecision-1])
{
if (dataConversionErrorFlag != 0)
{
// LCOV_EXCL_START
*(unsigned short *)target = limits[targetPrecision-1];
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
// LCOV_EXCL_STOP
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
unsigned short unsignedShortSource = (unsigned short) doublesource;
if (dataConversionErrorFlag != 0)
{
// Convert back and check for a value change.
double doublesource2 = unsignedShortSource;
if (doublesource2 > doublesource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
}
else
{
if (doublesource2 < doublesource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
}
}
*(unsigned short *)target = unsignedShortSource;
}
}
break;
case CONV_FLOAT64_BIN16S:
{
double doublesource = *doubleSrcPtr;
if (doublesource < SHRT_MIN)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
// LCOV_EXCL_START
*(short *)target = SHRT_MIN;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
// LCOV_EXCL_STOP
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else if (doublesource > SHRT_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(short *)target = SHRT_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
Int64 int64source = (Int64) doublesource;
if (dataConversionErrorFlag != 0)
{
// Convert back and check for a value change.
#pragma warning (disable : 4244) //warning elimination
#pragma nowarn(1506) // warning elimination
double doublesource2 = int64source;
#pragma warn(1506) // warning elimination
#pragma warning (default : 4244) //warning elimination
if (doublesource2 > doublesource)
{
// LCOV_EXCL_START
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
// LCOV_EXCL_STOP
}
else
{
if (doublesource2 < doublesource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
}
}
if ((dataConversionErrorFlag != 0) ||
checkPrecision(int64source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{ // Set the target value.
*(short *)target = (short) int64source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
break;
case CONV_FLOAT64_BIN16U:
{
double doublesource = *doubleSrcPtr;
if (doublesource < 0)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
// LCOV_EXCL_START
*(unsigned short *)target = 0;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
// LCOV_EXCL_STOP
}
else
{
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
}
else if (doublesource > USHRT_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
// LCOV_EXCL_START
*(unsigned short *)target = USHRT_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
// LCOV_EXCL_STOP
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
Int64 int64source = (Int64) doublesource;
if (dataConversionErrorFlag != 0)
{
#pragma warning (disable : 4244) //warning elimination
// Convert back and check for a value change.
#pragma nowarn(1506) // warning elimination
// LCOV_EXCL_START
double doublesource2 = int64source;
#pragma warn(1506) // warning elimination
#pragma warning (default : 4244) //warning elimination
if (doublesource2 > doublesource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
}
else
{
if (doublesource2 < doublesource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
// LCOV_EXCL_STOP
}
}
if ((dataConversionErrorFlag != 0) ||
checkPrecision(int64source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{ // Set the target value.
*(unsigned short *)target = (unsigned short) int64source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
break;
case CONV_FLOAT64_BIN32S:
{
double doublesource = *doubleSrcPtr;
if (doublesource < INT_MIN)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(Lng32 *)target = INT_MIN;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else if (doublesource > INT_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(Lng32 *)target = INT_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else {
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
Int64 int64source = (Int64) doublesource;
if (dataConversionErrorFlag != 0)
{
// Convert back and check for a value change.
#pragma warning (disable : 4244) //warning elimination
#pragma nowarn(1506) // warning elimination
double doublesource2 = int64source;
#pragma warn(1506) // warning elimination
#pragma warning (default : 4244) //warning elimination
if (doublesource2 > doublesource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
}
else
{
if (doublesource2 < doublesource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
}
}
if ((dataConversionErrorFlag != 0) ||
checkPrecision(int64source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{ // Set the target value.
*(Lng32 *)target = (Lng32) int64source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
break;
case CONV_FLOAT64_BIN32U:
{
double doublesource = *doubleSrcPtr;
if (doublesource < 0)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(ULng32 *)target = 0;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
}
else if (doublesource > UINT_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(ULng32 *)target = UINT_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
Int64 int64source = (Int64) doublesource;
if (dataConversionErrorFlag != 0)
{
// Convert back and check for a value change.
#pragma warning (disable : 4244) //warning elimination
#pragma nowarn(1506) // warning elimination
double doublesource2 = int64source;
#pragma warn(1506) // warning elimination
#pragma nowarn(1506) // warning elimination
#pragma warning (default : 4244) //warning elimination
#pragma warn(1506) // warning elimination
if (doublesource2 > doublesource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
}
else
{
if (doublesource2 < doublesource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
}
}
if ((dataConversionErrorFlag != 0) ||
checkPrecision(int64source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{ // Set the target value.
*(ULng32 *)target = (ULng32) int64source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
break;
case CONV_FLOAT64_BIN64S:
{
double doublesource = *doubleSrcPtr;
if (doublesource < LLONG_MIN)
{
// LCOV_EXCL_START
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(Int64 *)target = LLONG_MIN;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
// LCOV_EXCL_STOP
}
}
else if (doublesource > LLONG_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
// LCOV_EXCL_START
*(Int64 *)target = LLONG_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
// LCOV_EXCL_STOP
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
Int64 int64source = (Int64) doublesource;
if (dataConversionErrorFlag != 0)
{
// Convert back and check for a value change.
#pragma warning (disable : 4244) //warning elimination
#pragma nowarn(1506) // warning elimination
// LCOV_EXCL_START
double doublesource2 = int64source;
#pragma warn(1506) // warning elimination
#pragma nowarn(1506) // warning elimination
#pragma warning (default : 4244) //warning elimination
#pragma warn(1506) // warning elimination
if (doublesource2 > doublesource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
}
else
{
if (doublesource2 < doublesource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
// LCOV_EXCL_STOP
}
}
if ((dataConversionErrorFlag != 0) ||
checkPrecision(int64source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{ // Set the target value.
*(Int64 *)target = int64source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
break;
case CONV_FLOAT64_BIN64U:
{
double doublesource = *doubleSrcPtr;
if (doublesource < 0)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(UInt64 *)target = 0;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
}
else if (doublesource > ULLONG_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(UInt64 *)target = ULLONG_MAX;
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
UInt64 int64source = (UInt64) doublesource;
if (dataConversionErrorFlag != 0)
{
// Convert back and check for a value change.
double doublesource2 = int64source;
if (doublesource2 > doublesource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
}
else
{
if (doublesource2 < doublesource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
}
}
if ((dataConversionErrorFlag != 0) ||
checkPrecision(int64source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) == ex_expr::EXPR_OK)
{ // Set the target value.
*(UInt64 *)target = (UInt64) int64source;
}
else
{
return ex_expr::EXPR_ERROR;
}
}
}
break;
case CONV_FLOAT64_DECS:
case CONV_FLOAT64_DECU:
{
double doublesource = *doubleSrcPtr;
#pragma nowarn(1506) // warning elimination
if (doublesource < getMinDecValue(targetLen, targetType))
#pragma warn(1506) // warning elimination
{
if (dataConversionErrorFlag != 0)
{
// LCOV_EXCL_START
setMinDecValue(target, targetLen, targetType);
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
// LCOV_EXCL_STOP
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
#pragma nowarn(1506) // warning elimination
else if (doublesource > getMaxDecValue(targetLen))
#pragma warn(1506) // warning elimination
{
if (dataConversionErrorFlag != 0)
{
// LCOV_EXCL_START
setMaxDecValue(target, targetLen);
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
// LCOV_EXCL_STOP
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
Int64 int64source = (Int64) doublesource;
if (dataConversionErrorFlag != 0)
{
// Convert back and check for a value change.
#pragma warning (disable : 4244) //warning elimination
#pragma nowarn(1506) // warning elimination
// LCOV_EXCL_START
double doublesource2 = int64source;
#pragma warn(1506) // warning elimination
#pragma warning (default : 4244) //warning elimination
if (doublesource2 > doublesource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
}
else
{
if (doublesource2 < doublesource)
{
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
// LCOV_EXCL_STOP
}
}
if (convInt64ToDec(target,
targetLen,
int64source,
heap,
diagsArea) != ex_expr::EXPR_OK)
{
return ex_expr::EXPR_ERROR;
}
}
}
break;
case CONV_FLOAT64_FLOAT32:
{
short ov = 0;
double doubleSource = *doubleSrcPtr;
*floatTgtPtr = MathConvReal64ToReal32(doubleSource, &ov);
if (dataConversionErrorFlag == 0)
{
if (ov)
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (ov == 1) // overflow
{
if (doubleSource < 0) // < -FLT_MAX
{
*floatTgtPtr = -FLT_MAX;
*dataConversionErrorFlag =
ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else // > +FLT_MAX
{
*floatTgtPtr = +FLT_MAX;
*dataConversionErrorFlag =
ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
} // overflow
else if (ov == -1) // underflow
{
if (doubleSource < 0) // > -FLT_MIN
{
*floatTgtPtr = 0;
*dataConversionErrorFlag =
ex_conv_clause::CONV_RESULT_ROUNDED_UP;
}
else // < +FLT_MIN
{
*floatTgtPtr = 0;
*dataConversionErrorFlag =
ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
} // underflow
} // data conversion flag
}
break;
case CONV_FLOAT64_FLOAT64:
{
short ov = 0;
// double doubleSource = *doubleSrcPtr;
*doubleTgtPtr = MathConvReal64ToReal64(*doubleSrcPtr, &ov);
if (dataConversionErrorFlag == 0)
{
if (ov)
{
// LCOV_EXCL_START
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
// LCOV_EXCL_STOP
return ex_expr::EXPR_ERROR;
}
}
else
{
double doubleTarget = *doubleTgtPtr;
if (ov == 1) // overflow
{
// LCOV_EXCL_START
if (doubleTarget < 0) // < -DBL_MAX
{
*doubleTgtPtr = -DBL_MAX;
*dataConversionErrorFlag =
ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else // > +DBL_MAX
{
*doubleTgtPtr = +DBL_MAX;
*dataConversionErrorFlag =
ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
// LCOV_EXCL_STOP
} // overflow
else if (ov == -1) // underflow
{
// LCOV_EXCL_START
if (doubleTarget < 0) // > -DBL_MIN
{
*doubleTgtPtr = 0;
*dataConversionErrorFlag =
ex_conv_clause::CONV_RESULT_ROUNDED_UP;
}
else // < +DBL_MIN
{
*doubleTgtPtr = 0;
*dataConversionErrorFlag =
ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
// LCOV_EXCL_STOP
}
} // underflow
} // data conversion flag
};
break;
case CONV_FLOAT64_ASCII: {
if (targetLen < SQL_REAL_MIN_DISPLAY_SIZE) {
ExRaiseDetailSqlError(heap, diagsArea, EXE_STRING_OVERFLOW,
source, sourceLen, sourceType, sourceScale, targetType, tempFlags);
return ex_expr::EXPR_ERROR;
};
if (convFloat64ToAscii(target,
targetLen,
targetPrecision,
targetScale,
*doubleSrcPtr,
SQL_DOUBLE_PRECISION_FRAG_DIGITS,
varCharLen,
varCharLenSize,
leftPad) != 0) {
ExRaiseDetailSqlError(heap, diagsArea, EXE_STRING_OVERFLOW,
source, sourceLen, sourceType, sourceScale, targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
};
break;
case CONV_BIGNUM_BIN16S:
case CONV_BIGNUM_BIN16U:
case CONV_BIGNUM_BIN32S:
case CONV_BIGNUM_BIN32U: {
Int64 intermediate;
Lng32 tempDataConvErrorFlag;
ex_expr::exp_return_type rc;
if (dataConversionErrorFlag)
{
// want to catch conversion errors in a variable
tempDataConvErrorFlag
= convBigNumToInt64AndScale(&intermediate,
source,
sourceLen,
targetScale-sourceScale,
heap);
}
else
{
// want to use diagsArea to catch errors
if (convBigNumToInt64(&intermediate,
source,
sourceLen,
heap,
diagsArea,
tempFlags | CONV_INTERMEDIATE_CONVERSION) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
}
rc = convDoIt((char *) &intermediate,
(Lng32) sizeof(Int64),
(short) REC_BIN64_SIGNED,
0, // sourcePrecision
0, // sourceScale
target,
targetLen,
targetType,
targetPrecision,
targetScale,
NULL, // varCharLen
0, // varCharLenSize
heap,
diagsArea,
CONV_UNKNOWN,
dataConversionErrorFlag,
tempFlags | CONV_INTERMEDIATE_CONVERSION);
if (dataConversionErrorFlag)
{
// This is tricky (sigh): We must tell our caller what happened
// during this data conversion, but to do so requires combining
// error information from two conversions. The possible situations
// that can occur are as follows:
//
// conversion to Int 64 conversion to final type desired return
// -------------------- ------------------------ --------------
// round down to max round down to max round down to max
// (if we rounded down to the max 64-bit number,
// we know we will round down further to the max
// value when going to any 16 or 32 bit number)
//
// round up to min round up to min round up to min
// (similar)
//
// round down no error round down
// (can happen due to scaling; in this case we
// know the 64-bit result and the final type
// result are the same, so we know the final
// result was rounded down from the original)
//
// round down round down to max round down to max
// (after all, we rounded down to the max value)
//
// round up no error round up
// (similar to round down/no error case)
//
// round up round up to max round up to max
// (similar to round down/round down to max case)
//
// no error no error no error
// (obvious)
//
// no error round down to max round down to max
// (obvious)
//
// no error round up to min round up to min
// (obvious)
//
// The other cases can never occur. (Proof: both routines have the
// characteristic that the only possible errors for positive numbers
// are rounding down, and for negative numbers rounding up. Conversion
// preserves sign apart from conversion to zero, but if the Int64
// result is zero there will be no error on the 2nd conversion.
// Also, round down and round up can occur only due to
// scaling, and scaling occurs in convDoIt only when converting from
// Large Decimal, so round down and round up cannot occur in the 2nd
// conversion.)
//
// Now, inspecting the above chart, we see that the desired result
// is the same as the 2nd conversion, except possibly when the 2nd
// conversion reports no error. But in all those cases, the desired
// result is that of the 1st conversion. So, the following logic
// implements the above chart.
if (*dataConversionErrorFlag == ex_conv_clause::CONV_RESULT_OK)
*dataConversionErrorFlag = tempDataConvErrorFlag;
}
return rc;
};
break;
case CONV_BIGNUM_BIN64S: {
Int64 intermediate;
if (dataConversionErrorFlag)
{
// want conversion errors in a variable
*dataConversionErrorFlag
= convBigNumToInt64AndScale(&intermediate,
source,
sourceLen,
targetScale-sourceScale,
heap);
}
else
{
// want conversion errors in diagsArea
if (convBigNumToInt64(&intermediate,
source,
sourceLen,
heap,
diagsArea,
tempFlags) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
if (checkPrecision(intermediate,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
}
*(Int64 *)target = intermediate;
};
break;
case CONV_BIGNUM_BIN64U: {
UInt64 intermediate;
if (dataConversionErrorFlag)
{
Int64 intermediateTemp;
// want conversion errors in a variable
*dataConversionErrorFlag
= convBigNumToInt64AndScale(&intermediateTemp,
source,
sourceLen,
targetScale-sourceScale,
heap);
}
else
{
// want conversion errors in diagsArea
if (convBigNumToUInt64(&intermediate,
source,
sourceLen,
heap,
diagsArea,
tempFlags) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
if (checkPrecision(intermediate,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
}
*(UInt64 *)target = intermediate;
};
break;
case CONV_BIGNUM_DECU:
case CONV_BIGNUM_DECS: {
if (dataConversionErrorFlag) {
*dataConversionErrorFlag =
convBigNumToDecAndScale(target,
targetLen,
source,
sourceLen,
sourcePrecision,
(index == CONV_BIGNUM_DECU),
targetScale - sourceScale,
heap);
return ex_expr::EXPR_OK;
}
else {
Lng32 tempDataConversionErrorFlag =
convBigNumToDecAndScale(target,
targetLen,
source,
sourceLen,
sourcePrecision,
(index == CONV_BIGNUM_DECU),
0, // do not scale
heap);
if ((tempDataConversionErrorFlag ==
ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN) ||
(tempDataConversionErrorFlag ==
ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX)) {
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
return ex_expr::EXPR_OK;
};
};
break;
case CONV_BIGNUM_FLOAT32:
case CONV_BIGNUM_FLOAT64: {
// We first convert Big Num to Ascii (which itself is done by first converting
// to Large Dec, then from Large Dec to Ascii), then from Ascii to Float.
// (tbd: It would be probably better to convert from Big Num to Float directly)
Lng32 intermediateLen = sourcePrecision + 1;
char * intermediate = (char *)heap->allocateMemory(intermediateLen);
Lng32 errorMark;
if (*diagsArea)
errorMark = (*diagsArea)->getNumber(DgSqlCode::ERROR_);
else
errorMark = 0;
if (convBigNumToAscii(intermediate,
intermediateLen,
0,
source,
sourceLen,
sourcePrecision,
(dataConversionErrorFlag ? sourceScale : 0),
NULL, // varCharLen
0, // varCharLenSize
leftPad,
heap,
diagsArea,
tempFlags | CONV_INTERMEDIATE_CONVERSION) != ex_expr::EXPR_OK) {
//if a EXE_NUMERIC OVERFLOW error was generated during the conversion,
//change it to a warning.
// LCOV_EXCL_START
if (*diagsArea) {
Lng32 errorMark2 = (*diagsArea)->getNumber(DgSqlCode::ERROR_);
Int32 counter = errorMark2 - errorMark;
while (counter) {
if (((*diagsArea)->getErrorEntry(errorMark2 - counter + 1))->
getSQLCODE() == -EXE_STRING_OVERFLOW) {
(*diagsArea)->deleteError(errorMark2 - counter);
ExRaiseSqlWarning(heap, diagsArea, EXE_NUMERIC_OVERFLOW);
}
counter--;
}
}
else {
heap->deallocateMemory((void *)intermediate);
return ex_expr::EXPR_ERROR;
}
// LCOV_EXCL_STOP
}
// Convert ascii to float.
ex_expr::exp_return_type rc =
convDoIt(intermediate,
intermediateLen,
(short) REC_BYTE_F_ASCII,
0, // sourcePrecision
SQLCHARSETCODE_ISO88591, // sourceScale
target,
targetLen,
targetType,
targetPrecision,
targetScale,
NULL, // varCharLen
0, // varCharLenSize
heap,
diagsArea,
CONV_UNKNOWN,
dataConversionErrorFlag,
tempFlags | CONV_INTERMEDIATE_CONVERSION);
heap->deallocateMemory((void *)intermediate);
return rc;
};
break;
case CONV_BIGNUM_ASCII: {
return convBigNumToAscii(target,
targetLen,
targetPrecision,
source,
sourceLen,
sourcePrecision,
sourceScale,
varCharLen,
varCharLenSize,
leftPad,
heap,
diagsArea,
tempFlags);
};
break;
case CONV_BIGNUM_BIGNUM: {
return convBigNumToBigNum(target,
targetLen,
targetType,
targetPrecision,
source,
sourceLen,
sourceType,
sourcePrecision,
heap,
diagsArea,
tempFlags);
};
break;
case CONV_DECLS_DECLS: {
// LCOV_EXCL_START
if (targetLen < sourceLen) {
// overflow
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
};
// copy first character (which may or may not be a sign)
target[0] = source[0];
Lng32 targetIdx = 1;
if (targetLen > sourceLen) {
// target is larger, fill in zeros
str_pad(&target[targetIdx], targetLen - sourceLen, '0');
targetIdx = targetLen - sourceLen + 1;
};
// copy source to target
str_cpy_all(&target[targetIdx], &source[1], sourceLen - 1);
};
break;
case CONV_DECLS_ASCII: {
return convDecLStoAscii(target,
targetLen,
targetPrecision,
source,
sourceLen,
sourceScale,
heap,
diagsArea,
tempFlags);
};
break;
case CONV_DECLS_DECU: {
// We convert first from REC_DECIMAL_LS to REC_DECIMAL_LSE and then from
// REC_DECIMAL_LSE to REC_DECIMAL_UNSIGNED
// Conversion from REC_DECIMAL_LS to REC_DECIMAL_LSE
char *intermediateTarget = new (heap) char[targetLen];
Lng32 intermediateTargetLen = targetLen;
// if the source is REC_DECIMAL_LS, we use the same conversion as for ASCII,
// but we ignore the targetScale
if (convAsciiToDec(intermediateTarget,
targetType,
intermediateTargetLen,
((sourceType == REC_DECIMAL_LS) ? 0 : targetScale),
source,
sourceLen,
0,
heap,
diagsArea,
tempFlags | CONV_INTERMEDIATE_CONVERSION) != ex_expr::EXPR_OK)
{
NADELETEBASIC(intermediateTarget, heap);
return ex_expr::EXPR_ERROR;
}
if ((targetType == REC_DECIMAL_UNSIGNED) &&
(intermediateTarget[0] & 0200)) {
// unsigned decimal can't be negative
ExRaiseSqlError(heap, diagsArea, EXE_UNSIGNED_OVERFLOW);
NADELETEBASIC(intermediateTarget, heap);
return ex_expr::EXPR_ERROR;
};
// Conversion from REC_DECIMAL_LSE to REC_DECIMAL_UNSIGNED
Int64 intermediate = 0;
if (convDecToInt64(intermediate,
intermediateTarget,
intermediateTargetLen,
heap,
diagsArea,
tempFlags | CONV_INTERMEDIATE_CONVERSION) != ex_expr::EXPR_OK)
{
NADELETEBASIC(intermediateTarget, heap);
return ex_expr::EXPR_ERROR;
}
if (convExactToDec(target,
targetLen,
targetType,
intermediate,
heap,
diagsArea,
dataConversionErrorFlag,
tempFlags | CONV_INTERMEDIATE_CONVERSION) != ex_expr::EXPR_OK)
{
NADELETEBASIC(intermediateTarget, heap);
return ex_expr::EXPR_ERROR;
}
NADELETEBASIC(intermediateTarget, heap);
return ex_expr::EXPR_OK;
};
break;
// LCOV_EXCL_STOP
case CONV_INTERVALY_INTERVALMO: // convert years to months
{
if (convBinToBinScaleMult(target,
targetType,
targetLen,
targetPrecision,
targetScale,
source,
sourceType,
sourceLen,
sourcePrecision,
12, // multiply years by 12 to get months
heap,
diagsArea,
dataConversionErrorFlag,
tempFlags) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
return ex_expr::EXPR_OK;
}
break;
case CONV_INTERVALMO_INTERVALY:
{
if (convBinToBinScaleDiv(target,
targetType,
targetLen,
targetPrecision,
targetScale,
source,
sourceType,
sourceLen,
sourcePrecision,
12, // divide months by 12 to get years
heap,
diagsArea,
dataConversionErrorFlag,
tempFlags) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
return ex_expr::EXPR_OK;
}
break;
case CONV_INTERVALD_INTERVALH:
{
if (convBinToBinScaleMult(target,
targetType,
targetLen,
targetPrecision,
targetScale,
source,
sourceType,
sourceLen,
sourcePrecision,
24, // multiply days by 24 to get hours
heap,
diagsArea,
dataConversionErrorFlag,
tempFlags) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
return ex_expr::EXPR_OK;
}
break;
case CONV_INTERVALD_INTERVALM:
{
if (convBinToBinScaleMult(target,
targetType,
targetLen,
targetPrecision,
targetScale,
source,
sourceType,
sourceLen,
sourcePrecision,
24*60, // multiply days by 24*60 to get minutes
heap,
diagsArea,
dataConversionErrorFlag,
tempFlags) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
return ex_expr::EXPR_OK;
}
break;
case CONV_INTERVALD_INTERVALS:
{
Int64 scaleFactor = 24*60*60 // multiply days by 24*60*60 to get seconds
* tenToPowerOf[targetScale];
if (convBinToBinScaleMult(target,
targetType,
targetLen,
targetPrecision,
targetScale,
source,
sourceType,
sourceLen,
sourcePrecision,
scaleFactor,
heap,
diagsArea,
dataConversionErrorFlag,
tempFlags) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
return ex_expr::EXPR_OK;
}
break;
case CONV_INTERVALH_INTERVALD:
{
if (convBinToBinScaleDiv(target,
targetType,
targetLen,
targetPrecision,
targetScale,
source,
sourceType,
sourceLen,
sourcePrecision,
24, // divide hours by 24 to get days
heap,
diagsArea,
dataConversionErrorFlag,
tempFlags) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
return ex_expr::EXPR_OK;
}
break;
case CONV_INTERVALH_INTERVALM:
{
if (convBinToBinScaleMult(target,
targetType,
targetLen,
targetPrecision,
targetScale,
source,
sourceType,
sourceLen,
sourcePrecision,
60, // multiply hours by 60 to get minutes
heap,
diagsArea,
dataConversionErrorFlag,
tempFlags) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
return ex_expr::EXPR_OK;
}
break;
case CONV_INTERVALH_INTERVALS:
{
Int64 scaleFactor = 60 * 60 // multiply hours by 60*60 to get seconds
* tenToPowerOf[targetScale];
if (convBinToBinScaleMult(target,
targetType,
targetLen,
targetPrecision,
targetScale,
source,
sourceType,
sourceLen,
sourcePrecision,
scaleFactor,
heap,
diagsArea,
dataConversionErrorFlag,
tempFlags) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
return ex_expr::EXPR_OK;
}
break;
case CONV_INTERVALM_INTERVALD:
{
if (convBinToBinScaleDiv(target,
targetType,
targetLen,
targetPrecision,
targetScale,
source,
sourceType,
sourceLen,
sourcePrecision,
60*24, // divide minutes by 60*24 to get days
heap,
diagsArea,
dataConversionErrorFlag,
tempFlags) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
return ex_expr::EXPR_OK;
}
break;
case CONV_INTERVALM_INTERVALH:
{
if (convBinToBinScaleDiv(target,
targetType,
targetLen,
targetPrecision,
targetScale,
source,
sourceType,
sourceLen,
sourcePrecision,
60, // divide minutes by 60 to get hours
heap,
diagsArea,
dataConversionErrorFlag,
tempFlags) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
return ex_expr::EXPR_OK;
}
break;
case CONV_INTERVALM_INTERVALS:
{
Int64 scaleFactor = 60 // multiply minutes by 60 to get seconds
* tenToPowerOf[targetScale];
if (convBinToBinScaleMult(target,
targetType,
targetLen,
targetPrecision,
targetScale,
source,
sourceType,
sourceLen,
sourcePrecision,
scaleFactor,
heap,
diagsArea,
dataConversionErrorFlag,
tempFlags) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
return ex_expr::EXPR_OK;
}
break;
case CONV_INTERVALS_INTERVALD:
{
Int64 scaleFactor = 60*60*24 // divide seconds by 60*60*24 to get days
* tenToPowerOf[sourceScale]; // divide again by 10**fraction precision
if (convBinToBinScaleDiv(target,
targetType,
targetLen,
targetPrecision,
targetScale,
source,
sourceType,
sourceLen,
sourcePrecision,
scaleFactor,
heap,
diagsArea,
dataConversionErrorFlag,
tempFlags) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
return ex_expr::EXPR_OK;
}
break;
case CONV_INTERVALS_INTERVALH:
{
Int64 scaleFactor = 60*60 // divide seconds by 60*60 to get hours
* tenToPowerOf[sourceScale]; // divide again by 10**fraction precision
if (convBinToBinScaleDiv(target,
targetType,
targetLen,
targetPrecision,
targetScale,
source,
sourceType,
sourceLen,
sourcePrecision,
scaleFactor,
heap,
diagsArea,
dataConversionErrorFlag,
tempFlags) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
return ex_expr::EXPR_OK;
}
break;
case CONV_INTERVALS_INTERVALM:
{
Int64 scaleFactor = 60 // divide seconds by 60 to get minutes
* tenToPowerOf[sourceScale]; // divide again by 10**fraction precision
if (convBinToBinScaleDiv(target,
targetType,
targetLen,
targetPrecision,
targetScale,
source,
sourceType,
sourceLen,
sourcePrecision,
scaleFactor,
heap,
diagsArea,
dataConversionErrorFlag,
tempFlags) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
return ex_expr::EXPR_OK;
}
break;
case CONV_INTERVALS_INTERVALS_DIV: // second(n) to second(m), n > m
{
if (convBinToBinScaleDiv(target,
targetType,
targetLen,
targetPrecision,
targetScale,
source,
sourceType,
sourceLen,
sourcePrecision,
tenToPowerOf[sourceScale - targetScale],
heap,
diagsArea,
dataConversionErrorFlag,
tempFlags) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
return ex_expr::EXPR_OK;
}
break;
case CONV_INTERVALS_INTERVALS_MULT: // second(n) to second(m), m > n
{
if (convBinToBinScaleMult(target,
targetType,
targetLen,
targetPrecision,
targetScale,
source,
sourceType,
sourceLen,
sourcePrecision,
tenToPowerOf[targetScale - sourceScale],
heap,
diagsArea,
dataConversionErrorFlag,
tempFlags) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
return ex_expr::EXPR_OK;
}
break;
case CONV_INTERVAL_ASCII: {
return convIntervalToAscii(source,
sourceLen,
sourcePrecision, // leading precision
sourceScale, // fraction precision
sourceType,
target,
targetLen,
targetPrecision, // max chars allowed or 0
varCharLen,
varCharLenSize,
leftPad,
heap,
diagsArea);
};
break;
case CONV_INTERVAL_UNICODE: {
charBuf cBuf(targetLen/BYTES_PER_NAWCHAR, heap);
ex_expr::exp_return_type ok =
convIntervalToAscii(source,
sourceLen,
sourcePrecision, // leading precision
sourceScale, // fraction precision
sourceType,
(char*)cBuf.data(),
cBuf.getBufSize(), // target buffer size
0,
varCharLen,
varCharLenSize,
leftPad,
heap,
diagsArea
);
if ( ok != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
NAWcharBuf *wBuf = NULL;
wBuf = ISO88591ToUnicode(cBuf, heap, wBuf);
if ( wBuf && cBuf.getStrLen() == wBuf->getStrLen() ) {
str_cpy_all(target, (char*)(wBuf->data()), BYTES_PER_NAWCHAR*(wBuf->getStrLen()));
if (varCharLenSize != 0 && varCharLen )
double_varchar_length(varCharLen, varCharLenSize);
} else {
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_DATETIME_ERROR,NULL,NULL,NULL,NULL,stringToHex(hexstr, sizeof(hexstr), source, sourceLen ));
ok = ex_expr::EXPR_ERROR;
}
NADELETE(wBuf, NAWcharBuf, heap);
return ok;
};
break;
case CONV_DATETIME_DATETIME: {
return convDatetimeDatetime(target,
targetLen,
(REC_DATETIME_CODE)targetPrecision,
targetScale,
source,
sourceLen,
(REC_DATETIME_CODE)sourcePrecision,
sourceScale,
heap,
diagsArea,
(short) (flags & CONV_ENABLE_DATETIME_VALIDATION),
dataConversionErrorFlag);
};
break;
case CONV_DATETIME_ASCII: {
if (convDatetimeToAscii(target,
targetLen,
targetPrecision,
source,
sourceLen,
(REC_DATETIME_CODE)sourcePrecision,
(short)sourceScale, // fractionprecision
varCharLen,
varCharLenSize,
leftPad,
heap,
diagsArea) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
};
break;
//
// 6/5/98: added for datetime to unicode
//
case CONV_DATETIME_UNICODE: {
charBuf cBuf(targetLen/BYTES_PER_NAWCHAR, heap);
// to ascii version first
ex_expr::exp_return_type ok =
convDatetimeToAscii((char*)cBuf.data(),
cBuf.getBufSize(), // target buffer size
0,
source,
sourceLen,
(REC_DATETIME_CODE)sourcePrecision,
(short)sourceScale, // fractionprecision
varCharLen,
varCharLenSize,
leftPad,
heap,
diagsArea
);
if ( ok != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
NAWcharBuf *wBuf = NULL;
// get the final unicode version
wBuf = ISO88591ToUnicode(cBuf, heap, wBuf);
if ( wBuf && cBuf.getStrLen() == wBuf->getStrLen() ) {
str_cpy_all(target, (char*)(wBuf->data()), BYTES_PER_NAWCHAR*(wBuf->getStrLen()));
// set the varchar length if necessary
if (varCharLenSize != 0 && varCharLen )
double_varchar_length(varCharLen, varCharLenSize);
ok = ex_expr::EXPR_OK;
} else {
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_DATETIME_ERROR,NULL, NULL, NULL, NULL, stringToHex(hexstr, sizeof(hexstr), source, sourceLen ));
ok = ex_expr::EXPR_ERROR;
}
NADELETE(wBuf, NAWcharBuf, heap);
return ok;
};
break;
case CONV_ASCII_BIN8S:
case CONV_ASCII_BIN8U:
case CONV_ASCII_BIN16S:
case CONV_ASCII_BIN16U:
case CONV_ASCII_BIN32S:
case CONV_ASCII_BIN32U: {
Int64 interm;
if (convAsciiToInt64(interm,
targetScale,
source,
sourceLen,
heap,
diagsArea,
tempFlags | CONV_INTERMEDIATE_CONVERSION) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
switch (index)
{
case CONV_ASCII_BIN8S: {
if (interm < CHAR_MIN)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(Target<Int8> *)target = CHAR_MIN;
*dataConversionErrorFlag =
ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else if (interm > CHAR_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(Target<Int8> *)target = CHAR_MAX;
*dataConversionErrorFlag =
ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType,
sourceScale, targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{ // Set the target value.
*(Target<Int8> *)target = (Int8) interm;
}
else
{ // Check target precision. Then set target value.
if ((targetPrecision > 0) &&
(checkPrecision(interm,
8,
REC_BIN64_SIGNED,
0,
0,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) != ex_expr::EXPR_OK))
{
return ex_expr::EXPR_ERROR;
}
*(Target<Int8> *)target = (Int8) interm;
}
}
};
break;
case CONV_ASCII_BIN8U: {
if (interm < 0)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(Target<unsigned short> *)target = 0;
*dataConversionErrorFlag =
ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else if (interm > UCHAR_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(Target<UInt8> *)target = UCHAR_MAX;
*dataConversionErrorFlag =
ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType,
sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{ // Set the target value.
*(Target<UInt8> *)target = (UInt8) interm;
}
else
{ // Check target precision. Then set target value.
if ((targetPrecision > 0) &&
(checkPrecision(interm,
8,
REC_BIN64_SIGNED,
0,
0,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) != ex_expr::EXPR_OK))
{
return ex_expr::EXPR_ERROR;
}
*(Target<UInt8> *)target = (UInt8) interm;
}
}
};
break;
case CONV_ASCII_BIN16S: {
if (interm < SHRT_MIN)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(Target<short> *)target = SHRT_MIN;
*dataConversionErrorFlag =
ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else if (interm > SHRT_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(Target<short> *)target = SHRT_MAX;
*dataConversionErrorFlag =
ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType,
sourceScale, targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{ // Set the target value.
*(Target<short> *)target = (short) interm;
}
else
{ // Check target precision. Then set target value.
if ((targetPrecision > 0) &&
(checkPrecision(interm,
8,
REC_BIN64_SIGNED,
0,
0,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) != ex_expr::EXPR_OK))
{
return ex_expr::EXPR_ERROR;
}
*(Target<short> *)target = (short) interm;
}
}
};
break;
case CONV_ASCII_BIN16U: {
if (interm < 0)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(Target<unsigned short> *)target = 0;
*dataConversionErrorFlag =
ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else if (interm > USHRT_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(Target<unsigned short> *)target = USHRT_MAX;
*dataConversionErrorFlag =
ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType,
sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{ // Set the target value.
*(Target<unsigned short> *)target = (unsigned short) interm;
}
else
{ // Check target precision. Then set target value.
if ((targetPrecision > 0) &&
(checkPrecision(interm,
8,
REC_BIN64_SIGNED,
0,
0,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) != ex_expr::EXPR_OK))
{
return ex_expr::EXPR_ERROR;
}
*(Target<unsigned short> *)target = (unsigned short) interm;
}
}
};
break;
case CONV_ASCII_BIN32S: {
if (interm < INT_MIN)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(Target<Lng32> *)target = INT_MIN;
*dataConversionErrorFlag =
ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else if (interm > INT_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(Target<Lng32> *)target = INT_MAX;
*dataConversionErrorFlag =
ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType,
sourceScale, targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{ // Set the target value.
*(Target<Lng32> *)target = (Lng32) interm;
}
else
{ // Check target precision. Then set target value.
if ((targetPrecision > 0) &&
(checkPrecision(interm,
8,
REC_BIN64_SIGNED,
0,
0,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) != ex_expr::EXPR_OK))
{
return ex_expr::EXPR_ERROR;
}
*(Target<Lng32> *)target = (Lng32) interm;
}
}
};
break;
case CONV_ASCII_BIN32U: {
if (interm < 0)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(Target<ULng32> *)target = 0;
*dataConversionErrorFlag =
ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else if (interm > UINT_MAX)
{
if (dataConversionErrorFlag != 0) // Capture error in variable?
{
*(Target<ULng32> *)target = UINT_MAX;
*dataConversionErrorFlag =
ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX;
}
else
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
source, sourceLen, sourceType,
sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
}
}
else
{
if (dataConversionErrorFlag != 0)
{ // Set the target value.
*(Target<ULng32> *)target = (ULng32) interm;
}
else
{ // Check target precision. Then set target value.
if ((targetPrecision > 0) &&
(checkPrecision(interm,
8,
REC_BIN64_SIGNED,
0,
0,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) != ex_expr::EXPR_OK))
{
return ex_expr::EXPR_ERROR;
}
*(Target<ULng32> *)target = (ULng32) interm;
}
}
};
break;
default: break;
}
};
break;
//
// 6/3/98: added for Cast() NCHAR extension.
//
case CONV_BIN16S_UNICODE:
case CONV_BIN16U_UNICODE:
case CONV_BIN32S_UNICODE:
case CONV_BIN32U_UNICODE:
case CONV_BIN64S_UNICODE:
case CONV_FLOAT32_UNICODE:
case CONV_FLOAT64_UNICODE:
case CONV_DECS_UNICODE:
case CONV_BIGNUM_UNICODE:
{
ConvInstruction cci = CONV_UNKNOWN; // next switch will change.
switch (index) {
case CONV_BIN16S_UNICODE: cci = CONV_BIN16S_ASCII;break;
case CONV_BIN16U_UNICODE: cci = CONV_BIN16U_ASCII;break;
case CONV_BIN32S_UNICODE: cci = CONV_BIN32S_ASCII;break;
case CONV_BIN32U_UNICODE: cci = CONV_BIN32U_ASCII;break;
case CONV_BIN64S_UNICODE: cci = CONV_BIN64S_ASCII;break;
case CONV_FLOAT32_UNICODE: cci = CONV_FLOAT32_ASCII;break;
case CONV_FLOAT64_UNICODE: cci = CONV_FLOAT64_ASCII;break;
case CONV_DECS_UNICODE: cci = CONV_DECS_ASCII;break;
case CONV_BIGNUM_UNICODE: cci = CONV_BIGNUM_ASCII;break;
default: break;
}
// get the ascii version first
charBuf cBuf(targetLen/BYTES_PER_NAWCHAR, heap);
ex_expr::exp_return_type ok =
convDoIt(source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
(char*)cBuf.data(),
cBuf.getBufSize(), // target buffer size
REC_BYTE_F_ASCII,
targetPrecision,
targetScale,
varCharLen,
varCharLenSize,
heap,
diagsArea,
cci,
0,
tempFlags | CONV_INTERMEDIATE_CONVERSION);
if ( ok == ex_expr::EXPR_ERROR )
return ok;
// refine the length for varchar typed target
Lng32 final_length;
if ( varCharLenSize != 0 && varCharLen ) {
if ( varCharLenSize == sizeof(short) )
final_length = *(short*)varCharLen;
else
final_length = *(Lng32*)varCharLen;
cBuf.setStrLen(final_length);
}
NAWcharBuf *wBuf = NULL;
// get the final unicode version
wBuf = ISO88591ToUnicode(cBuf, heap, wBuf);
if (wBuf && (wBuf -> getStrLen() == cBuf.getStrLen()) ) {
str_cpy_all(target, (char*)(wBuf->data()), BYTES_PER_NAWCHAR*(wBuf->getStrLen()));
if ( varCharLenSize != 0 && varCharLen )
double_varchar_length(varCharLen, varCharLenSize);
ok = ex_expr::EXPR_OK;
} else {
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_STRING_ERROR, NULL, NULL, NULL, NULL,stringToHex(hexstr, sizeof(hexstr), source, sourceLen ));
ok = ex_expr::EXPR_ERROR;
}
NADELETE(wBuf, NAWcharBuf, heap);
return ok;
};
break;
// 6/2/98: extend Cast() for NCHAR
case CONV_UNICODE_BIN16S:
case CONV_UNICODE_BIN16U:
case CONV_UNICODE_BIN32S:
case CONV_UNICODE_BIN32U:
case CONV_UNICODE_BIN64S:
case CONV_UNICODE_FLOAT32:
case CONV_UNICODE_FLOAT64:
case CONV_UNICODE_DEC:
case CONV_UNICODE_BIGNUM:
{
// We make use of the ascii version. Before that we need
// to the ascii version.
const NAWcharBuf wBuf((NAWchar*)source, sourceLen/BYTES_PER_NAWCHAR, heap);
charBuf *cBuf = NULL;
cBuf = unicodeToISO88591(wBuf, heap, cBuf);
// If we have it, make sure all content has been included.
if (cBuf) {
if ( cBuf -> getStrLen() == sourceLen/BYTES_PER_NAWCHAR ) {
ConvInstruction cci = CONV_UNKNOWN;
switch (index) {
case CONV_UNICODE_BIN16S: cci = CONV_ASCII_BIN16S;break;
case CONV_UNICODE_BIN16U: cci = CONV_ASCII_BIN16U;break;
case CONV_UNICODE_BIN32S: cci = CONV_ASCII_BIN32S;break;
case CONV_UNICODE_BIN32U: cci = CONV_ASCII_BIN32U;break;
case CONV_UNICODE_BIN64S: cci = CONV_ASCII_BIN64S;break;
case CONV_UNICODE_FLOAT32: cci = CONV_ASCII_FLOAT32;break;
case CONV_UNICODE_FLOAT64: cci = CONV_ASCII_FLOAT64;break;
case CONV_UNICODE_DEC: cci = CONV_ASCII_DEC;break;
case CONV_UNICODE_BIGNUM: cci = CONV_ASCII_BIGNUM;break;
default: break;
}
ex_expr::exp_return_type ok =
convDoIt((char*)cBuf->data(),
cBuf->getStrLen(), // source string length in bytes
REC_BYTE_F_ASCII,
sourcePrecision,
SQLCHARSETCODE_ISO88591,
target,
targetLen,
targetType,
targetPrecision,
targetScale,
NULL, // varCharLen
0, // varCharLenSize
heap,
diagsArea,
cci,
0,
tempFlags | CONV_INTERMEDIATE_CONVERSION);
NADELETE(cBuf, charBuf, heap);
return ok;
}
}
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_STRING_ERROR,NULL, NULL, NULL, NULL, stringToHex(hexstr, sizeof(hexstr), source, sourceLen ));
return ex_expr::EXPR_ERROR;
};
break;
case CONV_ASCII_BIN64S: {
Int64 intermediate;
if (convAsciiToInt64(intermediate,
targetScale,
source,
sourceLen,
heap,
diagsArea,
tempFlags) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
if (checkPrecision(intermediate,
8,
REC_BIN64_SIGNED,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
*(Int64 *)target = intermediate;
};
break;
case CONV_ASCII_BIN64U: {
UInt64 intermediate;
if (convAsciiToUInt64(intermediate,
targetScale,
source,
sourceLen,
heap,
diagsArea,
tempFlags) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
if (checkPrecision(intermediate,
8,
REC_BIN64_SIGNED,
sourcePrecision,
sourceScale,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
tempFlags) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
*(UInt64 *)target = intermediate;
};
break;
case CONV_ASCII_DEC: {
// if the source is REC_DECIMAL_LS, we use the same conversion as for ASCII,
// but we ignore the targetScale
if (convAsciiToDec(target,
targetType,
targetLen,
((sourceType == REC_DECIMAL_LS) ? 0 : targetScale),
source,
sourceLen,
0,
heap,
diagsArea,
tempFlags) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
if ((targetType == REC_DECIMAL_UNSIGNED) &&
(target[0] & 0200)) {
// unsigned decimal can't be negative
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, source,
sourceLen, sourceType, sourceScale,
targetType, tempFlags);
return ex_expr::EXPR_ERROR;
};
};
break;
case CONV_ASCII_FLOAT32: {
double dintermediate;
if (convAsciiToFloat64((char*)&dintermediate,
source,
sourceLen,
heap,
diagsArea,
tempFlags | CONV_INTERMEDIATE_CONVERSION) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
if (convDoIt((char*)&dintermediate,
sizeof(double),
REC_FLOAT64,
targetPrecision,
targetScale,
target,
targetLen,
targetType,
targetPrecision,
0, NULL, 0, heap, diagsArea,
CONV_UNKNOWN, 0,
tempFlags | CONV_INTERMEDIATE_CONVERSION) != ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
};
break;
case CONV_ASCII_FLOAT64: {
return convAsciiToFloat64(target,
source,
sourceLen,
heap,
diagsArea,
tempFlags);
};
break;
case CONV_ASCII_BIGNUM: {
return convAsciiToBigNum(target,
targetLen,
targetType,
targetPrecision,
targetScale,
source,
sourceLen,
heap,
diagsArea,
tempFlags);
};
break;
case CONV_ASCII_DATETIME: {
return convAsciiToDatetime(target,
targetLen,
(REC_DATETIME_CODE)targetPrecision,
(short)targetScale, // fractionprecision
source,
sourceLen,
heap,
diagsArea,
flags);
};
break;
// 6/2/98: added for Unicode to Datetime conversion.
// This is treated as a special case as we need to call
// convAsciiToDateTime().
case CONV_UNICODE_DATETIME: {
const NAWcharBuf wBuf((NAWchar*)source, sourceLen/BYTES_PER_NAWCHAR, heap);
charBuf *cBuf = NULL;
cBuf = unicodeToISO88591(wBuf, heap, cBuf);
if (cBuf) {
if ( cBuf -> getStrLen() == sourceLen/BYTES_PER_NAWCHAR ) {
ex_expr::exp_return_type ok =
convAsciiToDatetime(target,
targetLen,
(REC_DATETIME_CODE)targetPrecision,
(short)targetScale, // fractionprecision
(char*)cBuf->data(),
cBuf->getStrLen(), // in bytes
heap,
diagsArea,
0);
NADELETE(cBuf, charBuf, heap);
return ok;
}
}
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_DATETIME_ERROR,NULL, NULL, NULL, NULL, stringToHex(hexstr, sizeof(hexstr), source, sourceLen ));
return ex_expr::EXPR_ERROR;
};
break;
//
// 6/5/98: added for unicode to interval
//
case CONV_UNICODE_INTERVAL:
{
const NAWcharBuf wBuf((NAWchar*)source, sourceLen/BYTES_PER_NAWCHAR, heap);
charBuf *cBuf = NULL;
cBuf = unicodeToISO88591(wBuf, heap, cBuf);
if (cBuf) {
if ( cBuf -> getStrLen() == sourceLen/BYTES_PER_NAWCHAR ) {
ex_expr::exp_return_type ok =
convAsciiToInterval(target,
targetLen,
targetType,
targetPrecision, // leading precision
targetScale, // fractionprecision
(char*)cBuf->data(),
cBuf->getStrLen(), // in bytes
allowSignInInterval,
heap,
diagsArea,
tempFlags | CONV_INTERMEDIATE_CONVERSION);
NADELETE(cBuf, charBuf, heap);
return ok;
}
}
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_DATETIME_ERROR, NULL, NULL, NULL, NULL, stringToHex(hexstr, sizeof(hexstr), source, sourceLen ));
return ex_expr::EXPR_ERROR;
};
break;
case CONV_ASCII_INTERVAL: {
return convAsciiToInterval(target,
targetLen,
targetType,
targetPrecision, // leading precision
targetScale, // fractionprecision
source,
sourceLen,
allowSignInInterval,
heap,
diagsArea,
tempFlags);
};
break;
case CONV_ASCII_F_V:
case CONV_ASCII_V_V: {
// check for needed character conversions or validations
if (requiresNoConvOrVal(sourceLen, sourcePrecision, sourceScale,
targetLen, targetPrecision, targetScale, index))
{
// this case can often be translated into PCODE
Lng32 copyLen = ((targetLen >= sourceLen) ? sourceLen : targetLen);
str_cpy_all(target, source, copyLen);
setVCLength(varCharLen, varCharLenSize, copyLen);
if (copyLen < sourceLen)
{
char * first_nonblank = str_find_first_nonblank(
&source[copyLen], sourceLen - copyLen);
if (first_nonblank) // if truncated portion isn't all blanks
{
if (dataConversionErrorFlag) // want conversion flag instead of warning?
{
// yes - determine whether target is greater than or less than source
if (*(unsigned char *)first_nonblank < ' ') // note assumption: ASCII character set
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
else
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
else
// no - raise a warning
ExRaiseSqlWarning(heap, diagsArea, EXE_STRING_OVERFLOW);
}
}
}
else
{
// this case isn't translated into PCODE at this time
Lng32 convertedDataLen;
if (convCharToChar(source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
target,
targetLen,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
dataConversionErrorFlag,
&convertedDataLen,
FALSE,
TRUE,
flags & CONV_ALLOW_INVALID_CODE_VALUE)
!= ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
setVCLength(varCharLen, varCharLenSize, convertedDataLen);
}
};
break;
// gb2312 -> utf8
// JIRA 1720
case CONV_GBK_F_UTF8_V:
{
int copyLen = 0;
int convLen = gbkToUtf8( source, sourceLen, target, targetLen);
if (convLen >= 0) {
copyLen = convLen;
if ( varCharLen )
setVCLength(varCharLen, varCharLenSize, copyLen);
//if the target length is not enough, instead of truncate, raise a SQL Error
if (convLen > targetLen)
ExRaiseSqlError(heap, diagsArea, EXE_STRING_OVERFLOW);
}
else {
// LCOV_EXCL_START
convLen = 0;
copyLen = 0;
if ( varCharLen )
setVCLength(varCharLen, varCharLenSize, copyLen);
char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_STRING_ERROR,NULL, NULL, NULL, NULL, stringToHex(hexstr, sizeof(hexstr), source, sourceLen ));
return ex_expr::EXPR_ERROR;
// LCOV_EXCL_STOP
}
};
break;
// 5/10/98: sjis -> unicode
case CONV_SJIS_F_UNICODE_F:
case CONV_SJIS_F_UNICODE_V:
case CONV_SJIS_V_UNICODE_F:
case CONV_SJIS_V_UNICODE_V:
{
Lng32 copyLen, convertedLen;
// LCOV_EXCL_START
const charBuf cBuf((unsigned char*)source, sourceLen, heap);
NAWcharBuf *wBuf = NULL;
wBuf = sjisToUnicode(cBuf, heap, wBuf);
if (wBuf) {
convertedLen = BYTES_PER_NAWCHAR * (wBuf -> getStrLen());
copyLen = (convertedLen < targetLen) ? convertedLen : targetLen;
str_cpy_all(target, (char*)(wBuf->data()), copyLen);
if (convertedLen > targetLen)
{
NAWchar * first_nonblank =
wc_str_find_first_nonblank(&((wBuf->data())[targetLen/BYTES_PER_NAWCHAR]),
(convertedLen - targetLen) / BYTES_PER_NAWCHAR);
if (first_nonblank) // if truncated portion isn't all blanks
{
if (dataConversionErrorFlag) // want conversion flag instead of warning?
{
// yes - determine whether target is greater than or less than source
// note assumption: UNICODE character set
// LCOV_EXCL_START
if (*first_nonblank < unicode_char_set::space_char())
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
else
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
// LCOV_EXCL_STOP
}
else
// no - raise a warning
ExRaiseSqlWarning(heap, diagsArea, EXE_STRING_OVERFLOW);
}
}
NADELETE(wBuf, NAWcharBuf, heap);
} else {
// LCOV_EXCL_START
convertedLen = 0;
copyLen = 0;
// LCOV_EXCL_STOP
}
// LCOV_EXCL_STOP
// There is no need to change the char string storage format
// for Unicode string.
if ( varCharLen )
setVCLength(varCharLen, varCharLenSize, copyLen);
if ( (index == CONV_SJIS_F_UNICODE_F || index == CONV_SJIS_V_UNICODE_F) &&
copyLen < targetLen )
wc_str_pad((NAWchar*)(&target[copyLen]), (targetLen - copyLen) >> 1);
};
break;
// 6/11/98: ascii -> unicode
case CONV_UTF8_F_UCS2_V:
case CONV_ASCII_UNICODE_F:
case CONV_ASCII_UNICODE_V:
case CONV_ASCII_TO_ANSI_V_UNICODE:
{
Lng32 copyLen, convertedLen;
const charBuf cBuf((unsigned char*)source, sourceLen, heap);
NAWcharBuf *wBuf = NULL;
if (sourceScale == SQLCHARSETCODE_ISO88591)
wBuf = ISO88591ToUnicode(cBuf, heap, wBuf);
else
{
Lng32 convertedDataLen;
if (convCharToChar(source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
target,
targetLen,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
dataConversionErrorFlag,
&convertedDataLen,
FALSE,
TRUE,
flags & CONV_ALLOW_INVALID_CODE_VALUE)
!= ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
wBuf = new (heap) NAWcharBuf( (NAWchar *)target, convertedDataLen/BYTES_PER_NAWCHAR, heap);
}
if ( index == CONV_ASCII_TO_ANSI_V_UNICODE )
targetLen--; // excluding the null terminator
if (wBuf) {
convertedLen = BYTES_PER_NAWCHAR * (wBuf -> getStrLen());
copyLen = (convertedLen < targetLen) ? convertedLen : targetLen;
str_cpy_all(target, (char*)(wBuf->data()), copyLen);
if ( index == CONV_ASCII_UNICODE_F && convertedLen < targetLen )
wc_str_pad((NAWchar*)(&target[copyLen]), (targetLen - copyLen) >> 1);
if (convertedLen > targetLen)
{
NAWchar * first_nonblank =
wc_str_find_first_nonblank(&((wBuf->data())[targetLen/BYTES_PER_NAWCHAR]),
(convertedLen - targetLen) / BYTES_PER_NAWCHAR);
if (first_nonblank) // if truncated portion isn't all blanks
{
if (dataConversionErrorFlag) // want conversion flag instead of warning?
{
// yes - determine whether target is greater than or less than source
// note assumption: UNICODE character set
if (*first_nonblank < unicode_char_set::space_char())
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
else
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
else
// no - raise a warning
ExRaiseSqlWarning(heap, diagsArea, EXE_STRING_OVERFLOW);
}
}
NADELETE(wBuf, NAWcharBuf, heap);
} else {
convertedLen = 0;
copyLen = 0;
}
// There is no need to change the char string storage format
// for Unicode string.
if ( varCharLen && index != CONV_ASCII_TO_ANSI_V_UNICODE )
setVCLength(varCharLen, varCharLenSize, copyLen);
if ( index == CONV_ASCII_TO_ANSI_V_UNICODE )
{
((NAWchar*)target)[copyLen/BYTES_PER_NAWCHAR] = 0;
}
};
break;
// 12/8/97: Unicode -> ASCII
case CONV_UNICODE_F_ASCII_F: // unicode -> ascii
case CONV_UNICODE_V_ASCII_F: // unicode -> ascii
case CONV_ANSI_V_UNICODE_TO_ASCII_F: // ansi unicode -> ascii
{
if (targetScale == (Lng32) SQLCHARSETCODE_UTF8 ||
targetScale == (Lng32) SQLCHARSETCODE_SJIS)
{
return
unicodeToMByteTarget(
(targetScale == (Lng32) SQLCHARSETCODE_UTF8) ? unicodeToUtf8 : unicodeToSjis,
source,
sourceLen,
target,
targetLen,
targetPrecision,
targetScale,
0/*varCharLen*/, 0/*varCharLenSize*/,
heap,
diagsArea,
dataConversionErrorFlag,
flags & CONV_ALLOW_INVALID_CODE_VALUE,
TRUE /* pad space*/);
}
else
return
unicodeToSByteTarget(
unicodeToISO88591,
source,
sourceLen,
target,
targetLen,
0, 0,
heap,
diagsArea,
dataConversionErrorFlag,
flags & CONV_ALLOW_INVALID_CODE_VALUE,
TRUE /* pad space*/);
};
break;
case CONV_UNICODE_F_ANSI_V: // unicode F -> ansi_v
case CONV_UNICODE_V_ANSI_V: // unicode V -> ansi_v
{
Int32 tempTargetLen = sourceLen;
char * tempTarget = new (heap) char[tempTargetLen];
ex_expr::exp_return_type ok =
convDoIt(source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
tempTarget,
tempTargetLen,
REC_BYTE_F_ASCII,
targetPrecision,
targetScale,
varCharLen, // NULL if not a varChar
varCharLenSize, // 0 if not a varChar
heap,
diagsArea,
(index==CONV_UNICODE_F_ANSI_V) ?
CONV_UNICODE_F_ASCII_F : CONV_UNICODE_V_ASCII_F,
dataConversionErrorFlag,
tempFlags | CONV_INTERMEDIATE_CONVERSION
);
if ( ok == ex_expr::EXPR_OK ) {
convDoIt(tempTarget,
tempTargetLen/BYTES_PER_NAWCHAR, // the number of bytes in the tempTarget buffer
REC_BYTE_F_ASCII, // is half that of the original Unicode version.
targetPrecision, // we already converted to the target precision
targetScale, // and scale
target,
targetLen,
targetType,
targetPrecision,
targetScale,
varCharLen, // NULL if not a varChar
varCharLenSize, // 0 if not a varChar
heap,
diagsArea,
CONV_ASCII_TO_ANSI_V,
dataConversionErrorFlag,
tempFlags | CONV_INTERMEDIATE_CONVERSION
);
}
NADELETEBASIC(tempTarget, heap);
}
break;
case CONV_ANSI_V_UNICODE_TO_ASCII_V: // ansi unicode (null terminalted)-> ascii
{
// LCOV_EXCL_START
NAWchar* w_source = (NAWchar*)source;
Lng32 w_sourceLen = sourceLen/BYTES_PER_NAWCHAR;
Lng32 i = 0;
while ((i < w_sourceLen) && (w_source[i] != 0))
i++;
if (i == w_sourceLen) {
ExRaiseSqlError(heap, diagsArea, EXE_MISSING_NULL_TERMINATOR);
return ex_expr::EXPR_ERROR;
};
sourceLen = i*BYTES_PER_NAWCHAR;
}
// LCOV_EXCL_STOP
//fall through
// 6/11/98: Unicode -> ASCII
case CONV_UCS2_F_UTF8_V:
case CONV_UNICODE_F_ASCII_V: // unicode -> ascii
case CONV_UNICODE_V_ASCII_V: // unicode -> ascii
{
if (targetScale == (Lng32) SQLCHARSETCODE_UTF8 ||
targetScale == (Lng32) SQLCHARSETCODE_SJIS)
{
return
unicodeToMByteTarget(
(targetScale == (Lng32) SQLCHARSETCODE_UTF8) ? unicodeToUtf8 : unicodeToSjis,
source,
sourceLen,
target,
targetLen,
targetPrecision,
targetScale,
varCharLen,
varCharLenSize,
heap,
diagsArea,
dataConversionErrorFlag,
flags & CONV_ALLOW_INVALID_CODE_VALUE,
FALSE);
}
else
return
unicodeToSByteTarget(
unicodeToISO88591,
source,
sourceLen,
target,
targetLen,
varCharLen,
varCharLenSize,
heap,
diagsArea,
dataConversionErrorFlag,
flags & CONV_ALLOW_INVALID_CODE_VALUE);
};
break;
// 5/14/98: Unicode -> SJIS (V)
case CONV_UNICODE_F_SJIS_V: // unicode -> sjis
case CONV_UNICODE_V_SJIS_V: // unicode -> sjis
{
return
unicodeToMByteTarget(
unicodeToSjis,
source,
sourceLen,
target,
targetLen,
targetPrecision,
targetScale,
varCharLen,
varCharLenSize,
heap,
diagsArea,
dataConversionErrorFlag,
flags & CONV_ALLOW_INVALID_CODE_VALUE);
};
break;
//UR2. Revisit in CharSet project. This case may not be valid anymore.
case CONV_UNICODE_F_SBYTE_LOCALE_F: // unicode -> single-byte locale
case CONV_UNICODE_V_SBYTE_LOCALE_F: // unicode -> single-byte locale
{
if (targetScale == (Lng32) SQLCHARSETCODE_UTF8 ||
targetScale == (Lng32) SQLCHARSETCODE_SJIS)
{
return
unicodeToMByteTarget(
(targetScale == (Lng32) SQLCHARSETCODE_UTF8) ? unicodeToUtf8 : unicodeToSjis,
source,
sourceLen,
target,
targetLen,
targetPrecision,
targetScale,
0/*varCharLen*/, 0/*varCharLenSize*/,
heap,
diagsArea,
dataConversionErrorFlag,
flags & CONV_ALLOW_INVALID_CODE_VALUE,
TRUE /* pad space */);
}
else
return
unicodeToSByteTarget(
unicodeToISO88591,
source,
sourceLen,
target,
targetLen,
0, 0,
heap,
diagsArea,
dataConversionErrorFlag,
flags & CONV_ALLOW_INVALID_CODE_VALUE,
TRUE /* pad space */
);
};
break;
// 5/10/98: Unicode -> SJIS (F)
case CONV_UNICODE_F_SJIS_F: // unicode -> sjis
case CONV_UNICODE_V_SJIS_F: // unicode -> sjis
{
return
unicodeToMByteTarget(
unicodeToSjis,
source,
sourceLen,
target,
targetLen,
targetPrecision,
targetScale,
0, 0,
heap,
diagsArea,
dataConversionErrorFlag,
flags & CONV_ALLOW_INVALID_CODE_VALUE,
TRUE /* pad space*/);
};
break;
//UR2. Revisit in CharSet project. This case may not be valid anymore.
case CONV_UNICODE_F_MBYTE_LOCALE_F: // unicode -> multi-byte locale
case CONV_UNICODE_V_MBYTE_LOCALE_F: // unicode -> multi-byte locale
{
if (targetScale == (Lng32) SQLCHARSETCODE_UTF8 ||
targetScale == (Lng32) SQLCHARSETCODE_SJIS)
{
return
unicodeToMByteTarget(
(targetScale == (Lng32) SQLCHARSETCODE_UTF8) ? unicodeToUtf8 : unicodeToSjis,
source,
sourceLen,
target,
targetLen,
targetPrecision,
targetScale,
varCharLen,
varCharLenSize,
heap,
diagsArea,
dataConversionErrorFlag,
flags & CONV_ALLOW_INVALID_CODE_VALUE,
TRUE /* pad space */);
}
else
return
unicodeToMByteTarget(
unicodeToISO88591,
source,
sourceLen,
target,
targetLen,
targetPrecision,
targetScale,
varCharLen,
varCharLenSize,
heap,
diagsArea,
dataConversionErrorFlag,
flags & CONV_ALLOW_INVALID_CODE_VALUE,
TRUE /* pad space */);
};
break;
case CONV_ANSI_V_UNICODE_TO_UNICODE_V: // ANSI VARNCHAR -> unicode (V)
{
NAWchar* w_source = (NAWchar*)source;
Lng32 w_sourceLen = sourceLen/BYTES_PER_NAWCHAR;
Lng32 i = 0;
while ((i < w_sourceLen) && (w_source[i] != 0))
i++;
if (i == w_sourceLen) {
ExRaiseSqlError(heap, diagsArea, EXE_MISSING_NULL_TERMINATOR);
return ex_expr::EXPR_ERROR;
};
sourceLen = i*BYTES_PER_NAWCHAR;
return
convDoIt(source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
target,
targetLen,
targetType,
targetPrecision,
targetScale,
varCharLen,
varCharLenSize,
heap,
diagsArea,
CONV_UNICODE_V_V, // unicode (V) -> unicode (V)
dataConversionErrorFlag,
tempFlags);
};
break;
case CONV_UNICODE_F_V: // unicode (F) -> unicode (V)
case CONV_UNICODE_V_V: // unicode (V) -> unicode (V)
{
Lng32 copyLen = ((targetLen >= sourceLen) ? sourceLen : targetLen);
str_cpy_all(target, source, copyLen);
// There is no need to change the char string storage format
// for Unicode string.
setVCLength(varCharLen, varCharLenSize, copyLen);
if (targetLen < sourceLen)
{
NAWchar* first_nonblank = wc_str_find_first_nonblank(
(NAWchar*)(&source[targetLen]), (sourceLen - targetLen) >> 1);
if (first_nonblank) // if truncated portion isn't all blanks
{
if (dataConversionErrorFlag) // want conversion flag instead of warning?
{
// yes - determine whether target is greater than or less than source
if (*first_nonblank < unicode_char_set::space_char() )
// note assumption: UNICODE character set
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
else
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
else
// no - raise a warning
ExRaiseSqlWarning(heap, diagsArea, EXE_STRING_OVERFLOW);
}
}
};
break;
// 6/26/98: ANSI VARNCHAR support
case CONV_UNICODE_TO_ANSI_V_UNICODE: // unicode -> ANSI VARNCHAR
case CONV_ANSI_V_UNICODE_TO_ANSI_V_UNICODE: // ANSI VARNCHAR-> ANSI VARNCHAR
{
if ( index == CONV_ANSI_V_UNICODE_TO_ANSI_V_UNICODE ) {
NAWchar* w_source = (NAWchar*)source;
Lng32 w_sourceLen = sourceLen/BYTES_PER_NAWCHAR;
Lng32 i = 0;
while ((i < w_sourceLen) && (w_source[i] != 0))
i++;
if (i == w_sourceLen) {
ExRaiseSqlError(heap, diagsArea, EXE_MISSING_NULL_TERMINATOR);
return ex_expr::EXPR_ERROR;
};
sourceLen = BYTES_PER_NAWCHAR*i;
}
Lng32 localVarCharLen = 0;
ex_expr::exp_return_type ok
= convDoIt(source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
target,
targetLen-2, // exclude the null terminator (two bytes)
targetType,
targetPrecision,
targetScale,
(char*)&localVarCharLen,
sizeof(localVarCharLen),
heap,
diagsArea,
CONV_UNICODE_V_V, // unicode (V) -> unicode (V)
dataConversionErrorFlag,
tempFlags);
if ( ok == ex_expr::EXPR_OK )
((NAWchar*)target)[localVarCharLen/BYTES_PER_NAWCHAR] = 0;
return ok;
};
break;
case CONV_ANSI_V_TO_ASCII_F: {
// find out the number of characters in the source string.
// Source string is terminated by a null character.
Lng32 i = 0;
while ((i < sourceLen) && (source[i] != 0))
i++;
if (i == sourceLen) {
ExRaiseSqlError(heap, diagsArea, EXE_MISSING_NULL_TERMINATOR);
return ex_expr::EXPR_ERROR;
};
// disregard the null terminator
sourceLen = i;
};
// fall thru
case CONV_ASCII_F_F:
case CONV_ASCII_V_F:
{
// check for needed character conversions or validations
if (requiresNoConvOrVal(sourceLen, sourcePrecision, sourceScale,
targetLen, targetPrecision, targetScale, index))
{
Lng32 copyLen = ((targetLen >= sourceLen) ? sourceLen : targetLen);
// this case can often be translated into PCODE
if (targetLen > copyLen)
{
if (leftPad)
{
str_pad(target, targetLen - copyLen, ' ');
str_cpy_all(&target[targetLen - copyLen], source, copyLen);
}
else
{
str_cpy_all(target, source, copyLen);
/* blank pad target */
str_pad(&target[copyLen], targetLen - copyLen, ' ');
}
}
else // targetLen <= copyLen
{
str_cpy_all(target, source, copyLen);
if (copyLen < sourceLen)
{
char * first_nonblank = str_find_first_nonblank(
&source[copyLen], sourceLen - copyLen);
if (first_nonblank) // if truncated portion isn't all blanks
{
if (dataConversionErrorFlag) // want conversion flag instead of warning?
{
// yes - determine whether target is greater than or less than source
if (*(unsigned char *)first_nonblank < ' ') // note assumption: charset uses ASCII blank
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
else
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
else
// no - raise a warning
ExRaiseSqlWarning(heap, diagsArea, EXE_STRING_OVERFLOW);
}
}
}
}
else
{
// this case isn't translated into PCODE at this time
if (convCharToChar(source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
target,
targetLen,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
dataConversionErrorFlag,
NULL,
TRUE,
TRUE,
flags & CONV_ALLOW_INVALID_CODE_VALUE)
!= ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
}
}
break;
case CONV_ANSI_V_UNICODE_TO_UNICODE_F:
{
// calcualte the sourceLen by searching for the NULL
NAWchar* w_source = (NAWchar*)source;
Lng32 w_sourceLen = sourceLen/BYTES_PER_NAWCHAR;
Lng32 i = 0;
while ((i < w_sourceLen) && (w_source[i] != 0))
i++;
if (i == w_sourceLen) {
ExRaiseSqlError(heap, diagsArea, EXE_MISSING_NULL_TERMINATOR);
return ex_expr::EXPR_ERROR;
};
sourceLen = BYTES_PER_NAWCHAR*i;
}
// fall through
// 12/8/97: added for Unicode
case CONV_UNICODE_F_F:
case CONV_UNICODE_V_F:
{
if (targetLen > sourceLen)
{
str_cpy_all(target, source, sourceLen);
/* blank pad target */
wc_str_pad((NAWchar*)(&target[sourceLen]), (targetLen - sourceLen) >> 1);
}
else
{
str_cpy_all(target, source, targetLen);
if (targetLen < sourceLen)
{
NAWchar * first_nonblank = wc_str_find_first_nonblank(
(NAWchar*)(&source[targetLen]), (sourceLen - targetLen) >> 1);
if (first_nonblank) // if truncated portion isn't all blanks
{
if (dataConversionErrorFlag) // want conversion flag instead of warning?
{
// yes - determine whether target is greater than or less than source
// note assumption: UNICODE character set
if (*first_nonblank < unicode_char_set::space_char())
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_UP;
else
*dataConversionErrorFlag = ex_conv_clause::CONV_RESULT_ROUNDED_DOWN;
}
else
// no - raise a warning
ExRaiseSqlWarning(heap, diagsArea, EXE_STRING_OVERFLOW);
}
}
};
};
break;
case CONV_ASCII_TO_ANSI_V: {
// check for needed character conversions or validations
if (requiresNoConvOrVal(sourceLen, sourcePrecision, sourceScale,
targetLen, targetPrecision, targetScale, index))
{
// max target length includes one byte (the end byte) for null
// terminator.
targetLen--;
if (targetLen >= sourceLen) {
str_cpy_all(target, source, sourceLen);
// put null character at the end
target[sourceLen] = 0;
}
else {
str_cpy_all(target, source, targetLen);
// put null character at the end
target[targetLen] = 0;
if ((targetLen < sourceLen) &&
str_find_first_nonblank(&source[targetLen], sourceLen - targetLen))
ExRaiseSqlWarning(heap, diagsArea, EXE_STRING_OVERFLOW);
}
}
else
{
Lng32 convertedDataLen;
if (convCharToChar(source,
sourceLen,
sourceType,
sourcePrecision,
sourceScale,
target,
targetLen,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
dataConversionErrorFlag,
&convertedDataLen,
FALSE,
TRUE,
flags & CONV_ALLOW_INVALID_CODE_VALUE)
!= ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
// put null character at the end
target[convertedDataLen] = 0;
}
};
break;
case CONV_ANSI_V_TO_ANSI_V:
// max source length includes one byte (the end byte) for null
// terminator.
// max target length includes one byte (the end byte) for null
// terminator.
targetLen--;
// fall through to next
case CONV_ANSI_V_TO_ASCII_V: {
// max source length includes one byte (the end byte) for null
// terminator.
// find out the number of characters in the source string.
// Source string is terminated by a null character.
Lng32 actSourceLen = 0;
while ((actSourceLen < sourceLen) && (source[actSourceLen] != 0))
actSourceLen++;
if (actSourceLen == sourceLen) {
ExRaiseSqlError(heap, diagsArea, EXE_MISSING_NULL_TERMINATOR);
return ex_expr::EXPR_ERROR;
};
// check for needed character conversions or validations
if (requiresNoConvOrVal(actSourceLen, sourcePrecision, sourceScale,
targetLen, targetPrecision, targetScale, index))
{
if (targetLen >= actSourceLen) {
str_cpy_all(target, source, actSourceLen);
if (index == CONV_ANSI_V_TO_ASCII_V) {
setVCLength(varCharLen, varCharLenSize, actSourceLen);
}
else {
target[actSourceLen] = 0;
}
setVCLength(varCharLen, varCharLenSize, actSourceLen);
}
else {
str_cpy_all(target, source, targetLen);
if (index == CONV_ANSI_V_TO_ASCII_V) {
setVCLength(varCharLen, varCharLenSize, targetLen);
}
else {
target[targetLen] = 0;
}
if (str_find_first_nonblank(&source[targetLen], actSourceLen - targetLen))
ExRaiseSqlWarning(heap, diagsArea, EXE_STRING_OVERFLOW);
}
}
else
{
Lng32 convertedDataLen;
if (convCharToChar(source,
actSourceLen,
sourceType,
sourcePrecision,
sourceScale,
target,
targetLen,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
dataConversionErrorFlag,
&convertedDataLen,
FALSE,
TRUE,
flags & CONV_ALLOW_INVALID_CODE_VALUE)
!= ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
if (index == CONV_ANSI_V_TO_ASCII_V) {
setVCLength(varCharLen, varCharLenSize, convertedDataLen);
}
else {
target[convertedDataLen] = 0;
}
}
};
break;
case CONV_BIN64S_DATETIME:
{
NABoolean LastDayFlag = FALSE;
// numeric to date conversion uses the formula:
// dt = (year - 1900) * 10000 + month * 100 + day
Int64 nVal = *(Int64*)source;
Int64 year = (nVal / 10000);
Int64 month = (nVal - (year * 10000)) / 100;
Int64 day = (nVal - (year * 10000) - (month * 100));
year = year + 1900;
if ((year > SHRT_MAX) ||
(month > CHAR_MAX) ||
(day > CHAR_MAX))
{
ExRaiseSqlError(heap, diagsArea, EXE_DATETIME_FIELD_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
// date is of the form: YYMD
*(short*)target = (short)year;
target[2] = (char)month;
target[3] = (char)day;
// validate the date
if (ExpDatetime::validateDate(REC_DATE_YEAR, REC_DATE_DAY,
target, NULL, FALSE, LastDayFlag) != 0)
{
ExRaiseSqlError(heap, diagsArea, EXE_DATETIME_FIELD_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
}
break;
case CONV_DATETIME_BIN64S:
{
// date to numeric conversion uses the formula:
// numeric = (year - 1900) * 10000 + month * 100 + day
Int32 year = *(short*)source;
Int32 month = source[2];
Int32 day = source[3];
*(Int64*)target = (year - 1900)* 10000 + month * 100 + day;
}
break;
case CONV_BLOB_BLOB:
{
str_cpy_all(target, source, sourceLen);
setVCLength(varCharLen, varCharLenSize, sourceLen);
}
break;
case CONV_BLOB_ASCII_F:
{
// conversion from internal format blob handle to external format
// should have been done by calling the ExpLOBconvertHandle function.
// By the time it reaches here, the source is already in the right
// format, either internal or external.
// It can be just copied to the target.
str_pad(target, targetLen, ' ');
str_cpy_all(target, source, sourceLen);
}
break;
case CONV_BOOL_BOOL:
{
if ((*(Int8*)source == 1) ||
(*(Int8*)source == 0))
*(Int8*)target = *(Int8*)source;
else
{
char tempBuf[10];
str_itoa(*(Int8*)source, tempBuf);
ExRaiseSqlError(heap, diagsArea, EXE_INVALID_BOOLEAN_VALUE,
NULL, NULL, NULL, NULL,
tempBuf);
return ex_expr::EXPR_ERROR;
}
}
break;
case CONV_BOOL_ASCII:
{
char boolbuf[10];
if (*(Int8*)source == 1)
strcpy(boolbuf, "TRUE");
else if (*(Int8*)source == 0)
strcpy(boolbuf, "FALSE");
else
{
char tempBuf[10];
str_itoa(*(Int8*)source, tempBuf);
ExRaiseSqlError(heap, diagsArea, EXE_INVALID_BOOLEAN_VALUE,
NULL, NULL, NULL, NULL,
tempBuf);
return ex_expr::EXPR_ERROR;
}
// this case isn't translated into PCODE at this time
Lng32 convertedDataLen;
if (convCharToChar(boolbuf, strlen(boolbuf), REC_BYTE_F_ASCII,
0, SQLCHARSETCODE_ISO88591,
target,
targetLen,
targetType,
targetPrecision,
targetScale,
heap,
diagsArea,
NULL,
&convertedDataLen,
((varCharLenSize > 0) ? FALSE : TRUE),
TRUE,
FALSE)
!= ex_expr::EXPR_OK)
return ex_expr::EXPR_ERROR;
if (varCharLenSize > 0)
setVCLength(varCharLen, varCharLenSize, convertedDataLen);
}
break;
case CONV_ASCII_BOOL:
{
char srcTempBuf[sourceLen+1];
str_cpy_convert(srcTempBuf, source, sourceLen, 1);
srcTempBuf[sourceLen] = 0;
Lng32 tempLen;
char * srcTempPtr = srcTempBuf;
srcTempPtr = str_strip_blanks(srcTempBuf, tempLen, TRUE, TRUE);
if ((strcmp(srcTempPtr, "TRUE") == 0) ||
(strcmp(srcTempPtr, "1") == 0))
*(Int8*)target = 1;
else if ((strcmp(srcTempPtr, "FALSE") == 0) ||
(strcmp(srcTempPtr, "0") == 0))
*(Int8*)target = 0;
else
{
char srcErrBuf[sourceLen + 1 + 2/*for quotes*/];
strcpy(srcErrBuf, "'");
str_cpy_all(&srcErrBuf[1], source, sourceLen);
srcErrBuf[1+sourceLen]=0;
strcat(srcErrBuf, "'");
ExRaiseSqlError(heap, diagsArea, EXE_INVALID_BOOLEAN_VALUE,
NULL, NULL, NULL, NULL,
srcErrBuf);
return ex_expr::EXPR_ERROR;
}
}
break;
case CONV_NOT_SUPPORTED:
default:
{
ExRaiseDetailSqlError(heap, diagsArea, EXE_CONVERT_NOT_SUPPORTED,
source,
sourceLen,
sourceType,
sourceScale,
targetType,
flags,
targetLen,
targetScale);
// this conversion is not supported.
// ExRaiseSqlError(heap, diagsArea, EXE_CONVERT_NOT_SUPPORTED);
return ex_expr::EXPR_ERROR;
}
break;
};
return ex_expr::EXPR_OK;
}
#pragma warning (default : 4101) //warning elimination
ex_expr::exp_return_type ex_conv_clause::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea** diagsArea) {
Attributes * tgt = getOperand(0);
Attributes * src = getOperand(1);
ex_expr::exp_return_type retcode = ex_expr::EXPR_OK;
Lng32 warningMark = 0;
if (lastVOAoffset_ > 0)
{// case of cif bulk move
char * srcData = op_data[1];
char * tgtData = op_data[0];
UInt32 copyLength = 0;
if (*(Int32*)srcData ==-1 ) //if aliggned format header is 0xFFFFFFFF
{// case of null instantiated row
assert(*(Int16*)&srcData[lastVOAoffset_] ==-1);
copyLength = ((SimpleType*)src)->getLength();
}
else
{
copyLength = ExpTupleDesc::getVarOffset( srcData,
UINT_MAX, //offset
lastVOAoffset_, // voaEntryOffset
lastVcIndicatorLength_,
lastNullIndicatorLength_);
copyLength += ExpTupleDesc::getVarLength( srcData + copyLength,
lastVcIndicatorLength_ );
copyLength += lastVcIndicatorLength_;
}
assert(copyLength > 0 && copyLength <=(UInt32)((SimpleType*)src)->getLength());
#if defined(_DEBUG)
char * envCifLoggingLocation= getenv("CIF_BM_LOG_LOC");
//
if (envCifLoggingLocation)
{
char file2 [255];
snprintf(file2,255,"%s/bm_logging.log", envCifLoggingLocation);
FILE * p2 = NULL;
p2 =fopen(file2, "a");
if (p2== NULL)
{
printf("Error in opening file %s\n", file2);
}
if (copyLength <=0 || copyLength >= (UInt32)((SimpleType*)src)->getLength())
{
fprintf(p2,"%s%d\t%s%d\n","copylength:",copyLength,"maxLength:",((SimpleType*)src)->getLength());
}
fclose(p2);
}
#endif
UInt32 newLen = copyLength;
str_cpy_all(tgtData,srcData,copyLength);
if ( alignment_ > 0 )
{
newLen = ExpAlignedFormat::adjustDataLength(tgtData, copyLength, alignment_, FALSE) ;
}
computedLength_ = newLen;
return ex_expr::EXPR_OK;
}
if (getCheckTruncationFlag() || getNoTruncationWarningsFlag())
if (*diagsArea)
warningMark= (*diagsArea)->getNumber(DgSqlCode::WARNING_);
else
warningMark = 0;
switch (getInstruction()) {
case CONV_COMPLEX_TO_COMPLEX: {
if (((ComplexType *)tgt)->conv(src, op_data) != 0) {
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, this,
op_data);
return ex_expr::EXPR_ERROR;
}
};
break;
case CONV_SIMPLE_TO_COMPLEX: {
if (((ComplexType *)tgt)->castFrom(src, op_data, heap, diagsArea) != 0) {
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, this,
op_data);
return ex_expr::EXPR_ERROR;
}
};
break;
case CONV_COMPLEX_TO_SIMPLE: {
if (((ComplexType *)src)->castTo(tgt, op_data, heap, diagsArea) != 0) {
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW, this,
op_data);
return ex_expr::EXPR_ERROR;
}
};
break;
default: {
Lng32 * dataConversionErrorFlag = 0;
if (getNumOperands() == 3)
{
dataConversionErrorFlag = (Lng32 *)op_data[2];
}
ULng32 convFlags = 0;
if (treatAllSpacesAsZero())
convFlags |= CONV_TREAT_ALL_SPACES_AS_ZERO;
if (allowSignInInterval())
convFlags |= CONV_ALLOW_SIGN_IN_INTERVAL;
if (noDatetimeValidation())
convFlags |= CONV_NO_DATETIME_VALIDATION;
char * source = op_data[1];
if (srcIsVarcharPtr())
{
Int64 ptrVal = *(Int64*)op_data[1];
source = (char*)ptrVal;
}
#pragma nowarn(1506) // warning elimination
retcode = convDoIt(source, //op_data[1],
src->getLength(op_data[-MAX_OPERANDS + 1]),
src->getDatatype(),
src->getPrecision(),
src->getScale(),
op_data[0],
tgt->getLength(),
tgt->getDatatype(),
tgt->getPrecision(),
tgt->getScale(),
op_data[-MAX_OPERANDS],
tgt->getVCIndicatorLength(),
heap,
diagsArea,
getInstruction(),
dataConversionErrorFlag,
convFlags
);
#pragma warn(1506) // warning elimination
if ((flags_ & REVERSE_DATA_ERROR_CONVERSION_FLAG) != 0)
{
if (dataConversionErrorFlag && (*dataConversionErrorFlag >= -2 && *dataConversionErrorFlag <= 2))
{
*dataConversionErrorFlag = -(*dataConversionErrorFlag);
}
}
if( retcode != ex_expr::EXPR_OK && ( flags_ & CONV_TO_NULL_WHEN_ERROR ) != 0)
{
//move null to target
if(tgt->getNullFlag())
{
ExpTupleDesc::setNullValue( op_data[-2*MAX_OPERANDS],
tgt->getNullBitIndex(),
tgt->getTupleFormat() );
retcode = ex_expr::EXPR_OK;
}
}
};
}; // switch
// If this conv clause came from either an update or an insert, and if
// the data types are char types and the target size is smaller than source
// size, the checkTruncError flag should be set.
// In this section, if the flag is set, and a warning is returned as the
// result of the conversion, an error should be issued instead of a warning.
// This is according to ANSI SQL92
// If this is for SPECIAL1_MODE, then neither warnings nor errors should be
// returned for truncations of char types on inserts and updates.
if (getCheckTruncationFlag() && *diagsArea) {
Int32 warningMark2 = (*diagsArea)->getNumber(DgSqlCode::WARNING_);
Int32 counter = warningMark2 - warningMark;
while (counter) {
if (((*diagsArea)->getWarningEntry(warningMark2 - counter + 1))->
getSQLCODE() == EXE_STRING_OVERFLOW) {
(*diagsArea)->deleteWarning(warningMark2-counter);
ExRaiseDetailSqlError(heap, diagsArea, EXE_STRING_OVERFLOW,
op_data[1],
src->getLength(op_data[-MAX_OPERANDS + 1]),
src->getDatatype(),
src->getScale(),
tgt->getDatatype(),
0,
tgt->getLength(),
tgt->getScale(),
tgt->getPrecision());
retcode = ex_expr::EXPR_ERROR;
}
else if (((*diagsArea)->getWarningEntry(warningMark2 - counter + 1))->
getSQLCODE() == EXE_NUMERIC_OVERFLOW) {
(*diagsArea)->deleteWarning(warningMark2-counter);
ExRaiseDetailSqlError(heap, diagsArea, EXE_NUMERIC_OVERFLOW,
this, op_data);
retcode = ex_expr::EXPR_ERROR;
}
counter--;
}
}
if (getNoTruncationWarningsFlag() && *diagsArea) {
Int32 warningMark2 = (*diagsArea)->getNumber(DgSqlCode::WARNING_);
Int32 counter = warningMark2 - warningMark;
while (counter) {
if (((*diagsArea)->getWarningEntry(warningMark2 - counter + 1))->
getSQLCODE() == EXE_STRING_OVERFLOW) {
(*diagsArea)->deleteWarning(warningMark2-counter);
}
else if (((*diagsArea)->getWarningEntry(warningMark2 - counter + 1))->
getSQLCODE() == EXE_NUMERIC_OVERFLOW) {
(*diagsArea)->deleteWarning(warningMark2-counter);
}
counter--;
}
}
return retcode;
};
ex_expr::exp_return_type ex_conv_clause::processNulls(char *op_data[],
CollHeap *heap,
ComDiagsArea **diagsArea)
{
Attributes *tgtAttr = getOperand(0);
if (getOperand(1)->getNullFlag() && // if input operand is nullable
(!op_data[1])) // and it is null
{
if (tgtAttr->getNullFlag()) // if result is nullable
{
// move null value to result
char *rslt = op_data[0];
// For a null value, DP2 expects the rest of the field to be 0,
// for SQL/MP tables, but we can do it for all.
if (tgtAttr->getTupleFormat() == ExpTupleDesc::SQLMX_ALIGNED_FORMAT)
{
// For aligned format the null and variable length and value
// are not in contiguous memory, thus zero out the variable
// length (if variable field) and value memory separately.
rslt = ( (tgtAttr->getVCIndicatorLength() > 0)
? op_data[ ex_clause::MAX_OPERANDS ]
: op_data[ 2 * ex_clause::MAX_OPERANDS ] );
}
str_pad(rslt,
tgtAttr->getLength() +
tgtAttr->getNullIndicatorLength() +
tgtAttr->getVCIndicatorLength(),
'\0');
ExpTupleDesc::setNullValue(op_data[0],
tgtAttr->getNullBitIndex(),
tgtAttr->getTupleFormat());
}
else // result is not nullable
{
// Attempt to put NULL into column with
// NOT NULL NONDROPPABLE constraint.
if (getNumOperands() != 3)
{
ExRaiseSqlError(heap, diagsArea, EXE_ASSIGNING_NULL_TO_NOT_NULL);
return ex_expr::EXPR_ERROR;
}
else // data conversion error flag is present
{ // begin fix to CR 10-040430-8520: regress/core/test005 fails in MP
// after a query caching fix changed NumericType::errorsCanOccur()
// to return true if an underflow/overflow can occur when doing a
// cast or a narrow from, say, an IEEE float to a Tandem REAL type.
// In the CR, "select * from t where e is null" is forced via CQS
// to use an index for e. t is an MP table. e is type Tandem REAL.
// The errorsCanOccur() fix causes ExpGenerator::generateKeyCast()
// to generate a "narrow ieee null constant to Tandem REAL" instead
// of "cast ieee null constant to Tandem REAL". At runtime, this
// method interprets "narrow ieee null constant to Tandem REAL"
// and incorrectly assumes it found a NULL primary key value (a
// contradiction). The correct behavior is to declare a conversion
// failure iff the target is not nullable and the source is null.
// set it to note that a conversion has failed
Lng32 *dataConversionErrorFlag =
(Lng32 *)op_data[2 * ex_clause::MAX_OPERANDS + 2];
*dataConversionErrorFlag = CONV_RESULT_FAILED;
// end fix to CR 10-040430-8520
// If target is varchar, it's important to clear out the length
// so that if it gets used (e.g. conversion error is ignored),
// then a bogus length would not be accessed
if (tgtAttr->getVCIndicatorLength() > 0) {
char* rslt = op_data[ ex_clause::MAX_OPERANDS ];
str_pad(rslt, tgtAttr->getVCIndicatorLength(), '\0');
}
// Make sure the data portion of target is cleared so
// that if it is used for partitioning, all data
// conversion error rows will be repartitioned to the
// same partition. Note that is some cases the
// dataCoversionErrorFlag is not properly used.
char* rslt = op_data[2* ex_clause::MAX_OPERANDS ];
str_pad(rslt, tgtAttr->getLength(), '\0');
}
}
return ex_expr::EXPR_NULL; // indicate that a null input was processed
}
// first operand is not null -- set null indicator in result if nullable
if (tgtAttr->getNullFlag())
{
ExpTupleDesc::clearNullValue(op_data[0],
tgtAttr->getNullBitIndex(),
tgtAttr->getTupleFormat());
}
return ex_expr::EXPR_OK; // indicate input is not null
};
////////////////////////////////////////////////////////////////////////
// up- or downscale an exact numeric.
////////////////////////////////////////////////////////////////////////
NA_EIDPROC
SQLEXP_LIB_FUNC
ex_expr::exp_return_type scaleDoIt(char *operand,
Lng32 operandLen,
Lng32 operandType,
Lng32 operandCurrScale,
Lng32 newScale,
Lng32 typeOfOldScale,
CollHeap * heap) {
// return if there is no difference in scale or if "newScale"
// is really a character set, used when the old representation
// of the value was a character type. Note that in that case,
// convDoIt has already scaled the value to the correct amount.
if (operandCurrScale == newScale ||
DFS2REC::isAnyCharacter(typeOfOldScale))
return ex_expr::EXPR_OK;
Int64 intermediate = 0;
double intermediateDouble = 0;
char* intermediateString = 0;
char *decimalString = 0;
NABoolean negativeNum = FALSE;
// variable used for float operation. Specified in "pragma refligned..."
float *floatOperandPtr;
double *doubleOperandPtr;
Int64 limit = 0;
switch (operandType) {
case REC_BIN16_SIGNED: {
intermediate = (Int64) *(short*)operand;
limit = (Int64)((intermediate > 0) ? (SHRT_MAX/10) : (SHRT_MIN/10));
}
break;
case REC_BIN16_UNSIGNED: {
intermediate = (Int64) *(unsigned short*)operand;
limit = (Int64)(USHRT_MAX/10);
}
break;
case REC_BIN32_SIGNED: {
intermediate = (Int64) *(Int32*)operand;
limit = (Int64)((intermediate > 0) ? (INT_MAX/10) : (INT_MIN/10));
}
break;
case REC_BIN32_UNSIGNED: {
intermediate = (Int64) *(UInt32*)operand;
limit = (Int64)(UINT_MAX/10);
}
break;
case REC_BIN64_SIGNED: {
intermediate = *(Int64*)operand;
limit = (Int64)((intermediate > 0) ? (LLONG_MAX/10) : (LLONG_MIN/10));
}
break;
case REC_FLOAT32: {
floatOperandPtr = (float *)operand;
intermediateDouble = *floatOperandPtr; //(double) *(float*)operand;
}
break;
case REC_FLOAT64: {
doubleOperandPtr = (double *)operand;
intermediateDouble = *doubleOperandPtr; //*(double*)operand;
}
break;
case REC_DECIMAL_LSE: {
case REC_DECIMAL_UNSIGNED:
// Check if the first bit is set
negativeNum = operand[0] & 0x80;
if (negativeNum)
operand[0] &= 0x7F;
decimalString = operand;
}
break;
case REC_DECIMAL_LS: {
intermediateString = operand;
}
break;
case REC_NUM_BIG_SIGNED:
case REC_NUM_BIG_UNSIGNED: {
// not yet supported
return ex_expr::EXPR_ERROR;
intermediateString = operand;
}
break;
default:
return ex_expr::EXPR_ERROR;
// LCOV_EXCL_STOP
};
Lng32 scale = operandCurrScale - newScale;
if (intermediate != 0) {
// do calculations only, if intermediate is not 0.
if (scale > 0) {
// operandCurrScale in greater than newScale, we have to downscale
// we can stop if intermediate is 0
while (intermediate && scale--)
intermediate /= 10;
}
else {
// we have to upscale.
while(scale++) {
if (((intermediate < 0) && (intermediate < limit)) ||
((intermediate > 0) && (intermediate > limit))) {
// the next multiplication causes an overflow
return ex_expr::EXPR_ERROR;
};
intermediate *= 10;
};
};
} // intermediate != 0
else if (intermediateDouble != 0) {
// downscale from exact to float
scale = operandCurrScale;
// Check for overflow. TBD.
while (scale--) intermediateDouble /= 10;
}
// LCOV_EXCL_START
else if (intermediateString != 0) {
if (DFS2REC::isBigNum(operandType))
{
}
else
{
intermediateString = new (heap) char[operandLen];
memset(intermediateString, '0', operandLen);
if (scale > 0) { //downscale
if (scale <= (operandLen - 1))
memcpy(&intermediateString[scale + 1],
&operand[1],
operandLen - scale - 1);
else {
NADELETEBASIC(intermediateString, heap);
return ex_expr::EXPR_ERROR;
}
}
if (scale < 0) { //upscale;
scale = -scale;
if (scale <= (operandLen - 1)) {
char* first_nonzero =
str_find_first_nonzero(&operand[1], scale);
if (first_nonzero)
{
NADELETEBASIC(intermediateString, heap);
return ex_expr::EXPR_ERROR;
}
str_cpy_all(&intermediateString[1],
&operand[1+scale],
operandLen - scale -1);
}
else {
NADELETEBASIC(intermediateString, heap);
return ex_expr::EXPR_ERROR;
}
// LCOV_EXCL_STOP
}
} // decimal
} // intermediateString != 0
else
if (decimalString != 0) {
// LCOV_EXCL_START
decimalString = new (heap) char[operandLen];
memset(decimalString, '0', operandLen);
if (scale > 0) { //downscale
if (scale <= operandLen)
str_cpy_all(&decimalString[scale], &operand[0], operandLen - scale);
else {
NADELETEBASIC(decimalString, heap);
return ex_expr::EXPR_ERROR;
}
}
if (scale < 0) { //upscale;
scale = -scale;
if (scale <= operandLen) {
char* first_nonzero =
str_find_first_nonzero(&operand[0], scale);
if (first_nonzero)
{
NADELETEBASIC(decimalString, heap);
return ex_expr::EXPR_ERROR;
}
str_cpy_all(&decimalString[0], &operand[scale], operandLen - scale);
}
else {
NADELETEBASIC(decimalString, heap);
return ex_expr::EXPR_ERROR;
// LCOV_EXCL_STOP
}
}
}
// scaling was sucessful, put result into operand
switch (operandType) {
case REC_BIN16_SIGNED: {
*(short*)operand = (short)intermediate;
}
break;
case REC_BIN16_UNSIGNED: {
*(unsigned short*)operand = (unsigned short)intermediate;
}
break;
case REC_BIN32_SIGNED: {
*(Lng32*)operand = (Lng32)intermediate;
}
break;
case REC_BIN32_UNSIGNED: {
*(ULng32*)operand = (ULng32)intermediate;
}
break;
case REC_BIN64_SIGNED: {
*(Int64*)operand = intermediate;
}
break;
case REC_FLOAT32: {
// LCOV_EXCL_START
floatOperandPtr = (float *)operand;
*floatOperandPtr = (float)intermediateDouble;
// LCOV_EXCL_STOP
}
break;
case REC_FLOAT64: {
doubleOperandPtr = (double *)operand;
*doubleOperandPtr = intermediateDouble;
}
break;
case REC_DECIMAL_LS: {
str_cpy_all(&operand[1], &intermediateString[1], operandLen -1);
NADELETEBASIC(intermediateString, heap);
}
break;
case REC_DECIMAL_LSE:
case REC_DECIMAL_UNSIGNED:
str_cpy_all(operand, decimalString, operandLen);
NADELETEBASIC(decimalString, heap);
if (negativeNum)
operand[0] |= 0x80;
break;
};
// LCOV_EXCL_STOP
return ex_expr::EXPR_OK;
};
// LCOV_EXCL_START
NA_EIDPROC
SQLEXP_LIB_FUNC
ex_expr::exp_return_type swapBytes(Attributes *attr,
void *ptr)
{
Int16 dataType = attr->getDatatype();
Int32 storageLength = attr->getStorageLength();
rec_datetime_field startField;
rec_datetime_field endField;
ExpDatetime *dtAttr;
if (dataType >= REC_MIN_BINARY && dataType <= REC_MAX_BINARY)
{
swapBytes(ptr, storageLength);
}
else
if (dataType == REC_FLOAT32 || dataType == REC_FLOAT64)
{
swapBytes(ptr, storageLength);
}
else
if (dataType >= REC_MIN_INTERVAL && dataType <= REC_MAX_INTERVAL)
{
swapBytes(ptr, storageLength);
}
else
if (dataType == REC_NCHAR_F_UNICODE ||
dataType == REC_NUM_BIG_UNSIGNED ||
dataType == REC_NUM_BIG_SIGNED)
{
for (Int32 i = 0; i < storageLength; i=i+2)
{
swapBytes((void *)((char *)ptr+i), 2);
}
}
else
if (dataType == REC_DATETIME)
{
dtAttr = (ExpDatetime *)attr;
// Get the start and end fields for this Datetime type.
dtAttr->getDatetimeFields(dtAttr->getPrecision(),
startField,
endField);
if (startField == REC_DATE_YEAR)
// swap the year portion in datetime field
swapBytes(ptr, 2);
if (endField == REC_DATE_SECOND)
{
// Swap the fraction part in the seconds
if (dtAttr->getScale() > 0) // There is fraction
swapBytes((char *)ptr+storageLength-4, 4);
}
}
return ex_expr::EXPR_OK;
}
// LCOV_EXCL_STOP