예제 #1
0
STDMETHODIMP CCUBRIDRowset::InsertRow(HCHAPTER hReserved, HACCESSOR hAccessor, void *pData, HROW *phRow)
{
	ATLTRACE(atlTraceDBProvider, 2, "CCUBRIDRowset::InsertRow\n");

	if(phRow) *phRow = NULL;

	if(phRow)
		CHECK_CANHOLDROWS(__uuidof(IRowsetChange));

	ClearError();
	if(m_nStatus==1) return RaiseError(E_UNEXPECTED, 1, __uuidof(IRowsetChange), L"This object is in a zombie state");

	CHECK_UPDATABILITY(DBPROPVAL_UP_INSERT);

	// Determine if we're in immediate or deferred mode
	bool bDeferred = IsDeferred(this);

	// 바인딩 정보를 구함
	ATLBINDINGS *pBinding;
	{
		bool bFound = m_rgBindings.Lookup((ULONG)hAccessor, pBinding);
		if(!bFound || pBinding==NULL)
			return RaiseError(DB_E_BADACCESSORHANDLE, 0, __uuidof(IRowsetChange));
		if(!(pBinding->dwAccessorFlags & DBACCESSOR_ROWDATA))
			return RaiseError(DB_E_BADACCESSORTYPE, 0, __uuidof(IRowsetChange)); // row accessor 가 아니다.
		if(pData==NULL && pBinding->cBindings!=0)
			return RaiseError(E_INVALIDARG, 0, __uuidof(IRowsetChange));
	}

	CCUBRIDRowsetRow *pRow;
	CCUBRIDRowsetRow::KeyType key;
	{	// 새 row를 위한 Row class를 생성한다.
		DBORDINAL cCols;
		ATLCOLUMNINFO *pColInfo = GetColumnInfo(this, &cCols);
		ATLTRY(pRow = new CCUBRIDRowsetRow(m_uCodepage, -1, cCols, pColInfo, m_spConvert, m_Columns.m_defaultVal));
		if(pRow==NULL) return RaiseError(E_OUTOFMEMORY, 0, __uuidof(IRowsetChange));

		// row handle에 추가
		key = (CCUBRIDRowsetRow::KeyType)m_rgRowData.GetCount();
		if (key == 0) key++;
		
		while(m_rgRowHandles.Lookup(key)) key++;
		m_rgRowHandles.SetAt(key, pRow);

		// rowset에 데이터가 하나 늘었다.
//		m_rgRowData.SetCount(m_rgRowData.GetCount()+1);
	}

	HRESULT hrRead = pRow->ReadData(pBinding, pData, m_uCodepage);
	if(FAILED(hrRead))
	{
//		m_rgRowData.SetCount(m_rgRowData.GetCount()-1);
		m_rgRowHandles.RemoveKey(key);
		delete pRow;
		return hrRead;
	}
	pRow->m_status = DBPENDINGSTATUS_NEW;

	if(phRow)
	{	// handle을 반환할 때는 참조 카운트를 하나 증가시킨다.
		pRow->AddRefRow();
		*phRow = (HROW)key;
	}

//	m_rgBookmarks.Add(pRow->m_iRowset+1);

	if(!bDeferred)
	{	// 변화를 지금 적용
		int hConn = GetSessionPtr()->GetConnection();
		UINT uCodepage = GetSessionPtr()->GetCodepage();
		HRESULT hr = pRow->WriteData(hConn, uCodepage, GetRequestHandle(), m_strTableName);
		if(FAILED(hr))
		{
			pRow->ReleaseRow();
			if (phRow != NULL)
				*phRow = NULL;
			return hr;
		}

		pRow->m_status = 0; // or UNCHANGED?
		if(pRow->m_dwRef==0)
		{
			m_rgRowHandles.RemoveKey(key);
			delete pRow;
		}

		DoCommit(this); // commit

		//// deferred update 모드였다가 immediate update 모드로 바뀌지는 않으므로
		//// 다른 NEW 상태의 row는 없다. 즉 m_iRowset을 변경해야 할 row는 없다.

		//// 새로 추가된 Row의 OID를 읽어들인다.
		//pRow->ReadData(GetRequestHandle(), true);
	}

	return hrRead;
}
예제 #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));
}
예제 #3
0
STDMETHODIMP CCUBRIDRowset::SetData(HROW hRow, HACCESSOR hAccessor, void *pData)
{
	ATLTRACE(atlTraceDBProvider, 2, "CCUBRIDRowset::SetData\n");

	ClearError();
	if(m_nStatus==1) return RaiseError(E_UNEXPECTED, 1, __uuidof(IRowsetChange), L"This object is in a zombie state");

	// cci_cursor_update를 이용하면 질의를 재실행할 때까지 SetData를 실행할 수 없다.
	// SQL and cci_execute를 이용하면 가능하다.
	CHECK_RESTART(__uuidof(IRowsetChange));

	CHECK_UPDATABILITY(DBPROPVAL_UP_CHANGE);

	// Determine if we're in immediate or deferred mode
	bool bDeferred = IsDeferred(this);

	// Attempt to locate the row in our map
	CCUBRIDRowsetRow *pRow;
	{
		bool bFound = m_rgRowHandles.Lookup((ULONG)hRow, pRow);
		if(!bFound || pRow==NULL)
			return RaiseError(DB_E_BADROWHANDLE, 0, __uuidof(IRowsetChange));
	}

	ATLASSERT( pRow->m_iRowset==(ULONG)-1 || pRow->m_iRowset<m_rgRowData.GetCount() );

	// 이미 지워진 row
	if(pRow->m_status==DBPENDINGSTATUS_DELETED || pRow->m_status==DBPENDINGSTATUS_INVALIDROW)
		return RaiseError(DB_E_DELETEDROW, 0, __uuidof(IRowsetChange));

	// 새로 삽입되었고 Storage로 전송됐다.
	if(pRow->m_iRowset==(ULONG)-1 && pRow->m_status!=DBPENDINGSTATUS_NEW)
		return DB_E_NEWLYINSERTED;

	// 바인딩 정보를 구함
	ATLBINDINGS *pBinding;
	{
		bool bFound = m_rgBindings.Lookup((ULONG)hAccessor, pBinding);
		if(!bFound || pBinding==NULL)
			return RaiseError(DB_E_BADACCESSORHANDLE, 0, __uuidof(IRowsetChange));
		if(!(pBinding->dwAccessorFlags & DBACCESSOR_ROWDATA))
			return RaiseError(DB_E_BADACCESSORTYPE, 0, __uuidof(IRowsetChange)); // row accessor 가 아니다.
		if(pData==NULL && pBinding->cBindings!=0)
			return RaiseError(E_INVALIDARG, 0, __uuidof(IRowsetChange));
	}

	HRESULT hr = pRow->ReadData(pBinding, pData, m_uCodepage);
	if(FAILED(hr)) return hr;
	// 새로 삽입된 row는 변경이 있어도 그냥 새로 삽입된 것으로 표시
	if(pRow->m_status!=DBPENDINGSTATUS_NEW)
		pRow->m_status = DBPENDINGSTATUS_CHANGED;

	if(!bDeferred)
	{	// 변화를 지금 적용
		int hConn = GetSessionPtr()->GetConnection();
		UINT uCodepage = GetSessionPtr()->GetCodepage();
		hr = pRow->WriteData(hConn, uCodepage, GetRequestHandle(), m_strTableName);

		if (hr == DB_E_INTEGRITYVIOLATION)
			return RaiseError(DB_E_INTEGRITYVIOLATION, 0, __uuidof(IRowsetChange));

		if(FAILED(hr)) return RaiseError(DB_E_ERRORSOCCURRED, 0, __uuidof(IRowsetChange));
		
		pRow->m_status = 0; // or UNCHANGED?
		DoCommit(this); // commit
	}

	return hr; // S_OK or DB_S_ERRORSOCCURRED
}
예제 #4
0
HRESULT CMultipleResult::SetSite(IUnknown *pUnkSite)
{
	HRESULT hr = IObjectWithSiteImpl<CMultipleResult>::SetSite(pUnkSite);
	GetSessionPtr()->RegisterTxnCallback(this, true);
	return hr;
}