/** * @brief Creates simple tile group for testing purposes. * @param backend Backend for tile group to use. * @param tuple_count Tuple capacity of this tile group. * * Tile group has two tiles, and each of them has two columns. * The first two columns have INTEGER types, the last two have TINYINT * and VARCHAR. * * IMPORTANT: If you modify this function, it is your responsibility to * fix any affected test cases. Test cases may be depending * on things like the specific number of tiles in this group. * * @return Pointer to tile group. */ storage::TileGroup *ExecutorTestsUtil::CreateTileGroup(int tuple_count) { std::vector<catalog::Column> columns; std::vector<catalog::Schema> schemas; columns.push_back(GetColumnInfo(0)); columns.push_back(GetColumnInfo(1)); catalog::Schema schema1(columns); schemas.push_back(schema1); columns.clear(); columns.push_back(GetColumnInfo(2)); columns.push_back(GetColumnInfo(3)); catalog::Schema schema2(columns); schemas.push_back(schema2); std::map<oid_t, std::pair<oid_t, oid_t>> column_map; column_map[0] = std::make_pair(0, 0); column_map[1] = std::make_pair(0, 1); column_map[2] = std::make_pair(1, 0); column_map[3] = std::make_pair(1, 1); storage::TileGroup *tile_group = storage::TileGroupFactory::GetTileGroup( INVALID_OID, INVALID_OID, TestingHarness::GetInstance().GetNextTileGroupId(), nullptr, schemas, column_map, tuple_count); return tile_group; }
storage::DataTable *ExecutorTestsUtil::CreateTable( int tuples_per_tilegroup_count, bool indexes) { catalog::Schema *table_schema = new catalog::Schema( {GetColumnInfo(0), GetColumnInfo(1), GetColumnInfo(2), GetColumnInfo(3)}); std::string table_name("TEST_TABLE"); // Create table. bool own_schema = true; bool adapt_table = false; storage::DataTable *table = storage::TableFactory::GetDataTable( INVALID_OID, INVALID_OID, table_schema, table_name, tuples_per_tilegroup_count, own_schema, adapt_table); if (indexes == true) { // PRIMARY INDEX std::vector<oid_t> key_attrs; auto tuple_schema = table->GetSchema(); catalog::Schema *key_schema; index::IndexMetadata *index_metadata; bool unique; key_attrs = {0}; key_schema = catalog::Schema::CopySchema(tuple_schema, key_attrs); key_schema->SetIndexedColumns(key_attrs); unique = true; index_metadata = new index::IndexMetadata( "primary_btree_index", 123, INDEX_TYPE_BTREE, INDEX_CONSTRAINT_TYPE_PRIMARY_KEY, tuple_schema, key_schema, unique); index::Index *pkey_index = index::IndexFactory::GetInstance(index_metadata); table->AddIndex(pkey_index); // SECONDARY INDEX key_attrs = {0, 1}; key_schema = catalog::Schema::CopySchema(tuple_schema, key_attrs); key_schema->SetIndexedColumns(key_attrs); unique = false; index_metadata = new index::IndexMetadata( "secondary_btree_index", 124, INDEX_TYPE_BTREE, INDEX_CONSTRAINT_TYPE_DEFAULT, tuple_schema, key_schema, unique); index::Index *sec_index = index::IndexFactory::GetInstance(index_metadata); table->AddIndex(sec_index); } return table; }
//----------------------------------------------------------------------------- // Purpose: // Input : *pWnd - //----------------------------------------------------------------------------- void CMySplitterWnd::ToggleMax(CWnd *pWnd) { int ir, ic; if(!pMaxPrev) { int dummy; // save current info GetRowInfo(0, sizePrev[1][0], dummy); GetRowInfo(1, sizePrev[1][1], dummy); GetColumnInfo(0, sizePrev[0][0], dummy); GetColumnInfo(1, sizePrev[0][1], dummy); } if(pWnd != pMaxPrev) { // maximize this one int iRow, iCol; CRect r; GetClientRect(r); VERIFY(IsChildPane(pWnd, &iRow, &iCol)); for(ir = 0; ir < 2; ir++) { for(ic = 0; ic < 2; ic++) { SetRowInfo(ir, 0, 0); SetColumnInfo(ic, 0, 0); } } SetRowInfo(iRow, r.Height(), 5); SetColumnInfo(iCol, r.Width(), 5); pMaxPrev = pWnd; } else { // restore saved info SetRowInfo(0, sizePrev[1][0], 0); SetRowInfo(1, sizePrev[1][1], 0); SetColumnInfo(0, sizePrev[0][0], 0); SetColumnInfo(1, sizePrev[0][1], 0); pMaxPrev = NULL; } RecalcLayout(); }
// IColumnProvider members STDMETHODIMP CShellExt::GetColumnInfo(DWORD dwIndex, SHCOLUMNINFO *psci) { PreserveChdir preserveChdir; if (dwIndex > 0) // TODO: keep for now to be able to hide unimplemented columns return S_FALSE; ShellCache::CacheType cachetype = g_ShellCache.GetCacheType(); if (cachetype == ShellCache::none) return S_FALSE; LoadLangDll(); switch (dwIndex) { case 0: // Git Status GetColumnInfo(dwIndex, psci, 15, IDS_COLTITLESTATUS, IDS_COLDESCSTATUS); break; case 1: // Git Revision GetColumnInfo(dwIndex, psci, 40, IDS_COLTITLEREV, IDS_COLDESCREV); break; case 2: // Git Url GetColumnInfo(dwIndex, psci, 30, IDS_COLTITLEURL, IDS_COLDESCURL); break; case 3: // Git Short Url GetColumnInfo(dwIndex, psci, 30, IDS_COLTITLESHORTURL, IDS_COLDESCSHORTURL); break; case 4: // Author and Git Author psci->scid.fmtid = FMTID_SummaryInformation; // predefined FMTID psci->scid.pid = PIDSI_AUTHOR; // Predefined - author psci->vt = VT_LPSTR; // We'll return the data as a string psci->fmt = LVCFMT_LEFT; // Text will be left-aligned in the column psci->csFlags = SHCOLSTATE_TYPE_STR; // Data should be sorted as strings psci->cChars = 32; // Default col width in chars MAKESTRING(IDS_COLTITLEAUTHOR); lstrcpynW(psci->wszTitle, stringtablebuffer, MAX_COLUMN_NAME_LEN); MAKESTRING(IDS_COLDESCAUTHOR); lstrcpynW(psci->wszDescription, stringtablebuffer, MAX_COLUMN_DESC_LEN); break; case 5: // SVN eol-style GetColumnInfo(dwIndex, psci, 30, IDS_COLTITLEEOLSTYLE, IDS_COLDESCEOLSTYLE); break; default: return S_FALSE; } return S_OK; }
ValueMap Sql::GetRowMap() const { ValueMap m; int n = GetColumns(); for(int i = 0; i < n; i++) m.Add(GetColumnInfo(i).name, (*this)[i]); return m; }
void CTabSplitterWnd::SaveSize() { #ifdef _DEBUG if (m_strSection == szSplitterSection) TRACE0("Warning: SetSection has not been called in IMSplitterWnd!\n"); #endif GetColumnInfo(0, m_cxCur, m_cxMin); if (m_cxCur) afxGetApp()->WriteProfileInt(m_strSection, szPaneWidthCurrent, m_cxCur); if (m_cxMin) afxGetApp()->WriteProfileInt(m_strSection, szPaneWidthMinimum, m_cxMin); GetRowInfo(0, m_cyCur, m_cyMin); if (m_cyCur) afxGetApp()->WriteProfileInt(m_strSection, szPaneHeightCurrent, m_cyCur); if (m_cyMin) afxGetApp()->WriteProfileInt(m_strSection, szPaneHeightMinimum, m_cyMin); }
TableProperties::TableProperties(BString tableName) : fTableName(tableName), fColumns() { GetColumnInfo(); GetIndexList(); //The column types returned by SQLite could be anything; since it's typeless, //it places no restriction on what the column types are. Thus, we'll try to //convert the column types returned by SQLite into one of the predefined types //used by BeAccessible (which currently are AutoNumber, Number, DateTime, Boolean, //and Text. ConvertDataTypes(); //Create a mapping between column names and their column properties structure for(int i = 0; i < fColumns.CountItems(); i++) { ColumnProperties* col = static_cast<ColumnProperties*>(fColumns.ItemAt(i)); fColumnMapping.fMapping[col->Name()] = col; } //Get the table_preferences XML for the given table GetTableXML(); }
void LogicalTile::MaterializeColumnAtATime( const std::unordered_map<oid_t, oid_t> &old_to_new_cols, const std::unordered_map<storage::Tile *, std::vector<oid_t>> &tile_to_cols, storage::Tile *dest_tile) { /////////////////////////// // EACH PHYSICAL TILE /////////////////////////// // Copy over all data from each base tile. for (const auto &kv : tile_to_cols) { const std::vector<oid_t> &old_column_ids = kv.second; /////////////////////////// // EACH COLUMN /////////////////////////// // Go over each column in given base physical tile for (oid_t old_col_id : old_column_ids) { auto &column_info = GetColumnInfo(old_col_id); // Amortize schema lookups once per column storage::Tile *old_tile = column_info.base_tile.get(); auto old_schema = old_tile->GetSchema(); // Get old column information oid_t old_column_id = column_info.origin_column_id; const size_t old_column_offset = old_schema->GetOffset(old_column_id); const ValueType old_column_type = old_schema->GetType(old_column_id); const bool old_is_inlined = old_schema->IsInlined(old_column_id); // Old to new column mapping auto it = old_to_new_cols.find(old_col_id); assert(it != old_to_new_cols.end()); // Get new column information oid_t new_column_id = it->second; auto new_schema = dest_tile->GetSchema(); const size_t new_column_offset = new_schema->GetOffset(new_column_id); const bool new_is_inlined = new_schema->IsInlined(new_column_id); const size_t new_column_length = new_schema->GetAppropriateLength(new_column_id); // Get the position list auto &column_position_list = GetPositionList(column_info.position_list_idx); oid_t new_tuple_id = 0; // Copy all values in the column to the physical tile // This uses fast getter and setter functions /////////////////////////// // EACH TUPLE /////////////////////////// for (oid_t old_tuple_id : *this) { oid_t base_tuple_id = column_position_list[old_tuple_id]; auto value = old_tile->GetValueFast(base_tuple_id, old_column_offset, old_column_type, old_is_inlined); LOG_TRACE("Old Tuple : %u Column : %u ", old_tuple_id, old_col_id); LOG_TRACE("New Tuple : %u Column : %u ", new_tuple_id, new_column_id); dest_tile->SetValueFast(value, new_tuple_id, new_column_offset, new_is_inlined, new_column_length); // Go to next tuple new_tuple_id++; } } } }
storage::DataTable *ConstraintsTestsUtil::CreateTable( int tuples_per_tilegroup_count, bool indexes) { catalog::Schema *table_schema = new catalog::Schema( {GetColumnInfo(0), GetColumnInfo(1), GetColumnInfo(2), GetColumnInfo(3)}); std::string table_name("TEST_TABLE"); // Create table. bool own_schema = true; bool adapt_table = false; storage::DataTable *table = storage::TableFactory::GetDataTable( INVALID_OID, INVALID_OID, table_schema, table_name, tuples_per_tilegroup_count, own_schema, adapt_table); if (indexes == true) { // PRIMARY INDEX std::vector<oid_t> key_attrs; auto tuple_schema = table->GetSchema(); catalog::Schema *key_schema; index::IndexMetadata *index_metadata; bool unique; key_attrs = {0}; key_schema = catalog::Schema::CopySchema(tuple_schema, key_attrs); key_schema->SetIndexedColumns(key_attrs); unique = true; index_metadata = new index::IndexMetadata( "primary_btree_index", 123, table->GetOid(), table->GetDatabaseOid(), IndexType::BWTREE, IndexConstraintType::PRIMARY_KEY, tuple_schema, key_schema, key_attrs, unique); std::shared_ptr<index::Index> pkey_index( index::IndexFactory::GetIndex(index_metadata)); table->AddIndex(pkey_index); // SECONDARY INDEX key_attrs = {0, 1}; key_schema = catalog::Schema::CopySchema(tuple_schema, key_attrs); key_schema->SetIndexedColumns(key_attrs); unique = false; index_metadata = new index::IndexMetadata( "secondary_btree_index", 124, table->GetOid(), table->GetDatabaseOid(), IndexType::BWTREE, IndexConstraintType::DEFAULT, tuple_schema, key_schema, key_attrs, unique); std::shared_ptr<index::Index> sec_index( index::IndexFactory::GetIndex(index_metadata)); table->AddIndex(sec_index); // SECONDARY INDEX - UNIQUE INDEX key_attrs = {3}; key_schema = catalog::Schema::CopySchema(tuple_schema, key_attrs); key_schema->SetIndexedColumns(key_attrs); unique = false; index_metadata = new index::IndexMetadata( "unique_btree_index", 125, table->GetOid(), table->GetDatabaseOid(), IndexType::BWTREE, IndexConstraintType::UNIQUE, tuple_schema, key_schema, key_attrs, unique); std::shared_ptr<index::Index> unique_index( index::IndexFactory::GetIndex(index_metadata)); table->AddIndex(unique_index); } return table; }
STDMETHODIMP CCUBRIDRowset::Update(HCHAPTER hReserved, DBCOUNTITEM cRows, const HROW rghRows[], DBCOUNTITEM *pcRows, HROW **prgRows, DBROWSTATUS **prgRowStatus) { ATLTRACE(atlTraceDBProvider, 2, "CCUBRIDRowset::Update\n"); ClearError(); if(m_nStatus==1) return RaiseError(E_UNEXPECTED, 1, __uuidof(IRowsetUpdate), L"This object is in a zombie state"); CHECK_RESTART(__uuidof(IRowsetUpdate)); DBCOUNTITEM ulRows = 0; // update할 row 수 bool bNotIgnore = true; // prgRows, prgRowStatus를 무시할지 여부를 나타냄 // the following lines are used to fix the two _alloca calls below. Those calls are risky // because we may be allocating huge amounts of data. So instead I'll allocate that data on heap. // But if you use _alloca you don't have to worry about cleaning this memory. So we will use these // temporary variables to allocate memory on heap. As soon as we exit the function, the memory will // be cleaned up, just as if we were using alloca. So now, instead of calling alloca, I'll alloc // memory on heap using the two smnart pointers below, and then assing it to the actual pointers. CHeapPtr<HROW> spTempRows; CHeapPtr<DBROWSTATUS> spTempRowStatus; if(cRows || pcRows) { if(prgRows) *prgRows = NULL; if(prgRowStatus) *prgRowStatus = NULL; } else { bNotIgnore = false; // Don't do status or row arrays } // Check to see how many changes we'll undo if(pcRows) { *pcRows = NULL; if(prgRows==NULL) return E_INVALIDARG; } if(cRows) { if(rghRows==NULL) return E_INVALIDARG; ulRows = cRows; } else ulRows = (DBCOUNTITEM)m_rgRowHandles.GetCount(); int hConn = GetSessionPtr()->GetConnection(); UINT uCodepage = GetSessionPtr()->GetCodepage(); // NULL out pointers { if(prgRows && ulRows && bNotIgnore) { // Make a temporary buffer as we may not fill up everything // in the case where cRows == 0 if(cRows) *prgRows = (HROW*)CoTaskMemAlloc(ulRows * sizeof(HROW)); else { spTempRows.Allocate(ulRows); *prgRows = spTempRows; } if (*prgRows==NULL) return E_OUTOFMEMORY; } if(prgRowStatus && ulRows && bNotIgnore) { if(cRows) *prgRowStatus = (DBROWSTATUS*)CoTaskMemAlloc(ulRows * sizeof(DBROWSTATUS)); else { spTempRowStatus.Allocate(ulRows); *prgRowStatus = spTempRowStatus; } if(*prgRowStatus==NULL) { if(cRows) CoTaskMemFree(*prgRows); *prgRows = NULL; return E_OUTOFMEMORY; } } } bool bSucceeded = false; bool bFailed = false; ULONG ulCount = 0; // update된 row 수 POSITION pos = m_rgRowHandles.GetStartPosition(); for (ULONG ulRow = 0; ulRow < ulRows; ulRow++) { ULONG ulCurrentRow = ulCount; bool bDupRow = false; // 중복된 row ULONG ulAlreadyProcessed = 0; // 중복된 row의 handle의 위치 HROW hRowUpdate = NULL; // 현재 update할 row의 handle { if(cRows) { // row handle이 주어졌음 hRowUpdate = rghRows[ulRow]; for (ULONG ulCheckDup = 0; ulCheckDup < ulRow; ulCheckDup++) { if (hRowUpdate==rghRows[ulCheckDup] || IsSameRow(hRowUpdate, rghRows[ulCheckDup]) == S_OK) { ulAlreadyProcessed = ulCheckDup; bDupRow = true; break; } } } else { // 모든 row에 대해 update //ATLASSERT(ulRow < (ULONG)m_rgRowHandles.GetCount()); // delete된 row가 있으면 성립하지 않는다. ATLASSERT( pos != NULL ); MapClass::CPair* pPair = m_rgRowHandles.GetNext(pos); ATLASSERT( pPair != NULL ); hRowUpdate = pPair->m_key; } } if(prgRows && bNotIgnore) (*prgRows)[ulCurrentRow] = hRowUpdate; if(bDupRow) { // We've already set the row before, just copy status and // continue processing if(prgRowStatus && bNotIgnore) (*prgRowStatus)[ulCurrentRow] = (*prgRowStatus)[ulAlreadyProcessed]; ulCount++; continue; } // Fetch the RowClass and determine if it is valid CCUBRIDRowsetRow *pRow; { bool bFound = m_rgRowHandles.Lookup((ULONG)hRowUpdate, pRow); if (!bFound || pRow == NULL) { if (prgRowStatus && bNotIgnore) (*prgRowStatus)[ulCurrentRow] = DBROWSTATUS_E_INVALID; bFailed = true; ulCount++; continue; } } // If cRows is zero we'll go through all rows fetched. We // shouldn't increment the attempted count for rows that are // not changed if (cRows != 0 || (pRow != NULL && pRow->m_status != 0 && pRow->m_status != DBPENDINGSTATUS_UNCHANGED && pRow->m_status != DBPENDINGSTATUS_INVALIDROW)) ulCount++; else continue; if(cRows==0) pRow->AddRefRow(); switch (pRow->m_status) { case DBPENDINGSTATUS_INVALIDROW: // Row is bad or deleted { if(prgRowStatus && bNotIgnore) (*prgRowStatus)[ulCurrentRow] = DBROWSTATUS_E_DELETED; bFailed = true; } break; case DBPENDINGSTATUS_UNCHANGED: case 0: { // If the row's status is not changed, then just put S_OK // and continue. The spec says we should not transmit the // request to the data source (as nothing would change). if(prgRowStatus && bNotIgnore) (*prgRowStatus)[ulCurrentRow] = DBROWSTATUS_S_OK; bSucceeded = true; } break; default: { DBORDINAL cCols; ATLCOLUMNINFO *pColInfo = GetColumnInfo(this, &cCols); HRESULT hr = pRow->WriteData(hConn, uCodepage, GetRequestHandle(), m_strTableName); if(FAILED(hr)) { DBROWSTATUS stat = DBROWSTATUS_E_FAIL; if(hr==DB_E_INTEGRITYVIOLATION) stat = DBROWSTATUS_E_INTEGRITYVIOLATION; if(prgRowStatus && bNotIgnore) (*prgRowStatus)[ulCurrentRow] = stat; bFailed = true; } else { //// m_iRowset을 적당히 조정한다. //if(pRow->m_status==DBPENDINGSTATUS_NEW) //{ // // NEW인 row는 항상 rowset의 뒤에 몰려있다. // // 그 row 중 가장 작은 m_iRowset이 update 된 row의 m_iRowset이 되면 된다. // CCUBRIDRowsetRow::KeyType key = pRow->m_iRowset; // POSITION pos = m_rgRowHandles.GetStartPosition(); // while(pos) // { // CCUBRIDRowset::MapClass::CPair *pPair = m_rgRowHandles.GetNext(pos); // ATLASSERT(pPair); // CCUBRIDRowsetRow *pCheckRow = pPair->m_value; // if( pCheckRow && pCheckRow->m_iRowset < key ) // { // if(pCheckRow->m_iRowset<pRow->m_iRowset) // pRow->m_iRowset = pCheckRow->m_iRowset; // pCheckRow->m_iRowset++; // } // } // // TODO: 북마크 업데이트가 필요한데 어떻게 해야 할지 모르겠다. // // 새로 추가된 Row의 OID를 읽어들인다. // pRow->ReadData(GetRequestHandle(), true); //} if(pRow->m_status==DBPENDINGSTATUS_DELETED) MakeRowInvalid(this, pRow); else pRow->m_status = DBPENDINGSTATUS_UNCHANGED; if(prgRowStatus && bNotIgnore) (*prgRowStatus)[ulCurrentRow] = DBROWSTATUS_S_OK; bSucceeded = true; // Check if we need to release the row because it's ref was 0 // See the IRowset::ReleaseRows section in the spec for more // information if (pRow->m_dwRef == 0) { pRow->AddRefRow(); // Artifically bump this to remove it if( FAILED( RefRows(1, &hRowUpdate, NULL, NULL, false) ) ) return E_FAIL; } } } break; } } // Set the output for rows undone. if(pcRows) *pcRows = ulCount; if(ulCount==0) { if(prgRows) { CoTaskMemFree(*prgRows); *prgRows = NULL; } if(prgRowStatus) { CoTaskMemFree(*prgRowStatus); *prgRowStatus = NULL; } } else if(cRows==0) { // In the case where cRows == 0, we need to allocate the final // array of data. if(prgRows && bNotIgnore) { HROW *prgRowsTemp = (HROW *)CoTaskMemAlloc(ulCount*sizeof(HROW)); if(prgRowsTemp==NULL) return E_OUTOFMEMORY; memcpy(prgRowsTemp, *prgRows, ulCount*sizeof(HROW)); *prgRows = prgRowsTemp; } if(prgRowStatus && bNotIgnore) { DBROWSTATUS *prgRowStatusTemp = (DBROWSTATUS *)CoTaskMemAlloc(ulCount*sizeof(DBROWSTATUS)); if(prgRowStatusTemp==NULL) { CoTaskMemFree(*prgRows); *prgRows = NULL; return E_OUTOFMEMORY; } memcpy(prgRowStatusTemp, *prgRowStatus, ulCount*sizeof(DBROWSTATUS)); *prgRowStatus = prgRowStatusTemp; } } DoCommit(this); // commit // Send the return value if(!bFailed) return S_OK; else { return bSucceeded ? DB_S_ERRORSOCCURRED : DB_E_ERRORSOCCURRED; } }
STDMETHODIMP CCUBRIDRowset::GetOriginalData(HROW hRow, HACCESSOR hAccessor, void *pData) { ATLTRACE(atlTraceDBProvider, 2, _T("CCUBRIDRowset::GetOriginalData\n")); ClearError(); if(m_nStatus==1) return RaiseError(E_UNEXPECTED, 1, __uuidof(IRowsetUpdate), L"This object is in a zombie state"); CHECK_RESTART(__uuidof(IRowsetUpdate)); // 바인딩 정보를 구함 ATLBINDINGS *pBinding; { bool bFound = m_rgBindings.Lookup((ULONG)hAccessor, pBinding); if(!bFound || pBinding==NULL) return DB_E_BADACCESSORHANDLE; if(!(pBinding->dwAccessorFlags & DBACCESSOR_ROWDATA)) return DB_E_BADACCESSORTYPE; // row accessor 가 아니다. if(pData==NULL && pBinding->cBindings!=0) return E_INVALIDARG; } // Attempt to locate the row in our map CCUBRIDRowsetRow *pRow; { bool bFound = m_rgRowHandles.Lookup((ULONG)hRow, pRow); if(!bFound || pRow==NULL) return DB_E_BADROWHANDLE; } // If the status is DBPENDINGSTATUS_INVALIDROW, the row has been // deleted and the change transmitted to the data source. In // this case, we can't get the original data so return // DB_E_DELETEDROW. if (pRow->m_status == DBPENDINGSTATUS_INVALIDROW) return DB_E_DELETEDROW; // Determine if we have a pending insert. In this case, the // spec says revert to default values, and if defaults, // are not available, then NULLs. if (pRow->m_status == DBPENDINGSTATUS_NEW) { for (ULONG lBind=0; lBind<pBinding->cBindings; lBind++) { DBBINDING* pBindCur = &(pBinding->pBindings[lBind]); // default value가 없으므로 NULL로 set if (pBindCur->dwPart & DBPART_VALUE) *((BYTE *)pData+pBindCur->obValue) = NULL; if (pBindCur->dwPart & DBPART_STATUS) *((DBSTATUS*)((BYTE*)(pData) + pBindCur->obStatus)) = DBSTATUS_S_ISNULL; } return S_OK; } // 새로 삽입된 Row if(pRow->m_iRowset==(ULONG)-1) { return pRow->WriteData(pBinding, pData, 0); } DBORDINAL cCols; ATLCOLUMNINFO *pInfo = GetColumnInfo(this, &cCols); DBROWCOUNT dwBookmark = pRow->m_iRowset+3;//Util::FindBookmark(m_rgBookmarks, (LONG)pRow->m_iRowset+1); // 임시 RowClass를 통해 storage에서 데이터를 읽어온 후, pData로 전송한다. CCUBRIDRowsetRow OrigRow(m_uCodepage, pRow->m_iRowset, cCols, pInfo, m_spConvert, m_Columns.m_defaultVal); OrigRow.ReadData(GetRequestHandle()); return OrigRow.WriteData(pBinding, pData, dwBookmark); }
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; }