| /* |
| * 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. |
| */ |
| |
| |
| // ---------------------------------------------------------------------------- |
| // |
| // File: KO_FETCH.CPP |
| // |
| // Purpose: Contains function for fetching results. |
| // As explained in the article ODBC has a |
| // defined way in which the data is made available. |
| // |
| // 1. The client CAN obtain general details |
| // about the result like num of rows etc using |
| // SQLRowCount, SQLNumResultCols. |
| // |
| // 2. It obtains metadata about the result |
| // more specifically info about columns like |
| // size type etc using SQLColAttribute or |
| // SQLDescribeCol. |
| // |
| // 3. Then it allocates and bind the buffer |
| // specifying the other info like buffer size |
| // etc for the cols it desires to extract using |
| // SQLBindCol |
| // |
| // 4. Then it instructs the driver to feed these |
| // buffers using SQLFetch or SQLExtendedFetch. |
| // |
| // 5. This is the general way. In case the data |
| // involved is quite large, it can be extracted |
| // piecemeal using SQLGetData. SQLPutData is the |
| // funcion corresponding to SQLGetData to specify |
| // large param values say storing images etc. |
| // Since I have not implemented params or long |
| // data read write in this sample, SQLPutData resides |
| // in this file with SQLGetData. |
| // |
| // All fetch occur via the local function _SQLFetch. |
| // Internally the fetch is executed in the following |
| // way. |
| // 1. The rowdesc from server (IRD) and appl (ARD ) |
| // is obtained. |
| // 2. Main loop to fetch rowset number of rows. More |
| // than one row can be fetched at a time. The movement |
| // in resulset is done using _SQLFetchMoveNext. |
| // 3. For each row, loop through each ARD item to |
| // extract the col(s) required by the client. |
| // |
| // SQLColConvert and associated funtions _SQLCopyCharData, |
| // SQLCopyNumData, _SQLCopyDateTimeData r used to perform |
| // necessary conversion between data as recived from the |
| // server and data as required by the client. |
| // |
| // Exported functions: |
| // SQLColAttribute |
| // SQLDescribeCol |
| // SQLBindCol |
| // SQLNumResultCols |
| // SQLRowCount |
| // SQLFetch |
| // SQLExtendedFetch |
| // SQLFetchScroll |
| // SQLGetData |
| // SQLPutData |
| // SQLMoreResults |
| // SQLNativeSql |
| // |
| // ---------------------------------------------------------------------------- |
| #include "stdafx.h" |
| |
| #include "Dump.h" |
| |
| // ------------------------- local functions ----------------------------- |
| RETCODE SQL_API _SQLFetch ( pODBCStmt pStmt, Word pFetchOrientation, Long pFetchOffset, ULong* pRowCountPtr, |
| UWord* pRowStatusArray ); |
| RETCODE SQL_API _SQLColConvert ( pODBCStmt pStmt, void* pTgtDataPtr, Long* pTgtDataSizePtr, CStrPtr pSrcColData, |
| pARDItem pARDCol, bool isSigned ); |
| RETCODE SQL_API _SQLFetchMoveNext ( pODBCStmt pStmt ); |
| RETCODE SQL_API _SQLResetRowPos ( pODBCStmt pStmt ); |
| |
| SQLRowContent* GetIfExist ( std::vector <SQLRowContent*>& container, int index ); |
| |
| // ----------------------------------------------------------------------- |
| // to get specific detail//attribute about a col returned from server --- FROM IRD |
| // kylin specific |
| // ----------------------------------------------------------------------- |
| |
| |
| 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; |
| } |
| |
| __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLColAttribute_basic called, ColNum: %d, FldID: %d", pColNum, pFldID ) ); |
| |
| // 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 : |
| // added for Excel |
| case SQL_COLUMN_LENGTH : |
| case SQL_COLUMN_PRECISION : |
| case SQL_COLUMN_SCALE : |
| _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; |
| } |
| //unique_ptr<char[]> temp ( wchar2char ( ( wchar_t* ) pDataPtr ) ); |
| //__ODBCLOG(_ODBCLogMsg(LogLevel_INFO, "_SQLColAttribute_basic was called - Stmt:%d, ColNum:%d, FldId:%d, pDataStr:%s, pDataSize:%d, pDataSizePtr:%d(n:%d), pNumValPtr:%d", |
| // pStmt, pColNum, pFldID, temp.get(), pDataSize, pDataSizePtr, n, pNumValuePtr ? *(( Long* )pNumValuePtr):-1)); |
| return SQL_SUCCESS; |
| } |
| |
| |
| #ifdef _WIN64 |
| RETCODE SQL_API SQLColAttributeW ( SQLHSTMT pStmt, |
| SQLUSMALLINT pColNum, |
| SQLUSMALLINT pFldID, |
| SQLPOINTER pDataPtr, |
| SQLSMALLINT pDataSize, |
| SQLSMALLINT* pDataSizePtr, |
| SQLLEN* pNumValuePtr ) { |
| __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLColAttributeW called, ColNum: %d, FldID: %d", pColNum, pFldID ) ); |
| RETCODE code = _SQLColAttribute_basic ( pStmt, pColNum, pFldID, pDataPtr, pDataSize, pDataSizePtr, pNumValuePtr, |
| false ); |
| __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "the return code is %d", code ) ); |
| return code; |
| } |
| |
| RETCODE SQL_API SQLColAttribute ( SQLHSTMT pStmt, |
| SQLUSMALLINT pColNum, |
| SQLUSMALLINT pFldID, |
| SQLPOINTER pDataPtr, |
| SQLSMALLINT pDataSize, |
| SQLSMALLINT* pDataSizePtr, |
| SQLLEN* pNumValuePtr ) { |
| __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLColAttributeW called, ColNum: %d, FldID: %d", pColNum, pFldID ) ); |
| RETCODE code = _SQLColAttribute_basic ( pStmt, pColNum, pFldID, pDataPtr, pDataSize, pDataSizePtr, pNumValuePtr, |
| true ); |
| __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "the return code is %d", code ) ); |
| return code; |
| } |
| |
| #else |
| RETCODE SQL_API SQLColAttributeW ( SQLHSTMT pStmt, |
| SQLUSMALLINT pColNum, |
| SQLUSMALLINT pFldID, |
| SQLPOINTER pDataPtr, |
| SQLSMALLINT pDataSize, |
| SQLSMALLINT* pDataSizePtr, |
| SQLPOINTER pNumValuePtr ) |
| { |
| __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLColAttributeW called, ColNum: %d, FldID: %d", pColNum, pFldID ) ); |
| RETCODE code = _SQLColAttribute_basic ( pStmt, pColNum, pFldID, pDataPtr, pDataSize, pDataSizePtr, pNumValuePtr, |
| false ); |
| __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "the return code is %d", code ) ); |
| return code; |
| } |
| |
| RETCODE SQL_API SQLColAttribute ( SQLHSTMT pStmt, |
| SQLUSMALLINT pColNum, |
| SQLUSMALLINT pFldID, |
| SQLPOINTER pDataPtr, |
| SQLSMALLINT pDataSize, |
| SQLSMALLINT* pDataSizePtr, |
| SQLPOINTER pNumValuePtr ) |
| { |
| __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLColAttributeW called, ColNum: %d, FldID: %d", pColNum, pFldID ) ); |
| return _SQLColAttribute_basic ( pStmt, pColNum, pFldID, pDataPtr, pDataSize, pDataSizePtr, pNumValuePtr, true ); |
| } |
| #endif |
| |
| // ---------------------------------------------------------------------- |
| // to get the basic set of ARD col attributes, ie details recd. from server --- FROM IRD |
| // SQLDescribeCol returns the result descriptor �� column name,type, column size, decimal digits, and nullability (from msdn) |
| // kylin specific |
| // ---------------------------------------------------------------------- |
| |
| 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 ); |
| |
| // here should return length of characters |
| if ( pColNameSizePtr ) |
| { |
| if ( isANSI ) |
| { |
| *pColNameSizePtr = ( Word ) n; |
| } |
| else |
| { |
| *pColNameSizePtr = ( Word ) ( n / 2 ); |
| } |
| } |
| |
| __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, (wchar_t*)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; |
| } |
| |
| SQLRETURN SQL_API SQLDescribeColW ( SQLHSTMT pStmt, |
| SQLUSMALLINT pColNum, |
| SQLWCHAR* pColNamePtr, |
| SQLSMALLINT pColNameSize, |
| SQLSMALLINT* pColNameSizePtr, |
| SQLSMALLINT* pDataTypePtr, |
| SQLULEN* pColSizePtr, |
| SQLSMALLINT* pDecimalDigitsPtr, |
| SQLSMALLINT* pNullablePtr ) |
| { |
| __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, |
| "SQLDescribeColW. Col: %d, ColNamePtr: %d, ColNameSize: %d, ColNameSizePtr: %d, DataTypePtr: %d, ColSizePtr: %d, DecDigitsPtr: %d, NullPtr: %d", |
| pColNum, pColNamePtr, pColNameSize, pColNameSizePtr, pDataTypePtr, pColSizePtr, pDecimalDigitsPtr, pNullablePtr ) ); |
| return _SQLDescribeCol_basic ( pStmt, pColNum, pColNamePtr, pColNameSize, pColNameSizePtr, pDataTypePtr, pColSizePtr, |
| pDecimalDigitsPtr, pNullablePtr, false ); |
| } |
| |
| SQLRETURN SQL_API SQLDescribeCol ( SQLHSTMT pStmt, |
| SQLUSMALLINT pColNum, |
| SQLCHAR* pColNamePtr, |
| SQLSMALLINT pColNameSize, |
| SQLSMALLINT* pColNameSizePtr, |
| SQLSMALLINT* pDataTypePtr, |
| SQLULEN* pColSizePtr, |
| SQLSMALLINT* pDecimalDigitsPtr, |
| SQLSMALLINT* pNullablePtr ) |
| { |
| __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, |
| "SQLDescribeCol. Col: %d, ColNamePtr: %d, ColNameSize: %d, ColNameSizePtr: %d, DataTypePtr: %d, ColSizePtr: %d, DecDigitsPtr: %d, NullPtr: %d", |
| pColNum, pColNamePtr, pColNameSize, pColNameSizePtr, pDataTypePtr, pColSizePtr, pDecimalDigitsPtr, pNullablePtr ) ); |
| return _SQLDescribeCol_basic ( pStmt, pColNum, pColNamePtr, pColNameSize, pColNameSizePtr, pDataTypePtr, pColSizePtr, |
| pDecimalDigitsPtr, pNullablePtr, true ); |
| } |
| |
| // ----------------------------------------------------------------------- |
| // to bind a column to with details from application --- TO ARD |
| // kylin specific, no change required |
| // ----------------------------------------------------------------------- |
| |
| /* |
| |
| 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; |
| } |
| |
| |
| // --------------------------------------------------------------------- |
| // to get the number of columns in result --- COUNTING ELEMENTS IN IRD.ROWDESC |
| // Kylin specific |
| // --------------------------------------------------------------------- |
| |
| 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; |
| } |
| |
| |
| // ---------------------------------------------------------------------- |
| // to count the number of rows in the current result --- COUNTING ELEMENTS IN IRD |
| // ---------------------------------------------------------------------- |
| |
| RETCODE SQL_API SQLRowCount ( HSTMT pStmt, SQLLEN* pDataPtr ) |
| { |
| __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLRowCount called" ) ); |
| __CHK_HANDLE ( pStmt, SQL_HANDLE_STMT, SQL_ERROR ); |
| // free diags |
| _SQLFreeDiag ( _DIAGSTMT ( pStmt ) ); |
| *pDataPtr = ( ( pODBCStmt ) pStmt ) -> RowCount; |
| __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLRowCount returned: %d", *pDataPtr ) ); |
| return SQL_SUCCESS; |
| } |
| |
| // ----------------------------------------------------------------------- |
| // to return the next row from the resultset |
| // ----------------------------------------------------------------------- |
| |
| RETCODE SQL_API SQLFetch ( HSTMT pStmt ) |
| { |
| __CHK_HANDLE ( pStmt, SQL_HANDLE_STMT, SQL_ERROR ); |
| // free diags |
| _SQLFreeDiag ( _DIAGSTMT ( pStmt ) ); |
| // all fetch occur thru the local function _SQLFetch |
| /* |
| RETCODE SQL_API _SQLFetch ( pODBCStmt pStmt, |
| Word pFetchOrientation, |
| Long pFetchOffset, |
| ULong* pRowCountPtr, |
| UWord* pRowStatusArray ) |
| */ |
| RETCODE ret = _SQLFetch ( ( pODBCStmt ) pStmt, SQL_FETCH_NEXT, |
| ( ( pODBCStmt ) pStmt ) -> ARD . RowArraySize > 0 ? ( ( pODBCStmt ) pStmt ) -> ARD . RowArraySize : 1, |
| ( ( pODBCStmt ) pStmt ) -> IRD . RowsProcessedPtr, ( ( pODBCStmt ) pStmt ) -> IRD . ArrayStatusPtr ); |
| |
| if ( ret == SQL_NO_DATA ) |
| { |
| __ODBCLOG ( _ODBCLogMsg ( LogLevel_INFO, "Last row of current query has been fetched" ) ); |
| } |
| |
| return ret; |
| } |
| |
| // ----------------------------------------------------------------------- |
| // to fetch the specified rowset of data from the result set |
| // Version Introduced: ODBC 1.0 Standards Compliance: Deprecated (from msdn) |
| // ----------------------------------------------------------------------- |
| |
| RETCODE SQL_API SQLExtendedFetch ( SQLHSTMT pStmt, |
| SQLUSMALLINT pFetchOrientation, |
| SQLINTEGER pFetchOffset, |
| SQLUINTEGER* pRowCountPtr, |
| SQLUSMALLINT* pRowStatusArray ) |
| { |
| __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, |
| "SQLExtendedFetch called, Stmt: %d, FO: %d, Offset: %d, Rcount: %d, RowStatus: %d", pStmt, pFetchOrientation, |
| pFetchOffset, pRowCountPtr, pRowStatusArray ) ); |
| __ODBCPOPMSG ( _ODBCPopMsg ( "SQLExtendedFetch is not implemented " ) ); |
| return SQL_ERROR; |
| Long n; |
| __CHK_HANDLE ( pStmt, SQL_HANDLE_STMT, SQL_ERROR ); |
| // free diags |
| _SQLFreeDiag ( _DIAGSTMT ( pStmt ) ); |
| |
| // only fetch next supported |
| if ( pFetchOrientation != SQL_FETCH_NEXT ) |
| { |
| __ODBCPOPMSG ( _ODBCPopMsg ( "SQLExtendedFetch option not supported, FetchOrientation: %d", pFetchOrientation ) ); |
| return SQL_ERROR; |
| } |
| |
| // check if number of rows explicitly specified |
| if ( pFetchOffset <= 0 ) |
| { |
| n = ( ( pODBCStmt ) pStmt ) -> ARD . RowArraySize; |
| } |
| |
| // use default rowset size as a fallback |
| if ( n <= 0 ) |
| { |
| n = 1; |
| } |
| |
| return _SQLFetch ( ( pODBCStmt ) pStmt, pFetchOrientation, n, pRowCountPtr, pRowStatusArray ); |
| } |
| |
| |
| // ----------------------------------------------------------------------- |
| // to fetch the specified rowset of data from the result set |
| // ----------------------------------------------------------------------- |
| |
| RETCODE SQL_API SQLFetchScroll ( SQLHSTMT pStatementHandle, |
| SQLSMALLINT pFetchOrientation, |
| SQLINTEGER pFetchOffset ) |
| { |
| __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLFetchScroll called" ) ); |
| __ODBCPOPMSG ( _ODBCPopMsg ( "SQLFetchScroll not implemented" ) ); |
| return SQL_ERROR; |
| } |
| |
| |
| // ----------------------------------------------------------------------- |
| // to send data for a parameter or column to the driver at statement execution time |
| // ----------------------------------------------------------------------- |
| |
| RETCODE SQL_API SQLPutData ( SQLHSTMT pStmt, |
| SQLPOINTER pDataPtr, |
| SQLINTEGER pDataSize ) |
| { |
| __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLPutData called" ) ); |
| __ODBCPOPMSG ( _ODBCPopMsg ( "SQLPutData not implemented" ) ); |
| return SQL_ERROR; |
| } |
| |
| // ----------------------------------------------------------------------- |
| // to iterate through multiple resultsets |
| // ----------------------------------------------------------------------- |
| |
| RETCODE SQL_API SQLMoreResults ( HSTMT pStmt ) |
| { |
| pODBCStmt odbcStmt = ( pODBCStmt )pStmt; |
| |
| __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLMoreResults called, stmt handle %d with start-row %d and end-row %d, next handle is %d", |
| (long) odbcStmt, odbcStmt->CurRowsetStartRowPos, odbcStmt->CurRowsetEndRowPos, (long) odbcStmt -> Next) ); |
| |
| // check if stmt been released already |
| if (( ! odbcStmt -> Prepared) || ( ! odbcStmt -> Next )) |
| { |
| return SQL_NO_DATA; |
| } |
| else if ( odbcStmt -> IRD . RowDesc != NULL ) |
| { |
| // ------- THIS CASE SHOULD NOT OCCUR ---------- |
| // check if position is currently unknown |
| if ( odbcStmt -> CurRowsetStartRow == NULL && odbcStmt -> CurRowsetStartRowPos == 0 ) |
| { |
| // position to first row ( both the pointers ) |
| if ( GetIfExist ( odbcStmt -> IRD . RowDesc -> results, 1 ) ) |
| { |
| return SQL_SUCCESS; |
| } |
| } |
| // ----------------------------------------------- |
| // position to next row if already position is known |
| else if ( odbcStmt -> CurRowsetEndRow != NULL ) |
| { |
| // position to next row |
| if ( GetIfExist ( odbcStmt -> IRD . RowDesc -> results, odbcStmt -> CurRowsetEndRowPos ) ) |
| { |
| return SQL_SUCCESS; |
| } |
| } |
| return SQL_NO_DATA; |
| } |
| return SQL_ERROR; |
| } |
| |
| // ----------------------------------------------------------------------- |
| // to get a driver specific version of specified sql statement |
| // ----------------------------------------------------------------------- |
| |
| RETCODE SQL_API SQLNativeSql ( SQLHDBC pConn, |
| SQLCHAR* pInStmtText, |
| SQLINTEGER pInStmtTextLen, |
| SQLCHAR* pOutStmtText, |
| SQLINTEGER pOutStmtTextLen, |
| SQLINTEGER* pOutStmtTextLenPtr ) |
| { |
| __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLNativeSql called" ) ); |
| __ODBCPOPMSG ( _ODBCPopMsg ( "SQLNativeSql not implemented" ) ); |
| return SQL_ERROR; |
| } |
| |
| |
| // ----------------------------------------------------------------------- |
| // to convert and transfer col data for application |
| // ----------------------------------------------------------------------- |
| |
| //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 ); |
| } |
| } |
| else 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; |
| } |
| |
| |
| // ----------------------------------------------------------------------- |
| // to get the specified column data from |
| // ----------------------------------------------------------------------- |
| |
| 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 ( SQLLEN) ) ); |
| } |
| |
| // 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; |
| } |
| |
| |
| // ----------------------------------------------------------------------- |
| // to move to the next row with relevant checks |
| // ----------------------------------------------------------------------- |
| |
| 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; |
| } |
| } |
| |
| SQLRowContent* GetIfExist ( std::vector <SQLRowContent*>& container, int index ) |
| { |
| index = index - 1; //sql cardinals start at 1 |
| |
| if ( index >= ( int ) container . size () ) |
| { |
| return NULL; |
| } |
| |
| else |
| { |
| return container . at ( index ); |
| } |
| } |
| |
| // ----------------------------------------------------------------------- |
| // to set the initial row positions for a fetch |
| // ----------------------------------------------------------------------- |
| |
| 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; |
| } |
| } |
| |
| |
| // ----------------------------------------------------------------------- |
| // to return the next row from the resultset |
| // ----------------------------------------------------------------------- |
| |
| RETCODE SQL_API _SQLFetch ( pODBCStmt pStmt, |
| Word pFetchOrientation, |
| Long pFetchOffset, //ARD.RowArraySize |
| ULong* pRowCountPtr, //IRD.RowsProcessedPtr |
| UWord* pRowStatusArray ) |
| { //ArrayStatusPtr |
| // note |
| // fetchoffset is treated as the number of rows to fetch |
| bool flgNoData; |
| Long i, n1, n2; |
| RETCODE s; |
| SQLRowContent* rowdata; |
| SQLResponse* rowdesc; |
| pODBCARD ard; |
| pARDItem ardcol; |
| |
| // CALLER SAFE |
| |
| // caller safe for row fetched |
| if ( pRowCountPtr ) |
| { |
| *pRowCountPtr = 0; |
| } |
| |
| // caller safe for each row status |
| if ( pRowStatusArray ) |
| for ( i = 0; i < pFetchOffset; i ++ ) |
| { |
| pRowStatusArray[i] = SQL_ROW_NOROW; |
| } |
| |
| // RESET POSITION OR SET INITIAL POSITIONS |
| |
| // postions the row counter for fetch start |
| if ( ( s = _SQLResetRowPos ( ( pODBCStmt ) pStmt ) ) != SQL_SUCCESS ) |
| { |
| return s; |
| } |
| |
| // COLLECT INFO to START |
| // get the row desc - ird |
| rowdesc = ( ( pODBCStmt ) pStmt ) -> IRD . RowDesc . get (); |
| // get the row desc - ard |
| ard = & ( ( ( pODBCStmt ) pStmt ) -> ARD ); |
| |
| // MAIN LOOP to fetch rowset number of rows |
| // loop to fetch the rows |
| for ( i = 0 , n1 = 0 , n2 = 0 , flgNoData = FALSE; i < pFetchOffset && flgNoData == FALSE; i ++ ) |
| { |
| __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "Get One Row:" ) ); |
| |
| // check if first row or not |
| if ( i != 0 ) |
| { |
| // move to next row if not first time |
| switch ( _SQLFetchMoveNext ( pStmt ) ) |
| { |
| case SQL_NO_DATA : |
| flgNoData = TRUE; // can continue |
| continue; |
| |
| case SQL_ERROR : |
| return SQL_ERROR; // not continuing |
| |
| default : // case SQL_SUCCESS: |
| break; |
| } |
| } |
| |
| // get the current row data |
| rowdata = pStmt -> CurRowsetEndRow; |
| |
| // LOOP to fetch cols of one row |
| |
| // loop to put data in all bound cols |
| for ( ardcol = ard -> BindCols; ardcol != NULL; ardcol = ardcol -> Next ) |
| { |
| __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "Get one column:" ) ); |
| // get data using _SQLFetchCol |
| s = _SQLFetchCol ( pStmt, ardcol, rowdesc, rowdata ); |
| |
| // update row status |
| switch ( s ) |
| { |
| case SQL_SUCCESS : |
| if ( pRowStatusArray && pRowStatusArray[i] == SQL_ROW_NOROW ) |
| { |
| pRowStatusArray[i] = SQL_ROW_SUCCESS_WITH_INFO; |
| } |
| |
| break; |
| |
| case SQL_SUCCESS_WITH_INFO : |
| ++ n1; // rows with info |
| |
| if ( pRowStatusArray ) |
| { |
| pRowStatusArray[i - 1] = SQL_ROW_SUCCESS_WITH_INFO; |
| } |
| |
| break; |
| |
| default : |
| ++ n2; // no. of rows with error |
| |
| if ( pRowStatusArray ) |
| { |
| pRowStatusArray[i - 1] = SQL_ROW_ERROR; |
| } |
| } |
| } |
| |
| // update the number of rows fetched |
| if ( pRowCountPtr ) |
| { |
| *pRowCountPtr = i + 1; |
| } |
| } |
| |
| // check if no data |
| if ( flgNoData == TRUE && i <= 0 ) |
| { |
| return SQL_NO_DATA; |
| } |
| |
| // check if all error |
| else if ( i > 0 && n2 == i ) |
| { |
| return SQL_ERROR; |
| } |
| |
| // check if any success with info |
| else if ( i > 0 && n1 > 0 ) |
| { |
| return SQL_SUCCESS_WITH_INFO; |
| } |
| |
| // all success |
| else |
| { |
| return SQL_SUCCESS; |
| } |
| } |
| |
| |
| // ----------------------------------------------------------------------- |
| // to retrieve long data for a single column in the result set using multiple calls |
| // ----------------------------------------------------------------------- |
| |
| RETCODE SQL_API SQLGetData ( SQLHSTMT pStmt, |
| SQLUSMALLINT pColNum, |
| SQLSMALLINT pDataType, |
| SQLPOINTER pDataPtr, |
| SQLLEN pDataSize, |
| SQLLEN* pDataSizePtr ) |
| { |
| __CHK_HANDLE ( pStmt, SQL_HANDLE_STMT, SQL_ERROR ); |
| |
| __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLGetData called, ColNum: %d, TgtType: %d, ValuePtr: %d, Capacity: %d", |
| pColNum, pDataType, pDataPtr, pDataSize ) ); |
| |
| if ( pColNum < 1 || pColNum > ( ( pODBCStmt )pStmt ) -> IRD . DescCount ) |
| { |
| _SQLPutDiagRow ( SQL_HANDLE_STMT, pStmt, "", "07009", -1, "Dynamic SQL error-invalid descriptor index" ); |
| return SQL_ERROR; |
| } |
| |
| pODBCARD ard; |
| pARDItem ardcol; |
| SQLRowContent* rowdata; |
| SQLResponse* rowdesc; |
| SQLSMALLINT tgtPDataType; |
| |
| ard = & ( ( ( pODBCStmt ) pStmt ) -> ARD ); |
| rowdata = ( ( pODBCStmt )pStmt ) -> CurRowsetEndRow; |
| rowdesc = ( ( pODBCStmt ) pStmt ) -> IRD . RowDesc . get (); |
| |
| if ( rowdata == NULL ) |
| { |
| _SQLPutDiagRow ( SQL_HANDLE_STMT, pStmt, "", "HY010", -1, "CLI-specific condition-function sequence error" ); |
| return SQL_ERROR; |
| } |
| |
| ardcol = _SQLGetARDItem ( ard, pColNum ); |
| if ( ardcol != NULL ) |
| { |
| /* It's illegal to call SQLGetdata for a "bound" Column */ |
| _SQLPutDiagRow ( SQL_HANDLE_STMT, pStmt, "", "07009", -1, "dynamic SQL error-invalid descriptor index" ); |
| return SQL_ERROR; |
| } |
| |
| // convert C data type to SQL data type |
| switch ( pDataType ) |
| { |
| case SQL_C_SBIGINT : |
| case SQL_C_SLONG : |
| case SQL_C_SSHORT : |
| case SQL_C_STINYINT : |
| tgtPDataType = pDataType - SQL_SIGNED_OFFSET; |
| break; |
| case SQL_C_ULONG : |
| case SQL_C_USHORT : |
| case SQL_C_UTINYINT : |
| case SQL_C_UBIGINT : |
| tgtPDataType = pDataType - SQL_UNSIGNED_OFFSET; |
| break; |
| default : |
| tgtPDataType = pDataType; |
| break; |
| } |
| |
| // manually bind column information to output |
| RETCODE ret = SQLBindCol ( pStmt, pColNum, tgtPDataType, pDataPtr, pDataSize, pDataSizePtr ); |
| if ( ret != SQL_SUCCESS ) |
| { |
| return ret; |
| } |
| |
| ardcol = _SQLGetARDItem ( ard, pColNum ); |
| ret = _SQLFetchCol ( ( pODBCStmt )pStmt, ardcol, rowdesc, rowdata ); |
| if ( ret != SQL_SUCCESS ) |
| { |
| return ret; |
| } |
| _SQLDetachARDItem ( ard, ardcol ); |
| |
| /*unique_ptr<char[]> temp2 ( wchar2char ( ( wchar_t* ) pDataPtr ) ); |
| __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "Data1: %s", temp2.get())); |
| __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "Size1: %d", *pDataSizePtr));*/ |
| |
| return SQL_SUCCESS; |
| } |
| |