Github user DaveBirdsall commented on a diff in the pull request:
https://github.com/apache/trafodion/pull/1310#discussion_r166080268
--- Diff: core/conn/unixodbc/odbc/odbcclient/unixcli/cli/ctosqlconv.cpp ---
@@ -157,852 +157,982 @@ unsigned long ODBC::Ascii_To_Interval_Helper(char
*source,
unsigned long ODBC::ConvertCToSQL(SQLINTEGER ODBCAppVersion,
- SQLSMALLINT
CDataType,
- SQLPOINTER
srcDataPtr,
- SQLINTEGER
srcLength,
- SQLSMALLINT
ODBCDataType,
- SQLSMALLINT
SQLDataType,
- SQLSMALLINT
SQLDatetimeCode,
- SQLPOINTER
targetDataPtr,
- SQLINTEGER
targetLength,
- SQLINTEGER
targetPrecision,
- SQLSMALLINT
targetScale,
- SQLSMALLINT
targetUnsigned,
- SQLINTEGER
targetCharSet,
- BOOL
byteSwap,
-// FPSQLDriverToDataSource
fpSQLDriverToDataSource,
-// DWORD
translateOption,
- ICUConverter* iconv,
- UCHAR
*errorMsg,
- SWORD
errorMsgMax,
- SQLINTEGER
EnvironmentType,
- BOOL
RWRSFormat,
- SQLINTEGER
datetimeIntervalPrecision)
+ SQLSMALLINT CDataType,
+ SQLPOINTER srcDataPtr,
+ SQLINTEGER srcLength,
+ SQLPOINTER targetDataPtr,
+ CDescRec *targetDescPtr,
+ BOOL byteSwap,
+#ifdef unixcli
+ ICUConverter* iconv,
+#else
+ FPSQLDriverToDataSource fpSQLDriverToDataSource,
+ DWORD translateOption,
+#endif
+ UCHAR *errorMsg,
+ SWORD errorMsgMax,
+ SQLINTEGER EnvironmentType,
+ BOOL RWRSFormat,
+ SQLINTEGER datetimeIntervalPrecision)
{
- unsigned long retCode = SQL_SUCCESS;
- SQLPOINTER DataPtr = NULL;
- SQLPOINTER outDataPtr = targetDataPtr;
- SQLINTEGER DataLen = DRVR_PENDING;
- short Offset = 0; // Used for VARCHAR fields
- SQLINTEGER OutLen = targetLength;
- short targetType = 0; //for bignum datatype
+ unsigned long retCode = SQL_SUCCESS;
+ if(pdwGlobalTraceVariable && *pdwGlobalTraceVariable){
+ TraceOut(TR_ODBC_DEBUG,"ConvertCToSQL(%d, %d, %#x, %d, %d, %d, %d,
%#x, %d, %d, %d, %d, %d, %d, %#x, %d, %d, %d)",
+ ODBCAppVersion,
+ CDataType,
+ srcDataPtr,
+ srcLength,
+ targetDescPtr->m_ODBCDataType,
+ targetDescPtr->m_SQLDataType,
+ targetDescPtr->m_SQLDatetimeCode,
+ targetDataPtr,
+ targetDescPtr->m_SQLOctetLength,
+ targetDescPtr->m_ODBCPrecision,
+ targetDescPtr->m_ODBCScale,
+ targetDescPtr->m_SQLUnsigned,
+ targetDescPtr->m_SQLCharset,
+ byteSwap,
+ errorMsg,
+ errorMsgMax,
+ EnvironmentType,
+ RWRSFormat);
+ }
+ else
+ RESET_TRACE();
+ if (CDataType == SQL_C_DEFAULT)
+ {
+ retCode = getCDefault(targetDescPtr->m_ODBCDataType,
ODBCAppVersion, targetDescPtr->m_SQLCharset, CDataType);
+ if (retCode != SQL_SUCCESS)
+ return retCode;
+ }
- int dec;
- int sign;
- int tempLen;
- int tempLen1;
- int temp;
+ if (errorMsg)
+ *errorMsg = '\0';
+
+ switch (targetDescPtr->m_ODBCDataType)
+ {
+ case SQL_VARCHAR:
+ case SQL_LONGVARCHAR:
+ case SQL_WVARCHAR:
+ case SQL_CHAR:
+ if( targetDescPtr->m_SQLDataType == SQLTYPECODE_BOOLEAN )
+ {
+ retCode = convToSQLBool(srcDataPtr,srcLength, CDataType,
targetDataPtr);
+ break;
+ }
+ case SQL_WCHAR:
+ retCode = ConvertToCharTypes(ODBCAppVersion,
+ CDataType,
+ srcDataPtr,
+ srcLength,
+ targetDescPtr,
+ iconv,
+ targetDataPtr,
+ errorMsg);
+ break;
- short i;
- short datetime_parts[8];
- char *tempPtr;
- double dTmp;
- double dTmp1;
- double scaleOffset;
- SCHAR tTmp;
- UCHAR utTmp;
- SSHORT sTmp;
- USHORT usTmp;
- SLONG_P lTmp;
- ULONG_P ulTmp;
- CHAR cTmpBuf[256];
- CHAR cTmpBuf2[256];
- CHAR cTmpBufInterval[256];
- CHAR cTmpFraction[10];
- __int64 tempVal64;
- __int64 integralPart;
- __int64 decimalPart;
- __int64 tempScaleVal64;
- unsigned __int64 integralMax;
- unsigned __int64 decimalMax;
- float fltTmp;
- BOOL useDouble = TRUE;
- BOOL negative = FALSE;
- long decimalDigits;
- long leadZeros;
- SQLUINTEGER ulFraction;
- SQLSMALLINT cTmpDataType;
-
- DATE_STRUCT *dateTmp;
- TIME_STRUCT *timeTmp;
- TIMESTAMP_STRUCT *timestampTmp;
- SQL_INTERVAL_STRUCT *intervalTmp;
- DATE_TYPES SQLDate;
- TIME_TYPES SQLTime;
- TIMESTAMP_TYPES SQLTimestamp;
- DATE_TYPES *pSQLDate;
- TIME_TYPES *pSQLTime;
- TIMESTAMP_TYPES *pSQLTimestamp;
- SQLINTEGER translateLength;
- SQLSMALLINT tODBCDataType;
- BOOL signedInteger = FALSE;
- BOOL unsignedInteger = FALSE;
- BOOL dataTruncatedWarning = FALSE;
- int AdjustedLength = 0;
- char srcDataLocale[256];
-
- if(pdwGlobalTraceVariable && *pdwGlobalTraceVariable){
- TraceOut(TR_ODBC_DEBUG,"ConvertCToSQL(%d, %d, %#x, %d, %d, %d,
%d, %#x, %d, %d, %d, %d, %d, %d, %#x, %d, %d, %d)",
- ODBCAppVersion,
- CDataType,
- srcDataPtr,
- srcLength,
- ODBCDataType,
- SQLDataType,
- SQLDatetimeCode,
- targetDataPtr,
- targetLength,
- targetPrecision,
- targetScale,
- targetUnsigned,
- targetCharSet,
- byteSwap,
- errorMsg,
- errorMsgMax,
- EnvironmentType,
- RWRSFormat);
- }
- else
- RESET_TRACE();
-/*
-1. Because MS programs do not support BIGINT type, the server has to
convert it to NUMERIC:
- ODBCDataType = SQL_NUMERIC;
- ODBCPrecision = 19;
- SignType = TRUE;
- Before conversion we have to change it back to:
- ODBCDataType = SQL_BIGINT;
-
-2. Because ODBC does not support unsigned types for SMALLINT and INTEGER,
- the server has to convert it to:
- a)SQLTYPECODE_SMALLINT_UNSIGNED:
- ODBCPrecision = 10;
- ODBCDataType = SQL_INTEGER;
- SignType = TRUE;
- b)SQLTYPECODE_INTEGER_UNSIGNED:
- ODBCPrecision = 19;
- ODBCDataType = SQL_NUMERIC;
- SignType = TRUE;
-
- Before conversion we have to change it back to datatype, precision and
sign described by SQL:
- a)
- ODBCPrecision = 5;
- ODBCDataType = SQL_SMALLINT;
- SignType = FALSE;
- b)
- ODBCPrecision = 10;
- ODBCDataType = SQL_INTEGER;
- SignType = FALSE;
-*/
- tODBCDataType = ODBCDataType;
- if (ODBCDataType == SQL_NUMERIC && SQLDataType == SQLTYPECODE_LARGEINT
&&
- targetPrecision == 19 && targetScale==0)
- {
- ODBCDataType = SQL_BIGINT;
- }
+ case SQL_TINYINT:
+ case SQL_SMALLINT:
+ case SQL_INTEGER:
+ case SQL_FLOAT:
+ case SQL_REAL:
+ case SQL_DOUBLE:
+ case SQL_DECIMAL:
+ retCode = ConvertToNumberSimple(CDataType,
+ srcDataPtr,
+ srcLength,
+ targetDescPtr,
+ iconv,
+ targetDataPtr,
+ errorMsg);
+ break;
- if (ODBCDataType == SQL_INTEGER && SQLDataType ==
SQLTYPECODE_SMALLINT_UNSIGNED &&
- targetPrecision == 10 && targetScale==0)
- {
- targetPrecision = 5;
- ODBCDataType = SQL_SMALLINT;
- targetUnsigned = true;
- }
+ case SQL_BIGINT:
+ retCode = ConvertToBigint(ODBCAppVersion,
+ CDataType,
+ srcDataPtr,
+ srcLength,
+ targetDescPtr,
+ iconv,
+ targetDataPtr,
+ errorMsg);
+ break;
- if (ODBCDataType == SQL_NUMERIC && SQLDataType ==
SQLTYPECODE_INTEGER_UNSIGNED &&
- targetPrecision == 19 && targetScale==0)
- {
- targetPrecision = 10;
- ODBCDataType = SQL_INTEGER;
- targetUnsigned = true;
- }
+ case SQL_NUMERIC:
+ retCode = ConvertToNumeric(ODBCAppVersion,
+ CDataType,
+ srcDataPtr,
+ srcLength,
+ targetDescPtr,
+ iconv,
+ targetDataPtr,
+ errorMsg);
+ break;
- if (ODBCDataType == SQL_BIGINT && SQLDataType ==
SQLTYPECODE_INTEGER_UNSIGNED &&
- targetPrecision == 19 && targetScale==0)
- {
- targetPrecision = 10;
- ODBCDataType = SQL_INTEGER;
- targetUnsigned = true;
- }
+ case SQL_DATE:
+ case SQL_TYPE_DATE:
+ retCode = ConvertToDateType(ODBCAppVersion,
+ CDataType,
+ srcDataPtr,
+ srcLength,
+ targetDescPtr,
+ iconv,
+ targetDataPtr,
+ RWRSFormat,
+ errorMsg);
+ break;
- if (CDataType == SQL_C_DEFAULT)
- {
- getCDefault(tODBCDataType, ODBCAppVersion, targetCharSet,
CDataType);
- if (ODBCAppVersion >= 3 && targetUnsigned)
- {
- switch(CDataType)
- {
- case SQL_C_SHORT:
- case SQL_C_SSHORT:
- CDataType = SQL_C_USHORT;
- break;
- case SQL_C_TINYINT:
- case SQL_C_STINYINT:
- CDataType = SQL_C_UTINYINT;
- break;
- case SQL_C_LONG:
- case SQL_C_SLONG:
- CDataType = SQL_C_ULONG;
- break;
- }
- }
- }
+ case SQL_TIME:
+ case SQL_TYPE_TIME:
+ retCode = ConvertToTimeType(ODBCAppVersion,
+ CDataType,
+ srcDataPtr,
+ srcLength,
+ targetDescPtr,
+ iconv,
+ targetDataPtr,
+ RWRSFormat,
+ errorMsg);
+ break;
-//--------------------------------------------------------------------------------------
+ case SQL_TIMESTAMP:
+ case SQL_TYPE_TIMESTAMP:
+ retCode = ConvertToTimeStampType(ODBCAppVersion,
+ CDataType,
+ srcDataPtr,
+ srcLength,
+ targetDescPtr,
+ iconv,
+ targetDataPtr,
+ RWRSFormat,
+ errorMsg);
+ break;
- if (errorMsg)
- *errorMsg = '\0';
- //if (targetPrecision < 19)
- if( !(((SQLDataType == SQLTYPECODE_NUMERIC) && (targetPrecision > 18))
||
- ((SQLDataType == SQLTYPECODE_NUMERIC_UNSIGNED) &&
(targetPrecision > 9))))
- getMaxNum(targetPrecision, targetScale, integralMax, decimalMax);
+ case SQL_INTERVAL_MONTH:
+ case SQL_INTERVAL_YEAR:
+ case SQL_INTERVAL_YEAR_TO_MONTH:
+ case SQL_INTERVAL_DAY:
+ case SQL_INTERVAL_HOUR:
+ case SQL_INTERVAL_MINUTE:
+ case SQL_INTERVAL_SECOND:
+ case SQL_INTERVAL_DAY_TO_HOUR:
+ case SQL_INTERVAL_DAY_TO_MINUTE:
+ case SQL_INTERVAL_DAY_TO_SECOND:
+ case SQL_INTERVAL_HOUR_TO_MINUTE:
+ case SQL_INTERVAL_HOUR_TO_SECOND:
+ case SQL_INTERVAL_MINUTE_TO_SECOND:
+ retCode = ConvertToTimeIntervalType(ODBCAppVersion,
+ CDataType,
+ srcDataPtr,
+ srcLength,
+ targetDescPtr,
+ iconv,
+ targetDataPtr,
+ RWRSFormat,
+ errorMsg,
+ datetimeIntervalPrecision);
+ break;
- switch (ODBCDataType)
- {
- case SQL_VARCHAR:
- case SQL_LONGVARCHAR:
- case SQL_WVARCHAR:
- {
- if(targetPrecision > SHRT_MAX)
- {
- Offset = sizeof(UINT);
- }
- else
- {
- Offset = sizeof(USHORT);
- }
- }
- case SQL_CHAR:
- if( SQLDataType == SQLTYPECODE_BOOLEAN )
+ default:
+ return IDS_07_006;
+ }
+
+ return retCode;
+}
+
+unsigned long ODBC::convToSQLBool(SQLPOINTER srcDataPtr,SQLINTEGER
srcLength, SQLSMALLINT CDataType, SQLPOINTER targetDataPtr)
+{
+
+ CHAR cTmpBuf[TMPLEN] = {0};
+ double dTmp = 0;
+ char temptarget = 0;
+ unsigned long retCode = SQL_SUCCESS;
+ errno = 0;
+
+ switch (CDataType)
+ {
+ case SQL_C_CHAR:
+ case SQL_C_WCHAR:
+ temptarget = strtol((char*)srcDataPtr,NULL,10);
+ if (errno == ERANGE)
+ return IDS_22_003;
+ break;
+
+ case SQL_C_TINYINT:
+ case SQL_C_STINYINT:
+ temptarget = *(SCHAR *)srcDataPtr;
+ break;
+
+ case SQL_C_BIT:
+ case SQL_C_UTINYINT:
+ temptarget = *(UCHAR *)srcDataPtr;
+ break;
+
+ case SQL_C_SHORT:
+ case SQL_C_SSHORT:
+ temptarget = *(SSHORT *)srcDataPtr;
+ break;
+
+ case SQL_C_USHORT:
+ temptarget = *(USHORT *)srcDataPtr;
+ break;
+
+ case SQL_C_LONG:
+ case SQL_C_SLONG:
+ temptarget = *(SLONG_P *)srcDataPtr;
+ break;
+ case SQL_C_ULONG:
+ temptarget = *(ULONG_P *)srcDataPtr;
+ break;
+
+ case SQL_C_SBIGINT:
+ temptarget = *(__int64 *)srcDataPtr;
+ break;
+
+ case SQL_C_UBIGINT:
+ temptarget = *(unsigned __int64 *)srcDataPtr;
+ break;
+
+ case SQL_C_NUMERIC:
+ retCode = ConvertCNumericToChar((SQL_NUMERIC_STRUCT*)srcDataPtr,
cTmpBuf);
+ if (retCode != SQL_SUCCESS)
+ return retCode;
+ retCode = ConvertCharToNumeric((char*)cTmpBuf, srcLength, dTmp);
+ if (retCode != SQL_SUCCESS)
+ return retCode;
+ temptarget = dTmp;
+ break;
+
+ default:
+ return IDS_07_006;
+ }
+
+ if (temptarget < 0)
+ return IDS_22_003_02;
+ if (temptarget > 1)
+ return IDS_22_003;
+
+ memcpy(targetDataPtr, &temptarget, sizeof(SCHAR));
+
+ return SQL_SUCCESS;
+}
+
+
+
+unsigned long ODBC::MemcpyToNumeric(SQLPOINTER DataPtr,
+ SQLINTEGER & DataLen,
+ CDescRec* targetDescPtr,
+ SQLSMALLINT CDataType,
+ BOOL useDouble,
+ double dTmp,
+ BOOL negative,
+ __int64 decimalPart,
+ __int64 integralPart,
+ long leadZeros,
+ ICUConverter* iconv,
+ SQLPOINTER & outDataPtr,
+ unsigned long retTmp
+ )
+{
+
+ SQLSMALLINT targetUnsigned = targetDescPtr->m_SQLUnsigned;
+ SQLSMALLINT targetScale = targetDescPtr->m_ODBCScale;
+ SQLSMALLINT SQLDataType = targetDescPtr->m_SQLDataType;
+ SQLINTEGER targetPrecision = targetDescPtr->m_ODBCPrecision;
+ double dTmp1 = 0;
+ double scaleOffset = 0;
+ CHAR tTmp = 0;
+ USHORT usTmp = 0;
+ UCHAR utTmp = 0;
+ SHORT sTmp = 0;
+ ULONG_P ulTmp = 0;
+ SLONG_P lTmp = 0;
+ __int64 tempVal64 = 0;
+ __int64 tempScaleVal64 = 0;
+ unsigned __int64 uVal64 = 0;
+ short i = 0;
+ long decimalDigits = 0;
+ unsigned long retCode = retTmp;
+
+ if (DataPtr == NULL)
+ {
+ if (useDouble)
{
- switch (CDataType)
+ if( targetUnsigned && ( dTmp < 0 || negative ))
+ return IDS_22_003_02; //negValue in unsigned column
+
+ dTmp1 = pow((double)10, targetPrecision - targetScale + 1);
+ if (dTmp < -dTmp1 || dTmp > dTmp1)
+ return IDS_22_003;
+ scaleOffset = pow(10, targetScale); // This value always
multplied to srcValue
+ // since SQL stores it as a implied decimal point
+ // 1.0 for NUMERIC (4,2) value is stored as 100
+ dTmp *= scaleOffset;
+ switch (SQLDataType)
+ {
+ case SQLTYPECODE_TINYINT_UNSIGNED:
+ utTmp = (UCHAR)dTmp;
+ DataPtr = &utTmp;
+ DataLen = sizeof(UCHAR);
+ break;
+ case SQLTYPECODE_TINYINT:
+ tTmp = (SCHAR)dTmp;
+ DataPtr = &tTmp;
+ DataLen = sizeof(SCHAR);
+ break;
+
+ case SQLTYPECODE_SMALLINT_UNSIGNED:
+ usTmp = (USHORT)dTmp;
+ DataPtr = &usTmp;
+ DataLen = sizeof(USHORT);
+ break;
+ case SQLTYPECODE_SMALLINT:
+ sTmp = (SHORT)dTmp;
+ DataPtr = &sTmp;
+ DataLen = sizeof(SHORT);
+ break;
+
+ case SQLTYPECODE_INTEGER_UNSIGNED:
+ ulTmp = (ULONG_P)dTmp;
+ DataPtr = &ulTmp;
+ DataLen = sizeof(ULONG_P);
+ break;
+ case SQLTYPECODE_INTEGER:
+ lTmp = (LONG)dTmp;
+ DataPtr = &lTmp;
+ DataLen = sizeof(LONG);
+ break;
+
+ case SQLTYPECODE_LARGEINT_UNSIGNED:
+ tempVal64 = (unsigned __int64)dTmp;
+ DataPtr = &tempVal64;
+ DataLen = sizeof(unsigned __int64);
+ break;
+ case SQLTYPECODE_LARGEINT:
+ tempVal64 = (__int64)dTmp;
+ DataPtr = &tempVal64;
+ DataLen = sizeof(__int64);
+ break;
+
+ default:
+ return IDS_07_006;
+ }
+ }
+ else
+ {
+ if( targetUnsigned && negative )
+ return IDS_22_003_02; //negValue in unsigned column
+
+ if (targetScale)
+ {
+ for (i = 0,tempVal64 = 1; i < targetScale ; i++)
+ tempVal64 *= 10;
+ tempVal64 = tempVal64 * integralPart;
+ decimalDigits = 0;
+ if (decimalPart > 0)
+ decimalDigits = getDigitCount(decimalPart);
+ scaleOffset = 0;
+ if (leadZeros < targetScale)
+ scaleOffset = targetScale - decimalDigits - leadZeros;
+ if (scaleOffset < 0)
+ {
+ //NUMERIC_VALUE_OUT_OF_RANGE_ERROR
+ return IDS_22_003;
+ }
+
+ for (i =0, tempScaleVal64 = decimalPart ; i < scaleOffset
; i++)
+ tempScaleVal64 *= 10;
+ tempVal64 += tempScaleVal64;
+ }
+ else
+ {
+ //NUMERIC_DATA_TRUNCATED_ERROR
+ if (decimalPart != 0)
+ retCode = IDS_01_S07;
+ tempVal64 = integralPart;
+ }
+ if (negative)
+ tempVal64 = -tempVal64;
+
+ switch( SQLDataType )
{
+ case SQLTYPECODE_TINYINT_UNSIGNED:
+ if (tempVal64 < 0)
+ return IDS_22_003_02;
+ if ((UCHAR)tempVal64 > UCHAR_MAX)
+ return IDS_22_003;
+ utTmp = (UCHAR)tempVal64;
+ if (tempVal64 != utTmp)
--- End diff --
This test makes the bug at 564 almost unobservable. If tempVal64 were
UCHAR_MAX+1, instead of error IDS_22_003, it looks like we will catch the
problem here and get error IDS_01_S07 instead.
---