HRESULT CCUBRIDRowsetRow::WriteData(ATLBINDINGS *pBinding, void *pData, DBROWCOUNT dwBookmark, CCUBRIDRowset* pRowset) { ATLTRACE(atlTraceDBProvider, 3, "CCUBRIDRowsetRow::WriteData(2)\n"); bool bFailed = false; bool bSucceeded = false; for(DBCOUNTITEM i=0;i<pBinding->cBindings;i++) { DBBINDING *pBindCur = &(pBinding->pBindings[i]); if(pBindCur->iOrdinal==0) { // Bookmark Column DBSTATUS dbStat = DBSTATUS_S_OK; DBLENGTH cbDst = 4; if(pBindCur->dwPart & DBPART_VALUE) { // deferred validation // DBLENGTH는 unsigned이므로 obStatus<obValue는 고려하지 않아도 됨 // DataConvert 함수에서 DBSTATUS_S_TRUNCATED 반환 DBLENGTH cbMaxLen = pBindCur->cbMaxLen; if(pBindCur->dwPart & DBPART_STATUS) { DBLENGTH cbLen = pBindCur->obStatus - pBindCur->obValue; if(cbLen<cbMaxLen) cbMaxLen = cbLen; } if(pBindCur->dwPart & DBPART_LENGTH) { DBLENGTH cbLen = pBindCur->obLength - pBindCur->obValue; if(cbLen<cbMaxLen) cbMaxLen = cbLen; } BYTE *pDstTemp = (BYTE *)pData + pBindCur->obValue; HRESULT hr = m_spConvert->DataConvert(DBTYPE_I4, pBindCur->wType, 4, &cbDst, &dwBookmark, pDstTemp, pBindCur->cbMaxLen, dbStat, &dbStat, pBindCur->bPrecision, pBindCur->bScale, 0); if (FAILED(hr)) return hr; } if(pBindCur->dwPart & DBPART_STATUS) *(DBSTATUS *)((BYTE *)pData + pBindCur->obStatus) = dbStat; if(pBindCur->dwPart & DBPART_LENGTH) *(DBLENGTH *)((BYTE *)pData + pBindCur->obLength) = ( dbStat==DBSTATUS_S_ISNULL ? 0 : cbDst ); continue; } // Non-Bookmark Columns //ISequentialStream 처리 //by risensh1ne if (pBindCur->pObject) { //Storage interface중 ISequentialStream만을 지원 if (pBindCur->pObject->iid != IID_ISequentialStream) return E_NOINTERFACE; CComPolyObject<CCUBRIDStream>* pObjStream; HRESULT hr = CComPolyObject<CCUBRIDStream>::CreateInstance(NULL, &pObjStream); if (FAILED(hr)) return hr; // 생성된 COM 객체를 참조해서, 실패시 자동 해제하도록 한다. CComPtr<IUnknown> spUnk; hr = pObjStream->QueryInterface(&spUnk); if(FAILED(hr)) { delete pObjStream; // 참조되지 않았기 때문에 수동으로 지운다. return hr; } int hConn; hr = pRowset->GetSessionPtr()->GetConnectionHandle(&hConn); if (FAILED(hr)) return hr; DBORDINAL cCols; ATLCOLUMNINFO *pInfo = pRowset->GetColumnInfo(pRowset, &cCols); pObjStream->m_contained.Initialize(hConn, this->m_szOID, &pInfo[pBindCur->iOrdinal - 1]); BYTE* temp = (BYTE *)pData + pBindCur->obValue; hr = pObjStream->QueryInterface(IID_ISequentialStream, (void **)temp); if (FAILED(hr)) return E_NOINTERFACE; continue; } ATLCOLUMNINFO *m_pInfoCur; CCUBRIDRowsetRowColumn *pColCur; { // m_pInfo[i].iOrdinal = i+1 if there is no self bookmark // m_pInfo[i].iOrdinal = i if there is a self bookmark if(m_pInfo[0].iOrdinal==0) { m_pInfoCur = &(m_pInfo[pBindCur->iOrdinal]); pColCur = m_rgColumns+pBindCur->iOrdinal; } else { m_pInfoCur = &(m_pInfo[pBindCur->iOrdinal-1]); pColCur = m_rgColumns+pBindCur->iOrdinal-1; } } if(pColCur->m_dwStatus==DBSTATUS_S_OK || pColCur->m_dwStatus==DBSTATUS_S_DEFAULT) { BYTE *pDstTemp = NULL; if(pBindCur->dwPart & DBPART_VALUE) { pDstTemp = (BYTE *)pData + pBindCur->obValue; //memset(pDstTemp, 0, pBindCur->cbMaxLen); } DBSTATUS dbStatus; DBLENGTH cbDataLen; HRESULT hr = pColCur->TransferData(m_spConvert, (int) m_pInfoCur->iOrdinal, pBindCur->wType, pBindCur->bPrecision, pBindCur->bScale, pDstTemp, pBindCur->cbMaxLen, &dbStatus, &cbDataLen); if (FAILED(hr)) return hr; // 고정길이 문자열(SQL의 CHAR, NCHAR)이면 뒤에 공백을 추가한다. // TODO: m_pInfoCur의 길이와 pBindCur의 길이를 비교해 // S_OK와 S_TRUNCATED 결정 if( (m_pInfoCur->wType==DBTYPE_STR || m_pInfoCur->wType==DBTYPE_WSTR) && (m_pInfoCur->dwFlags & DBCOLUMNFLAGS_ISFIXEDLENGTH) && (pBindCur->wType==DBTYPE_STR || pBindCur->wType==DBTYPE_WSTR) ) { DBLENGTH maxsize = m_pInfoCur->ulColumnSize; if(pBindCur->wType==DBTYPE_WSTR) maxsize *= 2; while(cbDataLen<pBindCur->cbMaxLen && cbDataLen<maxsize) { if(pBindCur->wType==DBTYPE_STR) { pDstTemp[cbDataLen] = ' '; cbDataLen++; } else { *(wchar_t *)(pDstTemp+cbDataLen) = L' '; cbDataLen += 2; } } if(pBindCur->wType==DBTYPE_STR) pDstTemp[cbDataLen] = '\0'; else *(wchar_t *)(pDstTemp+cbDataLen) = L'\0'; } if(pBindCur->dwPart & DBPART_STATUS) *(DBSTATUS *)((BYTE *)pData + pBindCur->obStatus) = dbStatus; if(pBindCur->dwPart & DBPART_LENGTH) *(DBLENGTH *)((BYTE *)pData + pBindCur->obLength) = cbDataLen; if(FAILED(hr)) bFailed = true; else bSucceeded = true; } else { if(pBindCur->dwPart & DBPART_STATUS) *(DBSTATUS *)((BYTE *)pData + pBindCur->obStatus) = pColCur->m_dwStatus; bSucceeded = true; } } if(bFailed) { // partially succeeded? return bSucceeded ? DB_S_ERRORSOCCURRED : DB_E_ERRORSOCCURRED; } else { return S_OK; } }
HRESULT CMultipleResult::GetResult(IUnknown *pUnkOuter, DBRESULTFLAG lResultFlag, REFIID riid, DBROWCOUNT *pcRowsAffected, IUnknown **ppRowset) { ATLTRACE2(atlTraceDBProvider, 2, _T("CMultipleResult::GetResult\n")); HRESULT hr = S_OK; CCUBRIDCommand* cmd = NULL; CCUBRIDRowset* pRowset = NULL; int result_count = 0, rc; T_CCI_CUBRID_STMT cmd_type; T_CCI_ERROR error; ClearError(); error.err_msg[0] = 0; //E_INVALIDARG 처리 if (!(lResultFlag == DBRESULTFLAG_DEFAULT || lResultFlag == DBRESULTFLAG_ROWSET || lResultFlag == DBRESULTFLAG_ROW)) { hr = E_INVALIDARG; goto error; } //E_NOINTERFACE 처리 if (lResultFlag == DBRESULTFLAG_ROWSET) { if (riid == IID_IRow) hr = E_NOINTERFACE; } else if (lResultFlag == DBRESULTFLAG_ROW) { if (riid == IID_IRowset) hr = E_NOINTERFACE; } if ( riid == IID_IRowsetUpdate ) hr = E_NOINTERFACE; else if ( riid == IID_IMultipleResults) hr = E_NOINTERFACE; if (hr == E_NOINTERFACE) goto error; if (pUnkOuter && riid != IID_IUnknown) { hr = DB_E_NOAGGREGATION; goto error; } if (pcRowsAffected) *pcRowsAffected = DB_COUNTUNAVAILABLE; //모든 쿼리가 다 수행되었으면 m_qr 해제 후 DB_S_NORESULT 리턴 if (m_resultIndex > m_numQuery) { ATLTRACE2(atlTraceDBProvider, 2, _T("DB_S_NORESULT\n")); cci_query_result_free(m_qr, m_numQuery); m_qr = NULL; if (ppRowset) *ppRowset = NULL; if (pcRowsAffected) *pcRowsAffected = DB_COUNTUNAVAILABLE; return DB_S_NORESULT; } if (m_bInvalidated) { hr = E_UNEXPECTED; goto error; } //Rowset이 열려있는 경우 DB_E_OBJECTOPEN을 리턴 if (m_command->m_cRowsetsOpen > 0) { hr = DB_E_OBJECTOPEN; goto error; } //다음번 결과셋을 가져온다 if (m_resultIndex != 1 && !m_bCommitted) { rc = cci_next_result(m_hReq, &error); if (rc < 0) { hr = E_FAIL; goto error; } } result_count = CCI_QUERY_RESULT_RESULT(m_qr, m_resultIndex); cmd_type = (T_CCI_CUBRID_STMT)CCI_QUERY_RESULT_STMT_TYPE(m_qr, m_resultIndex); //쿼리 인덱스 증가 m_resultIndex++; //CCUBRIDCommand 객체에 대한 레퍼런스를 받아옴 cmd = m_command; if (riid == IID_IRow) { if (ppRowset && (cmd_type==CUBRID_STMT_SELECT || cmd_type==CUBRID_STMT_GET_STATS || cmd_type==CUBRID_STMT_CALL || cmd_type==CUBRID_STMT_EVALUATE)) { CComPolyObject<CCUBRIDRow> *pRow; HRESULT hr = CComPolyObject<CCUBRIDRow>::CreateInstance(pUnkOuter, &pRow); if(FAILED(hr)) goto error; // 생성된 COM 객체를 참조해서, 실패시 자동 해제하도록 한다. CComPtr<IUnknown> spUnk; hr = pRow->QueryInterface(&spUnk); if(FAILED(hr)) { delete pRow; // 참조되지 않았기 때문에 수동으로 지운다. goto error; } //Command object의 IUnknown을 Row의 Site로 설정한다. CComPtr<IUnknown> spOuterUnk; GetCommandPtr()->QueryInterface(__uuidof(IUnknown), (void **)&spOuterUnk); hr = pRow->m_contained.SetSite(spOuterUnk, CCUBRIDRow::Type::FromCommand); if(FAILED(hr)) goto error; hr = pRow->m_contained.Initialize(m_hReq); if (FAILED(hr)) { if (ppRowset) *ppRowset = NULL; if (pcRowsAffected) *pcRowsAffected = DB_COUNTUNAVAILABLE; return RaiseError(hr, 0, __uuidof(IMultipleResults)); } //생성된 Row 객체의 IRow 인터페이스 반환 hr = pRow->QueryInterface(riid, (void **)ppRowset); if(FAILED(hr)) goto error; //if (result_count > 1) // return DB_S_NOTSINGLETON; } else { if (cmd_type == CUBRID_STMT_SELECT) { if (pcRowsAffected) *pcRowsAffected = -1; } else { if (pcRowsAffected) *pcRowsAffected = result_count; } if (m_resultIndex > m_numQuery) //마지막 쿼리인 경우 { GetSessionPtr()->AutoCommit(this); m_hReq = 0; m_bCommitted = true; } if (ppRowset != NULL) *ppRowset = NULL; } } //IID_IRowset이 아닌 경우 Rowset을 생성 //IID_IRow 처럼 다르게 처리해 주어야 하는 경우가 또 있을까? else { if(cmd_type==CUBRID_STMT_SELECT || cmd_type==CUBRID_STMT_GET_STATS || cmd_type==CUBRID_STMT_CALL || cmd_type==CUBRID_STMT_EVALUATE) { if (ppRowset) { if (riid != IID_NULL) { ATLTRACE2(atlTraceDBProvider, 2, _T("CMultipleResult::CreateRowset\n")); //Rowset object 생성 hr = cmd->CreateRowset<CCUBRIDRowset>(pUnkOuter, riid, m_pParams, pcRowsAffected, ppRowset, pRowset); if (FAILED(hr)) goto error; pRowset->InitFromCommand(m_hReq, result_count); } else *ppRowset = NULL; } } else { if (pcRowsAffected) *pcRowsAffected = result_count; //커밋을 하지 않으므로 다음번 쿼리에서 현재 쿼리의 업데이트 내용을 볼 수 없다!! //마지막 쿼리인 경우는 커밋 if (m_resultIndex > m_numQuery && m_numQuery > 1) //질의수가 2개 이상이면서 마지막 질의인 경우 커밋 { GetSessionPtr()->AutoCommit(this); m_hReq = 0; m_bCommitted = true; } *ppRowset = NULL; } } return S_OK; error: if (ppRowset) *ppRowset = NULL; if (pcRowsAffected) *pcRowsAffected = DB_COUNTUNAVAILABLE; m_hReq = 0; if (strlen(error.err_msg) > 0) return RaiseError(hr, 1, __uuidof(IMultipleResults), error.err_msg); else return RaiseError(hr, 0, __uuidof(IMultipleResults)); }