RETCODE SQL_API SQLExecDirectW ( SQLHSTMT pStmt, SQLWCHAR* pStmtText, SQLINTEGER pTextLength ) { __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLExecDirectW called on: %d", pStmt ) ); wchar_t* s; __CHK_HANDLE ( pStmt, SQL_HANDLE_STMT, SQL_ERROR ); _SQLFreeDiag ( _DIAGSTMT ( pStmt ) ); // precaution if ( pStmtText == NULL || ( pTextLength <= 0 && pTextLength != SQL_NTS ) ) { __ODBCPOPMSG ( _ODBCPopMsg ( "SQLExecDirect - bad params" ) ); _SQLPutDiagRow ( SQL_HANDLE_STMT, pStmt, "SQLExecDirectW", "01000", -1, "bad params" ); return SQL_ERROR; } // convert to full request, with zero termination ( as well as params - later ) if ( ProcessStmtForParams ( ( pODBCStmt ) pStmt, ( wchar_t* ) pStmtText, pTextLength, s ) == BAD ) { return SQL_ERROR; } // release existing stmt contents SQLFreeStmt ( pStmt, SQL_CLOSE ); // replace with new stmt string ( ( pODBCStmt ) pStmt )->Stmt = s; ( ( pODBCStmt ) pStmt )->StmtLen = pTextLength; // mark it as prepared ( ( pODBCStmt ) pStmt )->Prepared = 1; // execute RETCODE code = SQLExecute ( pStmt ); __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLExecDirectW exited on with %d", code ) ); return code; }
RETCODE SQL_API _SQLExecStmtFromReq ( pODBCStmt pStmt, bool pPrepared ) { ////// this part should not be required if already prepared // release existing stmt contents //SQLFreeStmt ( pStmt, SQL_CLOSE ); ////// __ODBCLOG ( _ODBCLogMsg ( LogLevel_INFO, "================================================================" ) ); __ODBCLOG ( _ODBCLogMsg ( LogLevel_INFO, "start exec the query: " ) ); __ODBCLOG ( _ODBCLogMsg ( LogLevel_INFO, pStmt->Stmt ) ); std::unique_ptr<SQLResponse> p; try { p = restQuery ( pStmt->Stmt, pStmt->Conn->Server, pStmt->Conn->ServerPort, pStmt->Conn->UserName, pStmt->Conn->Password, pStmt->Conn->Project ); __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "The REST request succeed" ) ); } catch ( const exception& e ) { std::stringstream ss; ss << "The REST query request failed, the error message is: " << e.what(); std::string s = ss.str(); __ODBCLOG ( _ODBCLogMsg ( LogLevel_ERROR, s.c_str() ) ); _SQLPutDiagRow ( SQL_HANDLE_STMT, pStmt, "_SQLExecStmtFromReq", "01000", -1, ( char* ) s.c_str() ); return SQL_ERROR; } // feed stmt structure with response, stmt will take charge of deleting it if ( p == NULL || p->isException == true || PutRespToStmt ( ( pODBCStmt ) pStmt, std::move ( p ) ) != GOOD ) { return SQL_ERROR; } __ODBCLOG ( _ODBCLogMsg ( LogLevel_INFO, "Successfully done executing the query" ) ); return SQL_SUCCESS; }
eGoodBad _SQLPutDiagRow ( SQLSMALLINT pHandleType, SQLHANDLE pHandle, StrPtr pFunc, StrPtr pState, Long pNativeErrorCode, Long pRow, Long pCol, StrPtr pMsgArgs, ... ) { // note // this implementation of function takes take row/col as param __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "_SQLPutDiagRow called" ) ); va_list args; pODBCDiag diag; pODBCDiagRow r; __CHK_HANDLE ( pHandle, pHandleType, BAD ); diag = _SQLGetDiagHandle ( pHandleType, pHandle ); if ( !diag ) { return BAD; } // get va_args va_start ( args, pMsgArgs ); r = _SQLPutDiagRow ( diag, pFunc, pState, pNativeErrorCode, pMsgArgs, args ); va_end ( args ); if ( r ) { r->Row = pRow; r->Col = pCol; return GOOD; } return BAD; }
/* Kylin uses rest request for query executing, SQLPrepare does not do anything meaningful */ RETCODE SQL_API SQLPrepareW ( SQLHSTMT pStmt, SQLWCHAR* pStmtText, SQLINTEGER pTextLength ) { wchar_t* s; __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLPrepareW called on: %d", pStmt ) ); __CHK_HANDLE ( pStmt, SQL_HANDLE_STMT, SQL_ERROR ); _SQLFreeDiag ( _DIAGSTMT ( pStmt ) ); // precaution if ( pStmtText == NULL || ( pTextLength <= 0 && pTextLength != SQL_NTS ) ) { __ODBCPOPMSG ( _ODBCPopMsg ( "SQLPrepare - bad params" ) ); _SQLPutDiagRow ( SQL_HANDLE_STMT, pStmt, "SQLPrepare", "01000", -1, "SQLPrepare - bad params" ); return SQL_ERROR; } // MANAGE STMT CONTENT // convert to full request, with zero termination ( as well as params - later ) if ( ProcessStmtForParams ( ( pODBCStmt ) pStmt, pStmtText, pTextLength, s ) == BAD ) { return SQL_ERROR; } // release existing stmt contents SQLFreeStmt ( pStmt, SQL_CLOSE ); // replace with new stmt string __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "The query being prepared is :" ) ); __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, s ) ); ( ( pODBCStmt ) pStmt )->Stmt = s; ( ( pODBCStmt ) pStmt )->StmtLen = pTextLength; // MARK as prepared // set the flag ( ( pODBCStmt ) pStmt )->Prepared = 1; return SQL_SUCCESS; }
RETCODE SQL_API _SQLResetRowPos ( pODBCStmt pStmt ) { // note // there r 2 row pointers one is the start row for the current fetch and // the other is the end row after the current fetch // this function brings them together and moves them to the first row // after the cur end row // a block of rows which is fetched in one go is ROWSET while the full // result is called RESULTSET // check if there is some response of type resultset if ( pStmt->IRD.RowDesc != NULL ) { // check if position is currently unknown if ( pStmt->CurRowsetEndRow == NULL && pStmt->CurRowsetEndRowPos == 0 ) { // position to first row ( both the pointers ) pStmt->CurRowsetEndRowPos = 1; pStmt->CurRowsetEndRow = GetIfExist ( pStmt->IRD.RowDesc->results, pStmt->CurRowsetEndRowPos ); } // already positioned somewhere else if ( pStmt->CurRowsetEndRow != NULL ) { // position to next row pStmt->CurRowsetEndRowPos += 1; pStmt->CurRowsetEndRow = GetIfExist ( pStmt->IRD.RowDesc->results, pStmt->CurRowsetEndRowPos ); } // calibrate the first row with end row pStmt->CurRowsetStartRow = pStmt->CurRowsetEndRow; pStmt->CurRowsetStartRowPos = pStmt->CurRowsetEndRowPos; // finally check if there is some data found if ( pStmt->CurRowsetStartRow == NULL ) { // put in diag _SQLPutDiagRow ( SQL_HANDLE_STMT, pStmt, "", "01000", -1, "SQLFetch - no data" ); return SQL_NO_DATA; } else { return SQL_SUCCESS; } } else { // error situation _SQLPutDiagRow ( SQL_HANDLE_STMT, pStmt, "_SQLResetRowPos", "01000", -1, "no resultset" ); return SQL_ERROR; } }
RETCODE SQL_API _SQLFetchMoveNext ( pODBCStmt pStmt ) { __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "_SQLFetch MoveNext is called" ) ); // check if there is some response of type resultset if ( pStmt->IRD.RowDesc != NULL ) { // ------- THIS CASE SHOULD NOT OCCUR ---------- // check if position is currently unknown if ( pStmt->CurRowsetStartRow == NULL && pStmt->CurRowsetStartRowPos == 0 ) { // position to first row ( both the pointers ) pStmt->CurRowsetStartRowPos = 1; pStmt->CurRowsetStartRow = GetIfExist ( pStmt->IRD.RowDesc->results, 1 ); pStmt->CurRowsetEndRowPos = 1; pStmt->CurRowsetEndRow = GetIfExist ( pStmt->IRD.RowDesc->results, 1 ); } // ----------------------------------------------- // position to next row if already position is known else if ( pStmt->CurRowsetEndRow != NULL ) { // position to next row pStmt->CurRowsetEndRowPos += 1; pStmt->CurRowsetEndRow = GetIfExist ( pStmt->IRD.RowDesc->results, pStmt->CurRowsetEndRowPos ); } // finally check if there is some data found if ( pStmt->CurRowsetEndRow == NULL ) { // put in diag _SQLPutDiagRow ( SQL_HANDLE_STMT, pStmt, "", "01000", -1, "SQLFetch - no data" ); return SQL_NO_DATA; } else { return SQL_SUCCESS; } } else { // error situation _SQLPutDiagRow ( SQL_HANDLE_STMT, pStmt, "_SQLFetchMoveNext", "01000", -1, "no resultset" ); return SQL_ERROR; } }
RETCODE SQL_API SQLExecute ( HSTMT pStmt ) { __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLExecute called on: %d", pStmt ) ); Word x; __CHK_HANDLE ( pStmt, SQL_HANDLE_STMT, SQL_ERROR ); _SQLFreeDiag ( _DIAGSTMT ( pStmt ) ); // check if prepared if ( ( ( pODBCStmt ) pStmt )->Prepared != 1 ) { _SQLPutDiagRow ( SQL_HANDLE_STMT, pStmt, "SQLExecute", "01000", -1, "No prepared stmt" ); return SQL_ERROR; } // excute the request x = _SQLExecStmtFromReq ( ( pODBCStmt ) pStmt, 1 ); return x; }
RETCODE SQL_API SQLCloseCursor ( SQLHSTMT pStmt ) { __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLCloseCursor called" ) ); __CHK_HANDLE ( pStmt, SQL_HANDLE_STMT, SQL_ERROR ); _SQLFreeDiag ( _DIAGSTMT ( pStmt ) ); // check if there is some result if ( ( ( pODBCStmt ) pStmt )->IRD.RowDesc != NULL ) { // free the results return SQLFreeStmt ( pStmt, SQL_CLOSE ); } else { // error condition _SQLPutDiagRow ( SQL_HANDLE_STMT, pStmt, "SQLCloseCursor", "24000", -1, "Invalid cursor state" ); return SQL_ERROR; } }
RETCODE TryFetchMetadata ( pODBCConn pgConn ) { __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "start loading metadata..." ) ); try { pgConn->meta = std::move ( restGetMeta ( pgConn->Server, pgConn->ServerPort, pgConn->UserName, pgConn->Password, pgConn->Project ) ); } catch ( const exception& e ) { __ODBCLOG ( _ODBCLogMsg ( LogLevel_ERROR, "The REST request failed to get metadata" ) ); __ODBCLOG ( _ODBCLogMsg ( LogLevel_ERROR, e.what() ) ); _SQLPutDiagRow ( SQL_HANDLE_DBC, pgConn, "SQLDriverConnect", "HY000", 1045, "Access denied. (using password: NO)" ); return SQL_ERROR; } __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "End loading metadata" ) ); return SQL_SUCCESS; }
RETCODE TryAuthenticate ( pODBCConn pgConn ) { __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "Start authenticating.." ) ); try { bool authenticated = restAuthenticate ( pgConn->Server, pgConn->ServerPort, pgConn->UserName, pgConn->Password ); if ( !authenticated ) { throw exception ( "Username/Password incorrect." ); } } catch ( const exception& e ) { __ODBCLOG ( _ODBCLogMsg ( LogLevel_ERROR, "The REST request failed to authenticate." ) ); __ODBCLOG ( _ODBCLogMsg ( LogLevel_ERROR, e.what() ) ); _SQLPutDiagRow ( SQL_HANDLE_DBC, pgConn, "SQLDriverConnect", "HY000", 1045, "Access denied. (using password: NO)" ); return SQL_ERROR; } __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "End authenticating" ) ); return SQL_SUCCESS; }
RETCODE SQL_API SQLNumResultCols ( SQLHSTMT pStmt, SQLSMALLINT* pColCountPtr ) { __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLNumResultCols called" ) ); SQLResponse* rowdesc; __CHK_HANDLE ( pStmt, SQL_HANDLE_STMT, SQL_ERROR ); // free diags _SQLFreeDiag ( _DIAGSTMT ( pStmt ) ); // caller safe * ( ( SQLSMALLINT* ) pColCountPtr ) = 0; // get the row desciptor rowdesc = ( ( pODBCStmt ) pStmt )->IRD.RowDesc.get(); if ( rowdesc == NULL ) { _SQLPutDiagRow ( SQL_HANDLE_STMT, pStmt, "SQLNumResultCols", "01000", -1, "no resultset or IRD" ); return SQL_ERROR; } // count the number of columns * ( ( SQLSMALLINT* ) pColCountPtr ) = ( SQLSMALLINT ) ( rowdesc->columnMetas.size() ); __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLNumResultCols called returned: %d", * ( ( SQLSMALLINT* ) pColCountPtr ) ) ); return SQL_SUCCESS; }
RETCODE SQL_API _SQLCopyCharData ( pODBCDiag pDiag, void* pTgtDataPtr, Long pDataBufSize, void* pSizePtr, Word pSizePtrSize, CStrPtr pSrcData, Long pSrcDataSize ) { __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "_SQLCopyCharData called,pDataBufSize %d, the src is %s, strlen(src) %d, pSrcDataSize %d", pDataBufSize, pSrcData, strlen ( pSrcData ), pSrcDataSize ) ); Long n; // caller safe if ( pTgtDataPtr ) { * ( ( StrPtr ) pTgtDataPtr ) = 0; } // DATA SIZE // check source data to compute size if ( pSrcData && _stricmp ( ( StrPtr ) pSrcData, "NULL" ) != 0 ) { n = ( pSrcDataSize < 0 ) ? strlen ( ( StrPtr ) pSrcData ) : pSrcDataSize; } // compute length based on whether null terminated else { n = 0; } // check if there is a holder for size if ( pSizePtr ) { // set size as per ptr type 16-bt or 32-bit if ( pSizePtrSize == 16 ) { * ( ( Word* ) pSizePtr ) = ( Word ) n; } else { * ( ( Long* ) pSizePtr ) = n; } } // check if src data but no size holder else if ( pSrcData ) { // check if diag to be set if ( pDiag ) { _SQLPutDiagRow ( pDiag, "_SQLCopyCharData", "01000", -1, "No holder for data size", NULL ); } __ODBCPOPMSG ( _ODBCPopMsg ( "_SQLCopyCharData - No holder for data size" ) ); return SQL_ERROR; } // check if there is a target holder if ( pTgtDataPtr ) { // check if there is a source pointer if ( pSrcData ) { // does all of it fit with null char if ( pDataBufSize >= n + 1 ) { memcpy ( ( StrPtr ) pTgtDataPtr, pSrcData, n ); ( ( StrPtr ) pTgtDataPtr ) [n] = 0; __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "_SQLCopyCharData has been called, the string(not truncated) is %s", pTgtDataPtr ) ); return SQL_SUCCESS; } // all of it does not fit else { memcpy ( ( StrPtr ) pTgtDataPtr, pSrcData, pDataBufSize - 1 ); ( ( StrPtr ) pTgtDataPtr ) [pDataBufSize - 1] = 0; __ODBCLOG ( _ODBCLogMsg ( LogLevel_WARN, "_SQLCopyCharData has been called, the target string is (truncated) %s", pTgtDataPtr ) ); //return SQL_SUCCESS_WITH_INFO may cause error in tableau //if ( pDiag ) // _SQLPutDiagRow ( pDiag, "_SQLCopyCharData", "01000", -1, "string data truncated", NULL ); //return SQL_SUCCESS_WITH_INFO; __ODBCLOG ( _ODBCLogMsg ( LogLevel_WARN, "string data truncated" ) ); return SQL_SUCCESS; } } // tgt data but no src data else { // clear tgt * ( ( Char* ) pTgtDataPtr ) = 0; __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "_SQLCopyCharData has been called, the string is (empty) %s", pTgtDataPtr ) ); } } return SQL_SUCCESS; }
SQLRETURN SQL_API _SQLDescribeCol_basic ( SQLHSTMT pStmt, SQLUSMALLINT pColNum, void* pColNamePtr, SQLSMALLINT pColNameSize, SQLSMALLINT* pColNameSizePtr, SQLSMALLINT* pDataTypePtr, SQLULEN* pColSizePtr, SQLSMALLINT* pDecimalDigitsPtr, SQLSMALLINT* pNullablePtr , bool isANSI ) { Long n; SQLResponse* ird; pIRDItem col; __CHK_HANDLE ( pStmt, SQL_HANDLE_STMT, SQL_ERROR ); // free diags _SQLFreeDiag ( _DIAGSTMT ( pStmt ) ); // precaution if ( pColNum == 0 ) { _SQLPutDiagRow ( SQL_HANDLE_STMT, pStmt, "SQLDescribeCol", "01000", -1, "bad params" ); return SQL_ERROR; } // get the row descriptor obtained with response ird = ( ( ( pODBCStmt ) pStmt )->IRD ).RowDesc.get(); // check if ( ird == NULL ) { _SQLPutDiagRow ( SQL_HANDLE_STMT, pStmt, "SQLDescribeCol", "01000", -1, "No resultset or no col descriptors" ); return SQL_ERROR; } // find the xth element/col col = _SQLGetIRDItem ( & ( ( ( pODBCStmt ) pStmt )->IRD ), pColNum ); // check if ( col == NULL ) { _SQLPutDiagRow ( SQL_HANDLE_STMT, pStmt, "SQLDescribeCol", "01000", -1, "Invalid col num" ); return SQL_ERROR; } // COL-NAME ie title if ( pColNamePtr ) { _SQLGetIRDItemField ( & ( ( ( pODBCStmt ) pStmt )->IRD ), col, pColNum, SQL_DESC_BASE_COLUMN_NAME, pColNamePtr, pColNameSize, pColNameSizePtr ? &n : NULL, isANSI ); if ( pColNameSizePtr ) { *pColNameSizePtr = ( Word ) n; } __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "name: %s", pColNamePtr ) ); } // COL-DATA TYPE if ( pDataTypePtr ) { _SQLGetIRDItemField ( & ( ( ( pODBCStmt ) pStmt )->IRD ), col, pColNum, SQL_DESC_CONCISE_TYPE, pDataTypePtr, -1, NULL, isANSI ); __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "data type: %d", *pDataTypePtr ) ); } // COL-SIZE if ( pColSizePtr ) { _SQLGetIRDItemField ( & ( ( ( pODBCStmt ) pStmt )->IRD ), col, pColNum, SQL_DESC_LENGTH, pColSizePtr, -1, NULL, isANSI ); __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "column size: %d", *pColSizePtr ) ); } // COL-DECIMAL if ( pDecimalDigitsPtr ) { _SQLGetIRDItemField ( & ( ( ( pODBCStmt ) pStmt )->IRD ), col, pColNum, SQL_DESC_SCALE, pDecimalDigitsPtr, -1, NULL, isANSI ); __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "decimal scale: %d", *pDecimalDigitsPtr ) ); } // COL-NULLABLE if ( pNullablePtr ) { _SQLGetIRDItemField ( & ( ( ( pODBCStmt ) pStmt )->IRD ), col, pColNum, SQL_DESC_NULLABLE, pNullablePtr, -1, NULL, isANSI ); __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "nullable: %d", *pNullablePtr ) ); } __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLDescribeCol returned" ) ); return SQL_SUCCESS; }
RETCODE SQL_API SQLDriverConnect ( SQLHDBC pConn, SQLHWND pWndHandle, SQLCHAR* pInConnStr, SQLSMALLINT pInConnStrLen, SQLCHAR* pOutConnStr, SQLSMALLINT pOutConnStrLen, SQLSMALLINT* pOutConnStrLenPtr, SQLUSMALLINT pDriverCompletion ) { __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "The window handle is %d, the driver completion flag is %d", pWndHandle, pDriverCompletion ) ); pODBCConn pgConn = ( pODBCConn ) pConn; bool f; bool flgDriver, flgDSN; // flags for knowing if these key present in string bool flgServer, flgPort, flgUID, flgPWD, flgProj; // flags for knowing if these key present in string Word i, n; Word iKVInputPairs; // no of key value pairs as input Word iDriverPos, iDSNPos; // ??? can be eliminated by optimization of code Word iServerPos, iPortPos, iUIDPos, iPWDPos, iProjPos; // ??? can be eliminated by optimization of code struct ODBCKV* KVInput; // key value as input via function param struct ODBCKV* KV; // generic, temp if ( !pInConnStr ) { __ODBCPOPMSG ( _ODBCPopMsg ( "SQLDriverConnect: pInConnStr is required" ) ); return SQL_ERROR; } else { //__ODBCLOG(_ODBCLogMsg(LogLevel_DEBUG,"The passed-in Connection Str is %s",(char*)pInConnStr)); } __CHK_HANDLE ( pConn, SQL_HANDLE_DBC, SQL_ERROR ); _SQLFreeDiag ( _DIAGCONN ( pConn ) ); // caller safe if ( pOutConnStr ) { *pOutConnStr = 0; } if ( pOutConnStrLenPtr ) { *pOutConnStrLenPtr = 0; } // initializations KVInput = NULL; flgServer = FALSE; flgPort = FALSE; flgUID = FALSE; flgPWD = FALSE; flgProj = FALSE; // check if an in-string has been specified if ( pInConnStr ) { __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "Parsing the in str" ) ); // split into key-value pairs if ( CvtStrToKeyValues ( ( StrPtr ) pInConnStr, pInConnStrLen, &iKVInputPairs, &KVInput ) != GOOD ) { return SQL_ERROR; } // first check if dsn keyword is present flgDSN = FindInKeyValues ( "DSN", NULL, KVInput, iKVInputPairs, &iDSNPos ); // look for driver only if DSN is absent else Driver is always ignored flgDriver = ( flgDSN ) ? FALSE : FindInKeyValues ( "DRIVER", NULL, KVInput, iKVInputPairs, &iDriverPos ); // if DSN is to be used, fetch its set of key values if ( flgDSN ) { __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "The in str is a dsn string" ) ); //connect by dsn SetCurrentDSN ( ( char* ) pInConnStr, "SQLDriverConnect" ); if ( LoadODBCINIDataToConn ( pgConn ) != GOOD ) { return SQL_ERROR; } } else if ( flgDriver ) { __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "The in str is a driver string" ) ); /************* debug for ( i = 0, n = iKVInputPairs, KV = KVInput; i < n; i++ ) fprintf ( stderr, "Index: %d, Key: %s, Value: %s\n", i, KV[i].key ? KV[i].key : "(nokey)", KV[i].value ? KV[i].value : "(no value)" ); *********/ // loop to parse both input key-values and DSN key-values & feed into struct for ( i = 0, n = iKVInputPairs, KV = KVInput; i < n; i++ ) { if ( !flgServer ) { flgServer = FindInKeyValues ( "SERVER", NULL, KV, n, &iServerPos ); if ( flgServer ) { CreateAndSetConnProp ( ( pODBCConn ) pConn, CONN_PROP_SERVER, KV[iServerPos].value ); } } if ( !flgPort ) { flgPort = FindInKeyValues ( "PORT", NULL, KV, n, &iPortPos ); if ( flgPort ) { CreateAndSetConnProp ( ( pODBCConn ) pConn, CONN_PROP_PORT, KV[iPortPos].value ); } } if ( !flgUID ) { flgUID = FindInKeyValues ( "UID", NULL, KV, n, &iUIDPos ); if ( flgUID ) { CreateAndSetConnProp ( ( pODBCConn ) pConn, CONN_PROP_UID, KV[iUIDPos].value ); __ODBCLOG ( _ODBCLogMsg ( LogLevel_INFO, "Log in as User : %s ", KV[iUIDPos].value ) ); } } if ( !flgPWD ) { flgPWD = FindInKeyValues ( "PWD", NULL, KV, n, &iPWDPos ); if ( flgPWD ) { CreateAndSetConnProp ( ( pODBCConn ) pConn, CONN_PROP_PWD, KV[iPWDPos].value ); } } if ( !flgProj ) { flgProj = FindInKeyValues ( "PROJECT", NULL, KV, n, &iProjPos ); if ( flgProj ) { CreateAndSetConnProp ( ( pODBCConn ) pConn, CONN_PROP_PROJECT, KV[iProjPos].value ); } } } } else { _SQLPutDiagRow ( SQL_HANDLE_DBC, pConn, "SQLDriverConnectW", "HY000", 1045, "Only DSN or driver connect is allowed" ); __ODBCPOPMSG ( _ODBCPopMsg ( "Only DSN or driver connect is allowed, instead of %s", pInConnStr ) ); return SQL_ERROR; } FreeGenODBCKeyValues ( KVInput, iKVInputPairs ); delete[] KVInput; } else if ( pDriverCompletion == SQL_DRIVER_NOPROMPT ) { // check if no-prompt forced __ODBCPOPMSG ( _ODBCPopMsg ( "No connection string && no prompt specified" ) ); _SQLPutDiagRow ( SQL_HANDLE_DBC, pConn, "SQLDriverConnectW", "HY000", 1045, "Access denied. (using UID: NO , using password: NO)" ); return SQL_ERROR; } RETCODE ret; // check if prompt required ie any info is missing if ( flgDriver && ( !flgServer || !flgPort || !flgUID || !flgPWD || !flgProj ) ) { __ODBCLOG ( _ODBCLogMsg ( LogLevel_INFO, "Connection info imcomplete, prompt for input..." ) ); if ( flgUID && !flgPWD && pDriverCompletion == SQL_DRIVER_NOPROMPT ) { _SQLPutDiagRow ( SQL_HANDLE_DBC, pConn, "SQLDriverConnectW", "HY000", 1045, "Access denied for user 'root'@'kylin-tableau-clean.com' (using password: NO)" ); __ODBCLOG ( _ODBCLogMsg ( LogLevel_ERROR, "UID present but PWD absent, guessing it's on Tableau Server, return SQL ERROR" ) ); return SQL_ERROR; } //connect by driver // fetch entire connection information thru dialogs switch ( PromptForConnInfo ( pConn ) ) { case 0: // user-cancelled return SQL_NO_DATA_FOUND; default: break; } ret = SQL_SUCCESS; } else { ret = TryFetchMetadata ( pgConn ) ; if ( ret == SQL_ERROR ) { return ret; } } // OUT CONN STRING // build the out-connection string if required if ( pOutConnStr && pOutConnStrLen > 0 && pOutConnStrLenPtr ) { if ( flgDriver ) { __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "Building out str..." ) ); // build the out conn string using key value pairs f = BuildConnStr ( ( StrPtr ) pOutConnStr, pOutConnStrLen, ( pODBCConn ) pConn, NULL, 0, NULL, 0 ); if ( !f ) { _SQLPutDiagRow ( SQL_HANDLE_DBC, pConn, "SQLDriverConnectW", "HY000", 1045, "Out connection string not complete" ); } } else { __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "Copy in str to out str" ) ); strcpy ( ( char* ) pOutConnStr, ( char* ) pInConnStr ); } *pOutConnStrLenPtr = strlen ( ( StrPtr ) pOutConnStr ); __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "The Length of Out Conn Str is %d", *pOutConnStrLenPtr ) ); } else { __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "skip writing to the out put string" ) ); } return ret; }
/* From msdn: SQLRETURN SQLBindCol( SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, SQLPOINTER TargetValuePtr, SQLLEN BufferLength, SQLLEN * StrLen_or_Ind); */ RETCODE SQL_API SQLBindCol ( SQLHSTMT pStmt, SQLUSMALLINT pColNum, SQLSMALLINT pDataType, SQLPOINTER pDataPtr, SQLLEN pDataSize, SQLLEN* pDataSizePtr ) { __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLBindCol called, ColNum: %d, TgtType: %d, ValuePtr: %d, Capacity: %d", pColNum, pDataType, pDataPtr, pDataSize ) ); pODBCARD ard; // application row descriptor pARDItem ardcol; // application row descriptor item __CHK_HANDLE ( pStmt, SQL_HANDLE_STMT, SQL_ERROR ); // free diags _SQLFreeDiag ( _DIAGSTMT ( pStmt ) ); // extract the appl. row descriptor from stmt ard = & ( ( ( pODBCStmt ) pStmt )->ARD ); // get the specified column if already bound ardcol = _SQLGetARDItem ( ard, pColNum ); // EXISTS if ( ardcol != NULL ) { // check if total unbind is required if ( pDataPtr == NULL && pDataSizePtr == NULL ) { // detach it from ARD link list _SQLDetachARDItem ( ard, ardcol ); // free delete ardcol; } else { // unbind/rebind col details _SQLSetARDItemField ( ard, ardcol, pColNum, SQL_DESC_DATA_PTR, pDataPtr, -1 ); _SQLSetARDItemField ( ard, ardcol, pColNum, SQL_DESC_CONCISE_TYPE, ( void* ) pDataType, -1 ); _SQLSetARDItemField ( ard, ardcol, pColNum, SQL_DESC_LENGTH, ( void* ) pDataSize, -1 ); _SQLSetARDItemField ( ard, ardcol, pColNum, SQL_DESC_OCTET_LENGTH_PTR, pDataSizePtr, -1 ); // reset the source data type ardcol->SrcDataType = 0; } return SQL_SUCCESS; } // DOES NOT EXIST // check for bad params if ( pDataPtr == NULL && pDataSizePtr == NULL ) { _SQLPutDiagRow ( SQL_HANDLE_STMT, pStmt, "SQLBindCol", "01000", -1, "Bad params" ); return SQL_ERROR; } // check for bad params else if ( pDataSize < 0 ) { _SQLPutDiagRow ( SQL_HANDLE_STMT, pStmt, "SQLBindCol", "01000", -1, "Invalid buffer length" ); return SQL_ERROR; } // CREATE // allocate a new col-item ardcol = new ARDItem; // reset _SQLSetARDItemFieldsDefault ( ardcol, pColNum ); // set all values - bind _SQLSetARDItemField ( ard, ardcol, pColNum, SQL_DESC_DATA_PTR, pDataPtr, -1 ); _SQLSetARDItemField ( ard, ardcol, pColNum, SQL_DESC_CONCISE_TYPE, ( void* ) pDataType, -1 ); _SQLSetARDItemField ( ard, ardcol, pColNum, SQL_DESC_LENGTH, ( void* ) pDataSize, -1 ); _SQLSetARDItemField ( ard, ardcol, pColNum, SQL_DESC_OCTET_LENGTH_PTR, pDataSizePtr, -1 ); // attach it to link list _SQLAttachARDItem ( ard, ardcol ); return SQL_SUCCESS; }
//mhb TODO, check if the sqltype defined here match from c# RETCODE SQL_API _SQLColConvert ( pODBCStmt pStmt, void* pTgtDataPtr, Long* pTgtDataSizePtr, const wchar_t* pSrcColData, pARDItem pARDCol, bool isSigned ) { //check out this for SQL data type to C data type mapping //http://msdn.microsoft.com/en-us/library/ms714556(v=vs.85).aspx // note // this function actually determines the conversion // required to transfer the data Word pSrcDataType = pARDCol->SrcDataType; Word pTgtDataType = pARDCol->DataConciseType; Long pTgtDataSize = pARDCol->DataSize; __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "_SQLColConvert called" ) ); __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "The SrcDataType is %d, the TgtDataType is %d, the TgtDataSize is %d", pSrcDataType, pTgtDataType, pTgtDataSize ) ); // TARGET TYPE IS LEFT TO OUR DRIVER // check if target type is open if ( pTgtDataType == SQL_DEFAULT ) { __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "pTgtDataType is SQL_DEFAULT, use default type mapping." ) ); // determine targettype based on data-source type // check out this http://msdn.microsoft.com/en-us/library/ms716298(v=vs.85).aspx for default type mapping switch ( pSrcDataType ) { case SQL_CHAR: pTgtDataType = SQL_C_CHAR; break; case SQL_VARCHAR: pTgtDataType = SQL_C_CHAR; break; case SQL_WCHAR: pTgtDataType = SQL_C_WCHAR; break; case SQL_WVARCHAR: pTgtDataType = SQL_C_WCHAR; break; case SQL_DECIMAL: pTgtDataType = SQL_C_CHAR; break; case SQL_BIT: pTgtDataType = SQL_C_BIT; break; case SQL_TINYINT: if ( isSigned ) { pTgtDataType = SQL_C_STINYINT; } else { pTgtDataType = SQL_C_UTINYINT; } break; case SQL_SMALLINT: if ( isSigned ) { pTgtDataType = SQL_C_SSHORT; } else { pTgtDataType = SQL_C_USHORT; } break; case SQL_INTEGER: if ( isSigned ) { pTgtDataType = SQL_C_SLONG; } else { pTgtDataType = SQL_C_ULONG; } break; case SQL_BIGINT: if ( isSigned ) { pTgtDataType = SQL_C_SBIGINT; } else { pTgtDataType = SQL_C_UBIGINT; } break; case SQL_FLOAT: pTgtDataType = SQL_C_FLOAT; break; case SQL_DOUBLE: pTgtDataType = SQL_C_DOUBLE; break; case SQL_TYPE_DATE: pTgtDataType = SQL_C_CHAR; break; case SQL_TYPE_TIME: pTgtDataType = SQL_C_CHAR; break; case SQL_TYPE_TIMESTAMP: pTgtDataType = SQL_C_CHAR; break; //case SQL_C_SLONG: //case SQL_C_ULONG: // unsigned long //case SQL_C_USHORT: //case SQL_C_SSHORT: //case SQL_NUMERIC: //case SQL_REAL: // pTgtDataType = pSrcDataType; // break; default: __ODBCPOPMSG ( _ODBCPopMsg ( "The data type %d not implemented", pSrcDataType ) ); return SQL_ERROR; break; } } else { __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "pTgtDataType is NOT SQL_DEFAULT, it is %d", pTgtDataType ) ); } // TARGET TYPE IS CHAR // as an optimization, check if the application // or target data type is char. since the data from // server is already in char format. the data can // easily be transferred without incurring any // conversion overhead unique_ptr<char[]> pTextInAnsi ( wchar2char ( pSrcColData ) ); // check if char type if ( pTgtDataType == SQL_CHAR || pTgtDataType == SQL_VARCHAR ) { // only in case of src data being bool a conversion is required if ( pSrcDataType == SQL_BIT ) { // prepare a converted single char bool string Char src[2]; if ( pTextInAnsi.get() == NULL ) { src[0] = '0'; } else { src[0] = ( pTextInAnsi.get() [0] == 'T' || pTextInAnsi.get() [0] == '1' || pTextInAnsi.get() [0] == 't' ) ? '1' : '0'; } src[1] = 0; // transfer the bool string return _SQLCopyCharData ( _DIAGSTMT ( pStmt ), pTgtDataPtr, pARDCol->DataSize, pTgtDataSizePtr, 32, src, -1 ); } else { // transfer the string as it is return _SQLCopyCharData ( _DIAGSTMT ( pStmt ), pTgtDataPtr, pARDCol->DataSize, pTgtDataSizePtr, 32, pTextInAnsi.get(), -1 ); } } if ( pTgtDataType == SQL_WCHAR || pTgtDataType == SQL_WVARCHAR ) { return _SQLCopyWCharDataW ( _DIAGSTMT ( pStmt ), pTgtDataPtr, pARDCol->DataSize, pTgtDataSizePtr, 32, pSrcColData, -1 ); } // TARGET TYPE IS NOT CHAR // try using a numeric conversion switch ( _SQLCopyNumData ( _DIAGSTMT ( pStmt ), pTgtDataPtr, pTgtDataType, pTextInAnsi.get(), pSrcDataType , pTgtDataSizePtr ) ) { case -1: return SQL_ERROR; case 0: return SQL_SUCCESS; default: break; } // try using a date/time conversion switch ( _SQLCopyDateTimeData ( _DIAGSTMT ( pStmt ), pTgtDataPtr, pTgtDataType, pTextInAnsi.get(), pSrcDataType ) ) { case -1: return SQL_ERROR; case 0: return SQL_SUCCESS; default: break; } // try using SQL_BIT data type ie bool if ( pTgtDataType == SQL_BIT ) { __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "the target data type is SQL_C_BIT" ) ); // prepare a converted single char bool string if ( pTextInAnsi.get() == NULL ) { * ( ( char* ) pTgtDataPtr ) = 0; } else { * ( ( char* ) pTgtDataPtr ) = ( pTextInAnsi.get() [0] == 'T' || pTextInAnsi.get() [0] == '1' || pTextInAnsi.get() [0] == 't' ) ? 1 : 0; } return SQL_SUCCESS; } // error condition __ODBCPOPMSG ( _ODBCPopMsg ( "_SQLColConvert - Unknown data type, Target: %d, Source: %d", pTgtDataType, pSrcDataType ) ); _SQLPutDiagRow ( SQL_HANDLE_STMT, pStmt, "_SQLColConvert", "01000", -1, "Unknown data type, Target: %d, Source: %d", pTgtDataType, pSrcDataType ); return SQL_ERROR; }
RETCODE _SQLColAttribute_basic ( SQLHSTMT pStmt, SQLUSMALLINT pColNum, SQLUSMALLINT pFldID, SQLPOINTER pDataPtr, SQLSMALLINT pDataSize, SQLSMALLINT* pDataSizePtr, // in bytes SQLPOINTER pNumValuePtr ,// integer bool isANSI ) { //if returned data is numeric, feed this Long n; SQLResponse* ird; pIRDItem col; __CHK_HANDLE ( pStmt, SQL_HANDLE_STMT, SQL_ERROR ); // free diags _SQLFreeDiag ( _DIAGSTMT ( pStmt ) ); // precaution if ( pColNum == 0 ) { _SQLPutDiagRow ( SQL_HANDLE_STMT, pStmt, "SQLColAttribute", "01000", -1, "bad params" ); return SQL_ERROR; } // get the row descriptor obtained with response ird = ( ( ( pODBCStmt ) pStmt )->IRD ).RowDesc.get(); // check if ( ird == NULL ) { _SQLPutDiagRow ( SQL_HANDLE_STMT, pStmt, "SQLColAttribute", "01000", -1, "No resultset or no col descriptors" ); return SQL_ERROR; } // find the xth element/col col = _SQLGetIRDItem ( & ( ( ( pODBCStmt ) pStmt )->IRD ), pColNum ); // check if ( col == NULL ) { _SQLPutDiagRow ( SQL_HANDLE_STMT, pStmt, "SQLColAttribute", "01000", -1, "Invalid col num" ); return SQL_ERROR; } // get value from descriptor as per field type switch ( pFldID ) { // numeric types clubbed together case SQL_DESC_AUTO_UNIQUE_VALUE: // is col auto-incrementing case SQL_DESC_CASE_SENSITIVE: // is col case-insensitive case SQL_DESC_TYPE: // verbose type case SQL_DESC_CONCISE_TYPE: // concise type case SQL_DESC_COUNT: // no.of highest bound column case SQL_DESC_LENGTH: case SQL_DESC_DISPLAY_SIZE: case SQL_DESC_OCTET_LENGTH: case SQL_DESC_FIXED_PREC_SCALE: case SQL_DESC_NULLABLE: case SQL_DESC_NUM_PREC_RADIX: case SQL_DESC_PRECISION: case SQL_DESC_SCALE: case SQL_DESC_SEARCHABLE: case SQL_DESC_UNNAMED: case SQL_DESC_UNSIGNED: case SQL_DESC_UPDATABLE: _SQLGetIRDItemField ( & ( ( ( pODBCStmt ) pStmt )->IRD ), col, pColNum, pFldID, pNumValuePtr, -1, NULL , isANSI ); break; // char types clubbed together case SQL_DESC_BASE_TABLE_NAME: // table name for column case SQL_DESC_CATALOG_NAME: // database name case SQL_DESC_LITERAL_PREFIX: case SQL_DESC_LITERAL_SUFFIX: case SQL_DESC_LOCAL_TYPE_NAME: case SQL_DESC_TYPE_NAME: case SQL_DESC_SCHEMA_NAME: case SQL_DESC_TABLE_NAME: _SQLGetIRDItemField ( & ( ( ( pODBCStmt ) pStmt )->IRD ), col, pColNum, pFldID, pDataPtr, pDataSize, pDataSizePtr ? &n : NULL, isANSI ); if ( pDataSizePtr ) { *pDataSizePtr = ( Word ) n; } break; case SQL_DESC_BASE_COLUMN_NAME: case SQL_DESC_LABEL: case SQL_DESC_NAME: // //// // as a special case the name length may be required without the actual name ////// StrPtr cname; Word cnamesize; if ( pDataPtr ) { cname = ( StrPtr ) pDataPtr; cnamesize = pDataSize; } else { cname = new Char[256]; // arbitary cnamesize = 255; } _SQLGetIRDItemField ( & ( ( ( pODBCStmt ) pStmt )->IRD ), col, pColNum, pFldID, cname, cnamesize, pDataSizePtr ? &n : NULL, isANSI ); if ( pDataPtr == NULL ) { delete[] cname; } if ( pDataSizePtr ) { *pDataSizePtr = ( Word ) n; } break; default: __ODBCPOPMSG ( _ODBCPopMsg ( "SQLColAttribute unknown attr, ColNum: %d, FldID: %d\n", pColNum, pFldID ) ); return SQL_ERROR; } return SQL_SUCCESS; }
RETCODE SQL_API _SQLFetchCol ( pODBCStmt pStmt, pARDItem pARDCol, //ard SQLResponse* pRowDesc,// ird SQLRowContent* pRowData ) { //content __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "_SQLFetchCol called" ) ); // note // this function checks the binding type and positions the pointer // for copying the data accordingly. It takes into account the // current row position in rowset, the initial min increment specified // by client and the size of the row or col buffer Long i; Long j; Long* tgtsizeptr; // target size ptr void* tgtdataptr; // target data ptr const wchar_t* srcdata; // source data SelectedColumnMeta* coldesc; // COMPUTE DATA AND SIZE PTR // get the row pos in current rowset i = ( pStmt->CurRowsetEndRowPos - pStmt->CurRowsetStartRowPos ); // compute min increment j = ( pStmt->ARD.BindOffsetPtr ) ? * ( pStmt->ARD.BindOffsetPtr ) : 0; // check the binding type if ( pStmt->ARD.BindTypeOrSize != SQL_BIND_BY_COLUMN ) { __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "ARD bindtypeorsize not euqal to SQL_BIND_BY_COLUMN" ) ); // note Long k; // compute row-size increment k = ( pStmt->ARD.BindTypeOrSize ); // compute target col and size ptr tgtdataptr = ( void* ) ( ( ( Char* ) ( pARDCol->DataPtr ) ) + j + ( i * k ) ); tgtsizeptr = ( Long* ) ( ( ( Char* ) ( pARDCol->SizePtr ) ) + j + ( i * k ) ); } // column-wise binding else { __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "ARD bindtypeorsize euqal to SQL_BIND_BY_COLUMN" ) ); // move both data and size ptr in the array //TODO find out where the pARDCol->DataSize if set tgtdataptr = ( void* ) ( ( ( Char* ) ( pARDCol->DataPtr ) ) + j + ( i * pARDCol->DataSize ) ); // use based on data type tgtsizeptr = ( Long* ) ( ( ( Char* ) ( pARDCol->SizePtr ) ) + j + ( i * sizeof ( Long ) ) ); } // PRECAUTION if ( tgtdataptr ) { * ( ( Char* ) tgtdataptr ) = 0; } if ( tgtsizeptr ) { * ( ( Long* ) tgtsizeptr ) = 0; } // COLLECT AND CHECK // get col desc for specified col ( response ) coldesc = pRowDesc->columnMetas.at ( pARDCol->ColNum - 1 ); //if ( coldesc == NULL ) { // _SQLPutDiagRow ( SQL_HANDLE_STMT, pStmt, "_SQLFetchCol", "01000", -1, pStmt->CurRowsetEndRowPos, pARDCol->ColNum, "column not found in resultset for specified index" ); // return SQL_SUCCESS_WITH_INFO; // no col for specified index //} // get the col data for specfied col ( response ) srcdata = pRowData->contents.at ( pARDCol->ColNum - 1 ).c_str(); //coldata = SOAPGetChildElemX ( pRowData, pARDCol->ColNum ); //if ( coldata == NULL ) { // _SQLPutDiagRow ( SQL_HANDLE_STMT, pStmt, "_SQLFetchCol", "01000", -1, pStmt->CurRowsetEndRowPos, pARDCol->ColNum, "column not found in resultset for specified index" ); // return SQL_SUCCESS_WITH_INFO; // no col for specified index //} // get col value as string //srcdata = SOAPGetElemText ( coldata ); // NULL DATA // note: a text of NULL indicates NULL data from server // check if data is NULL if ( srcdata == NULL || _wcsicmp ( srcdata, L"NULL" ) == 0 ) { __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "srcdata is null" ) ); // check if a size indicator is available if ( tgtsizeptr == NULL ) { _SQLPutDiagRow ( SQL_HANDLE_STMT, pStmt, "_SQLFetchCol", "22002", -1, pStmt->CurRowsetEndRowPos, pARDCol->ColNum, "Indicator variable required but not supplied" ); return SQL_SUCCESS_WITH_INFO; } // set to SQL_NULL_DATA else { // indicate null data * ( ( Long* ) tgtsizeptr ) = SQL_NULL_DATA; // added precaution for bad appl design /* if ( tgtdataptr ) memset ( tgtdataptr, 0, pARDCol->MaxSize );*/ return SQL_SUCCESS; } } // check if info about src is also available in ARD col if ( pARDCol->SrcDataType == 0 ) { GetIRDColDescInfo ( coldesc, & ( pARDCol->SrcDataType ), & ( pARDCol->SrcDataPrecision ), & ( pARDCol->SrcDataScale ), & ( pARDCol->SrcDataSize ) ); } // collect source data information in form comparable to appl // CONVERT AND TRANSFER //Important!!! //Notice the specification of different types //http://publib.boulder.ibm.com/infocenter/idshelp/v10/index.jsp?topic=/com.ibm.odbc.doc/odbc72.htm RETCODE ret = _SQLColConvert ( pStmt, tgtdataptr, tgtsizeptr, srcdata, pARDCol, coldesc->isSigned ); //char buffer[1024]; //hexDump((char*)tgtdataptr,4,buffer,false); //__ODBCLOG(_ODBCLogMsg(LogLevel_DEBUG,buffer)); //hexDump((char*)tgtdataptr,4,buffer,true); //__ODBCLOG(_ODBCLogMsg(LogLevel_DEBUG,buffer)); return ret; }
//mhb added, for those ard that accept wchar RETCODE SQL_API _SQLCopyWCharDataW ( pODBCDiag pDiag, void* pTgtDataPtr, Long pDataBufSize, void* pSizePtr, Word pSizePtrSize, const wchar_t* pSrcData, Long pSrcDataSize ) { __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "_SQLCopyWCharDataW called, pTgtDataPtr is null? %d, pSizePtr == null? %d", pTgtDataPtr == NULL, pSizePtr == NULL ) ); __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "_SQLCopyWCharDataW called, the src string is :" ) ); __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, pSrcData ) ); Long n; // caller safe if ( pTgtDataPtr ) { * ( ( wchar_t* ) pTgtDataPtr ) = 0; } // DATA SIZE // check source data to compute size if ( pSrcData && _wcsicmp ( pSrcData, L"NULL" ) != 0 ) { n = ( pSrcDataSize < 0 ) ? wcslen ( pSrcData ) : pSrcDataSize; } // compute length based on whether null terminated else { n = 0; } // check if there is a holder for size if ( pSizePtr ) { // set size as per ptr type 16-bt or 32-bit //should be number of characters if ( pSizePtrSize == 16 ) { * ( ( Word* ) pSizePtr ) = ( Word ) ( 2 * n ); } else { * ( ( Long* ) pSizePtr ) = ( 2 * n ); } __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "pSizePtr is set to %d", n ) ); } // check if src data but no size holder else if ( pSrcData ) { // check if diag to be set if ( pDiag ) { _SQLPutDiagRow ( pDiag, "_SQLCopyWCharDataW", "01000", -1, "No holder for data size", NULL ); } __ODBCPOPMSG ( _ODBCPopMsg ( "_SQLCopyWCharDataW - No holder for data size" ) ); return SQL_ERROR; } // DATA // check if there is a target holder if ( pTgtDataPtr ) { // check if there is a source pointer if ( pSrcData ) { // does all of it fit with null char if ( pDataBufSize >= ( n + 1 ) ) { memcpy ( ( StrPtr ) pTgtDataPtr, pSrcData, 2 * ( n + 1 ) ); ( ( wchar_t* ) pTgtDataPtr ) [n] = '\0'; //__ODBCLOG(_ODBCLogMsg(LogLevel_DEBUG,"_SQLCopyWCharDataW has been called, the target string(not truncated) is :")); //unique_ptr<char[]> temp2(wchar2char( (wchar_t*)pTgtDataPtr)); //__ODBCLOG(_ODBCLogMsg(LogLevel_DEBUG,temp2.get())); return SQL_SUCCESS; } // all of it does not fit else { //if(pDataBufSize % 2 == 1) // pDataBufSize -= 1; memcpy ( ( StrPtr ) pTgtDataPtr, pSrcData, 2 * ( pDataBufSize - 1 ) ); ( ( wchar_t* ) pTgtDataPtr ) [pDataBufSize - 1] = 0; //__ODBCLOG(_ODBCLogMsg(LogLevel_WARN,"_SQLCopyWCharDataW has been called, the target string is(truncated) :")); unique_ptr<char[]> temp ( wchar2char ( ( wchar_t* ) pTgtDataPtr ) ); //__ODBCLOG(_ODBCLogMsg(LogLevel_DEBUG, temp.get())); //return SQL_SUCCESS_WITH_INFO may cause error in tableau //if ( pDiag ) // _SQLPutDiagRow ( pDiag, "_SQLCopyWCharDataW", "01000", -1, "string data truncated", NULL ); //return SQL_SUCCESS_WITH_INFO; __ODBCLOG ( _ODBCLogMsg ( LogLevel_WARN, "string data truncated" ) ); return SQL_SUCCESS; } } // tgt data but no src data else { // clear tgt * ( ( wchar_t* ) pTgtDataPtr ) = 0; __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "_SQLCopyWCharDataW has been called, the string is (empty) %s", pTgtDataPtr ) ); } } return SQL_SUCCESS; }