Ejemplo n.º 1
0
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;
	}
}
Ejemplo n.º 2
0
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));
}