//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //============================================================================= #include "stdafx.h" //#include "sqlaccess.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" namespace GCSDK { // Memory pool for CRecordInfo CThreadSafeClassMemoryPool CRecordInfo::sm_MemPoolRecordInfo( 10, UTLMEMORYPOOL_GROW_FAST ); #ifdef _DEBUG // validation tracking CUtlRBTree CRecordInfo::sm_mapPMemPoolRecordInfo( DefLessFunc( CRecordInfo *) ); CThreadMutex CRecordInfo::sm_mutexMemPoolRecordInfo; #endif //----------------------------------------------------------------------------- // determine if this fieldset is equal to the other one //----------------------------------------------------------------------------- /* static */ bool FieldSet_t::CompareFieldSets( const FieldSet_t& refThis, CRecordInfo* pRecordInfoThis, const FieldSet_t& refOther, CRecordInfo* pRecordInfoOther ) { // same number of columns? int cColumns = refThis.GetCount(); if ( refOther.GetCount() != cColumns ) return false; int cIncludedColumns = refThis.GetIncludedCount(); if ( refOther.GetIncludedCount() != cIncludedColumns ) return false; // do the regular columns first; this is order-dependent for ( int m = 0; m < cColumns; m++ ) { int nThisField = refThis.GetField( m ); const CColumnInfo& refThisColumn = pRecordInfoThis->GetColumnInfo( nThisField ); int nOtherField = refOther.GetField( m ); const CColumnInfo& refOtherColumn = pRecordInfoOther->GetColumnInfo( nOtherField ); if ( refOtherColumn != refThisColumn ) { return false; } } // do the included columns now; order independent for ( int m = 0; m < cIncludedColumns; m++ ) { int nThisField = refThis.GetIncludedField( m ); const CColumnInfo& refThisColumn = pRecordInfoThis->GetColumnInfo( nThisField ); bool bFoundMatch = false; for ( int n = 0; n < cIncludedColumns; n++ ) { int nOtherField = refOther.GetIncludedField( n ); const CColumnInfo& refOtherColumn = pRecordInfoOther->GetColumnInfo( nOtherField ); if ( refOtherColumn == refThisColumn ) { bFoundMatch = true; break; } } if ( !bFoundMatch ) return false; } return true; } //----------------------------------------------------------------------------- // Purpose: Constructor //----------------------------------------------------------------------------- CRecordInfo::CRecordInfo() : m_MapIColumnInfo( 0, 0, CaselessStringLessThan ) { m_rgchName[0] = 0; m_bPreparedForUse = false; m_bAllColumnsAdded = false; m_bHaveChecksum = false; m_bHaveColumnNameIndex = false; m_nHasPrimaryKey = k_EPrimaryKeyTypeNone; m_iPKIndex = -1; m_cubFixedSize = 0; m_nChecksum = 0; m_eSchemaCatalog = k_ESchemaCatalogInvalid; m_nTableID = 0; } //----------------------------------------------------------------------------- // Purpose: Initializes this record info from DS equivalent information //----------------------------------------------------------------------------- void CRecordInfo::InitFromDSSchema( CSchema *pSchema ) { // copy the name over SetName( pSchema->GetPchName() ); // copy each of the fields, preallocating capacity int cFields = pSchema->GetCField(); m_VecColumnInfo.EnsureCapacity( cFields ); for ( int iField = 0; iField < cFields; iField++ ) { Field_t &field = pSchema->GetField( iField ); AddColumn( field.m_rgchSQLName, iField+1, field.m_EType, field.m_cubLength, field.m_nColFlags, field.m_cchMaxLength ); } m_nTableID = pSchema->GetITable(); // copy the list of PK index fields m_iPKIndex = pSchema->GetPKIndex( ); // copy the list of Indexes m_VecIndexes = pSchema->GetIndexes( ); // which schema? m_eSchemaCatalog = pSchema->GetESchemaCatalog(); // copy full-text column list // and the index of the catalog it will create on m_vecFTSFields = pSchema->GetFTSColumns(); m_nFullTextCatalogIndex = pSchema->GetFTSIndexCatalog(); // Copy over the FK data int cFKs = pSchema->GetFKCount(); for ( int i = 0; i < cFKs; ++i ) { FKData_t &fkData = pSchema->GetFKData( i ); AddFK( fkData ); } // prepare for use PrepareForUse( ); } //----------------------------------------------------------------------------- // Purpose: Adds a new column to this record info // Input: pchName - column name // nSQLColumn - column index in SQL to bind to (1-based) // eType - data type of column // cubFixedSize - for fixed-size fields, the size // nColFlags - attributes //----------------------------------------------------------------------------- void CRecordInfo::AddColumn( const char *pchName, int nSQLColumn, EGCSQLType eType, int cubFixedSize, int nColFlags, int cchMaxSize ) { Assert( !m_bPreparedForUse ); if ( m_bPreparedForUse ) return; uint32 unColumn = m_VecColumnInfo.AddToTail(); CColumnInfo &columnInfo = m_VecColumnInfo[unColumn]; columnInfo.Set( pchName, nSQLColumn, eType, cubFixedSize, nColFlags, cchMaxSize ); } //----------------------------------------------------------------------------- // Purpose: Adds a new FK to this record info //----------------------------------------------------------------------------- void CRecordInfo::AddFK( const FKData_t &fkData ) { m_VecFKData.AddToTail( fkData ); } //----------------------------------------------------------------------------- // Purpose: compare function to sort by column name //----------------------------------------------------------------------------- int __cdecl CompareColumnInfo( const CColumnInfo *pColumnInfoLeft, const CColumnInfo *pColumnInfoRight ) { const char *pchLeft = ( (CColumnInfo *) pColumnInfoLeft )->GetName(); const char *pchRight = ( (CColumnInfo *) pColumnInfoRight )->GetName(); Assert( pchLeft && pchLeft[0] ); Assert( pchRight && pchRight[0] ); return Q_stricmp( pchLeft, pchRight ); } //----------------------------------------------------------------------------- // Purpose: compares this record info to another record info //----------------------------------------------------------------------------- bool CRecordInfo::EqualTo( CRecordInfo* pOther ) { int nOurs = GetChecksum(); int nTheirs = pOther->GetChecksum(); // if this much isn't equal, we're no good if (nOurs != nTheirs) return false; if ( !CompareIndexLists( pOther ) ) return false; if ( !CompareFKs( pOther ) ) return false; return CompareFTSIndexLists( pOther ); } //----------------------------------------------------------------------------- // Purpose: format the index list into a string //----------------------------------------------------------------------------- void CRecordInfo::GetIndexFieldList( CFmtStr1024 *pstr, int nIndents ) const { // table name at first pstr->sprintf( "Table %s:\n", this->GetName() ); // for each of the indexes ... for ( int n = 0; n < m_VecIndexes.Count(); n++ ) { const FieldSet_t& fs = m_VecIndexes[n]; // indent enough for ( int x = 0; x < nIndents; x++ ) { pstr->Append( "\t" ); } // show if it is clustered or not pstr->AppendFormat( "Index %d (%s): %sclustered, %sunique {", n, fs.GetIndexName(), fs.IsClustered() ? "" : "non-", fs.IsUnique() ? "" : "non-" ); // then show all the columns for (int m = 0; m < fs.GetCount(); m++ ) { int x = fs.GetField( m ); const char* pstrName = m_VecColumnInfo[x].GetName(); pstr->AppendFormat( "%s %s", ( m == 0 ) ? "" : ",", pstrName ); } // then the included columns, too for ( int m = 0; m < fs.GetIncludedCount(); m++ ) { int x = fs.GetIncludedField( m ); const char* pstrName = m_VecColumnInfo[x].GetName(); pstr->AppendFormat( ", *%s", pstrName ); } pstr->Append( " }\n" ); } return; } //----------------------------------------------------------------------------- // Purpose: Get the number of foreign key constraints defined for the table //----------------------------------------------------------------------------- int CRecordInfo::GetFKCount() { return m_VecFKData.Count(); } //----------------------------------------------------------------------------- // Purpose: Get data for a foreign key by index (valid for 0...GetFKCount()-1) //----------------------------------------------------------------------------- FKData_t &CRecordInfo::GetFKData( int iIndex ) { return m_VecFKData[iIndex]; } //----------------------------------------------------------------------------- // Purpose: format the FK list into a string //----------------------------------------------------------------------------- void CRecordInfo::GetFKListString( CFmtStr1024 *pstr, int nIndents ) { // table name at first pstr->sprintf( "Table %s Foreign Keys: \n", this->GetName() ); if ( m_VecFKData.Count() == 0 ) { // indent enough pstr->AppendIndent( nIndents ); pstr->Append( "No foreign keys for table\n" ); } else { for ( int n = 0; n < m_VecFKData.Count(); n++ ) { // indent enough pstr->AppendIndent( nIndents ); FKData_t &fkData = m_VecFKData[n]; CFmtStr sColumns, sParentColumns; FOR_EACH_VEC( fkData.m_VecColumnRelations, i ) { FKColumnRelation_t &colRelation = fkData.m_VecColumnRelations[i]; if ( i > 0) { sColumns += ","; sParentColumns += ","; } sColumns += colRelation.m_rgchCol; sParentColumns += colRelation.m_rgchParentCol; } pstr->AppendFormat( "CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s(%s) ON DELETE %s ON UPDATE %s\n", fkData.m_rgchName, sColumns.Access(), fkData.m_rgchParentTableName, sParentColumns.Access(), PchNameFromEForeignKeyAction( fkData.m_eOnDeleteAction ), PchNameFromEForeignKeyAction( fkData.m_eOnUpdateAction ) ); } } return; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CRecordInfo::AddFTSFields( CUtlVector< int > &vecFields ) { AssertMsg( m_vecFTSFields.Count() == 0, "Only one FTS index per table" ); FOR_EACH_VEC( vecFields, n ) { int nField = vecFields[n]; m_vecFTSFields.AddToTail( nField ); } return; } //----------------------------------------------------------------------------- // Purpose: compares FK lists in this record with those of another //----------------------------------------------------------------------------- bool CRecordInfo::CompareFKs( CRecordInfo *pOther ) { if ( pOther->m_VecFKData.Count() != m_VecFKData.Count() ) return false; for( int i=0; i < m_VecFKData.Count(); ++i ) { FKData_t &fkDataMine = m_VecFKData[i]; bool bFoundInOther = false; for ( int j=0; j < pOther->m_VecFKData.Count(); ++j ) { FKData_t &fkDataOther = pOther->m_VecFKData[j]; if ( fkDataMine == fkDataOther ) { bFoundInOther = true; break; } } if ( !bFoundInOther ) return false; } return true; } //----------------------------------------------------------------------------- // Purpose: Locate an index by its properties (ignoring the name). // Returns position of index in the index array, or -1 if not found. //----------------------------------------------------------------------------- int CRecordInfo::FindIndex( CRecordInfo *pRec, const FieldSet_t& fieldSet ) { for ( int i = 0; i < m_VecIndexes.Count(); i++ ) { if ( FieldSet_t::CompareFieldSets( m_VecIndexes[i], this, fieldSet, pRec ) ) return i; } // Not found return -1; } //----------------------------------------------------------------------------- // Purpose: Locate an index with the given name. // Returns position of index in the index array, or -1 if not found. //----------------------------------------------------------------------------- int CRecordInfo::FindIndexByName( const char *pszName ) const { for ( int i = 0; i < m_VecIndexes.Count(); i++ ) { if ( V_stricmp( m_VecIndexes[i].GetIndexName(), pszName )== 0 ) return i; } // Not found return -1; } //----------------------------------------------------------------------------- // Purpose: compares index lists in this record with those of another //----------------------------------------------------------------------------- bool CRecordInfo::CompareIndexLists( CRecordInfo* pOther ) { // compare the index lists (but don't use CRCs) // different size? can't be the same if ( pOther->GetIndexFieldCount() != GetIndexFieldCount() ) { return false; } // We have to loop through both lists of indexes and try to find a match. // We also must make sure the match is exact, and that no previous match // can alias another attempt at a match. Pretty messy, but with no available // identity over index objects, we're forced to a suboptimal solution. int nIndexes = GetIndexFieldCount(); // get a copy of the other index vector, which we'll remove items from as // matches are found. CUtlVector vecOtherIndexes; vecOtherIndexes.CopyArray( pOther->GetIndexFields().Base(), nIndexes ); for ( int nOurs = 0; nOurs < nIndexes; nOurs++ ) { int nOtherMatchIndex = -1; const FieldSet_t& refOurs = GetIndexFields()[nOurs]; // rip through copy of other to find one that matches for ( int nOther = 0; nOther < vecOtherIndexes.Count(); nOther++ ) { const FieldSet_t& refOther = vecOtherIndexes[nOther]; if ( FieldSet_t::CompareFieldSets( refOurs, this, refOther, pOther ) ) { nOtherMatchIndex = nOther; break; } } if ( nOtherMatchIndex >= 0 ) { // this works! remove it from other copy vecOtherIndexes.Remove( nOtherMatchIndex ); } else { // something didn't match, so bail out early return false; } } return true; } //----------------------------------------------------------------------------- // Purpose: compares full-text indexes for this record with those of another // column order in an FTS is irrelevant, so this is a simple match //----------------------------------------------------------------------------- bool CRecordInfo::CompareFTSIndexLists( CRecordInfo* pOther ) const { // compare full-text index columns if ( m_vecFTSFields.Count() != pOther->m_vecFTSFields.Count() ) { // counts don't match, so obviously no good return false; } for ( int nColumnIndex = 0; nColumnIndex < m_vecFTSFields.Count(); nColumnIndex++ ) { bool bFound = false; for ( int nInnerIndex = 0; nInnerIndex < pOther->m_vecFTSFields.Count(); nInnerIndex++ ) { if ( m_vecFTSFields[nInnerIndex] == pOther->m_vecFTSFields[nColumnIndex] ) { bFound = true; break; } } if ( !bFound ) return false; } return true; } //----------------------------------------------------------------------------- // Purpose: Returns the checksum for this record info //----------------------------------------------------------------------------- int CRecordInfo::GetChecksum() { Assert( m_bPreparedForUse ); // calculate it now if we haven't already if ( !m_bHaveChecksum ) CalculateChecksum(); return m_nChecksum; } //----------------------------------------------------------------------------- // Purpose: Prepares this object for use after all columns have been added //----------------------------------------------------------------------------- void CRecordInfo::PrepareForUse() { Assert( !m_bPreparedForUse ); Assert( 0 == m_cubFixedSize ); Assert( 0 == m_nChecksum ); SetAllColumnsAdded(); FOR_EACH_VEC( m_VecColumnInfo, nColumn ) { CColumnInfo &columnInfo = m_VecColumnInfo[nColumn]; // keep track of total fixed size of all columns if ( !columnInfo.BIsVariableLength() ) m_cubFixedSize += columnInfo.GetFixedSize(); if ( columnInfo.BIsPrimaryKey() ) { // a PK column! if we have seen one before, // know we have a-column PK; otherwise, a single column PK if (m_nHasPrimaryKey == k_EPrimaryKeyTypeNone) m_nHasPrimaryKey = k_EPrimaryKeyTypeSingle; else m_nHasPrimaryKey = k_EPrimaryKeyTypeMulti; } } // make sure count matches the enum /* Assert( ( m_nHasPrimaryKey == k_EPrimaryKeyTypeNone && m_VecPKFields.Count() == 0 ) || ( m_nHasPrimaryKey == k_EPrimaryKeyTypeMulti && m_VecPKFields.Count() > 1) || ( m_nHasPrimaryKey == k_EPrimaryKeyTypeSingle && m_VecPKFields.Count() == 1) ); */ m_bPreparedForUse = true; } //----------------------------------------------------------------------------- // Purpose: Returns index of column with specified name // Input: pchName - column name // punColumn - pointer to fill in with index // Output: return true if found, false otherwise //----------------------------------------------------------------------------- bool CRecordInfo::BFindColumnByName( const char *pchName, int *punColumn ) { Assert( m_bAllColumnsAdded ); Assert( pchName && *pchName ); Assert( punColumn ); *punColumn = -1; // if we haven't already built the name index, build it now if ( !m_bHaveColumnNameIndex ) BuildColumnNameIndex(); *punColumn = m_MapIColumnInfo.Find( pchName ); return ( m_MapIColumnInfo.InvalidIndex() != *punColumn ); } //----------------------------------------------------------------------------- // Purpose: Sets the name of this record info // Input: pchName - name // Notes: record info that describes a table will have a name (the table name); // record info that describes a result set will not //----------------------------------------------------------------------------- void CRecordInfo::SetName( const char *pchName ) { Assert( pchName && *pchName ); Assert( !m_bPreparedForUse ); // don't change this after prepared for use Q_strncpy( m_rgchName, pchName, Q_ARRAYSIZE( m_rgchName ) ); } //----------------------------------------------------------------------------- // Purpose: Builds the column name index for fast lookup by name //----------------------------------------------------------------------------- void CRecordInfo::BuildColumnNameIndex() { AUTO_LOCK( m_Mutex ); if ( m_bHaveColumnNameIndex ) return; Assert( m_bAllColumnsAdded ); Assert( 0 == m_MapIColumnInfo.Count() ); FOR_EACH_VEC( m_VecColumnInfo, nColumn ) { // build name->column index map CColumnInfo &columnInfo = m_VecColumnInfo[nColumn]; m_MapIColumnInfo.Insert( columnInfo.GetName(), nColumn ); } m_bHaveColumnNameIndex = true; } //----------------------------------------------------------------------------- // Purpose: Calculates the checksum for this record info //----------------------------------------------------------------------------- void CRecordInfo::CalculateChecksum() { AUTO_LOCK( m_Mutex ); if ( m_bHaveChecksum ) return; // build the column name index if necessary if ( !m_bHaveColumnNameIndex ) BuildColumnNameIndex(); CRC32_t crc32; CRC32_Init( &crc32 ); FOR_EACH_MAP( m_MapIColumnInfo, iMapItem ) { uint32 unColumn = m_MapIColumnInfo[iMapItem]; CColumnInfo &columnInfo = m_VecColumnInfo[unColumn]; // calculate checksum of all of our columns columnInfo.CalculateChecksum(); int nChecksum = columnInfo.GetChecksum(); CRC32_ProcessBuffer( &crc32, (void*) &nChecksum, sizeof( nChecksum ) ); } // keep checksum for entire record info CRC32_Final( &crc32 ); m_nChecksum = crc32; m_bHaveChecksum = true; } //----------------------------------------------------------------------------- // Purpose: add another index disallowing duplicates. If a duplicate item is // found, we'll set the flags on the new item from the existing one. //----------------------------------------------------------------------------- int CRecordInfo::AddIndex( const FieldSet_t& fieldSet ) { for ( int n = 0; n < m_VecIndexes.Count(); n++ ) { FieldSet_t& fs = m_VecIndexes[n]; if ( FieldSet_t::CompareFieldSets( fieldSet, this, fs, this ) ) { fs.SetClustered( fs.IsClustered() ); return -1; } } int nRet = m_VecIndexes.AddToTail( fieldSet ); return nRet; } //----------------------------------------------------------------------------- // Purpose: Returns true if there is an IDENTITY column in the record info //----------------------------------------------------------------------------- bool CRecordInfo::BHasIdentity() const { FOR_EACH_VEC( m_VecColumnInfo, nColumn) { if( m_VecColumnInfo[nColumn].BIsAutoIncrement() ) return true; } return false; } //----------------------------------------------------------------------------- // Purpose: Constructor //----------------------------------------------------------------------------- CColumnInfo::CColumnInfo() { m_rgchName[0] = 0; m_nSQLColumn = 0; m_eType = k_EGCSQLTypeInvalid; m_nColFlags = 0; m_cubFixedSize = 0; m_cchMaxSize = 0; m_nChecksum = 0; m_bHaveChecksum = false; } //----------------------------------------------------------------------------- // Purpose: Sets column info for this column // Input: pchName - column name // nSQLColumn - column index in SQL to bind to (1-based) // eType - data type of column // cubFixedSize - for fixed-size fields, the size // nColFlags - attributes //----------------------------------------------------------------------------- void CColumnInfo::Set( const char *pchName, int nSQLColumn, EGCSQLType eType, int cubFixedSize, int nColFlags, int cchMaxSize ) { Assert( !m_rgchName[0] ); Q_strncpy( m_rgchName, pchName, Q_ARRAYSIZE( m_rgchName ) ); m_nSQLColumn = nSQLColumn; m_eType = eType; m_nColFlags = nColFlags; ValidateColFlags(); if ( !BIsVariableLength() ) { Assert( cubFixedSize > 0 ); m_cubFixedSize = cubFixedSize; m_cchMaxSize = 0; } else { // it's variable length, so we need a max length m_cchMaxSize = cchMaxSize; m_cubFixedSize = 0; } } //----------------------------------------------------------------------------- // Purpose: returns whether this column is variable length //----------------------------------------------------------------------------- bool CColumnInfo::BIsVariableLength() const { return m_eType == k_EGCSQLType_Blob || m_eType == k_EGCSQLType_String || m_eType == k_EGCSQLType_Image; } //----------------------------------------------------------------------------- // Purpose: convert column flags to a visible representation //----------------------------------------------------------------------------- void CColumnInfo::GetColFlagDescription( char* pstrOut, int cubOutLength ) const { if ( m_nColFlags == 0 ) Q_strncpy( pstrOut, "(none)", cubOutLength ); else { pstrOut[0] = 0; if ( m_nColFlags & k_nColFlagIndexed ) Q_strncat( pstrOut, "(Indexed)", cubOutLength ); if ( m_nColFlags & k_nColFlagUnique ) Q_strncat( pstrOut, "(Unique)", cubOutLength ); if ( m_nColFlags & k_nColFlagPrimaryKey ) Q_strncat( pstrOut, "(PrimaryKey)", cubOutLength ); if ( m_nColFlags & k_nColFlagAutoIncrement ) Q_strncat( pstrOut, "(AutoIncrement)", cubOutLength ); if ( m_nColFlags & k_nColFlagClustered ) Q_strncat( pstrOut, "(Clustered)", cubOutLength ); } return; } //----------------------------------------------------------------------------- // Purpose: sets column flag bits // Input: nColFlag - bits to set. (Other bits are not cleared.) //----------------------------------------------------------------------------- void CColumnInfo::SetColFlagBits( int nColFlag ) { ValidateColFlags(); m_nColFlags |= nColFlag; // set these bits ValidateColFlags(); } //----------------------------------------------------------------------------- // Purpose: Calculates the checksum for this column //----------------------------------------------------------------------------- void CColumnInfo::CalculateChecksum() { if ( m_bHaveChecksum ) return; // calculate checksum of this column for easy comparsion CRC32_t crc32; CRC32_Init( &crc32 ); CRC32_ProcessBuffer( &crc32, (void*) m_rgchName, Q_strlen( m_rgchName ) ); CRC32_ProcessBuffer( &crc32, (void*) &m_nColFlags, sizeof( m_nColFlags ) ); CRC32_ProcessBuffer( &crc32, (void*) &m_eType, sizeof( m_eType ) ); CRC32_ProcessBuffer( &crc32, (void*) &m_cubFixedSize, sizeof( m_cubFixedSize ) ); CRC32_ProcessBuffer( &crc32, (void*) &m_cchMaxSize, sizeof( m_cchMaxSize ) ); CRC32_Final( &crc32 ); m_nChecksum = crc32; m_bHaveChecksum = true; } //----------------------------------------------------------------------------- // determine if this CColumnInfo is the same as the referenced //----------------------------------------------------------------------------- bool CColumnInfo::operator==( const CColumnInfo& refOther ) const { if ( m_eType != refOther.m_eType ) return false; if ( m_cubFixedSize != refOther.m_cubFixedSize ) return false; if ( m_cchMaxSize != refOther.m_cchMaxSize ) return false; if ( m_nColFlags != refOther.m_nColFlags ) return false; if ( 0 != Q_strcmp( m_rgchName, refOther.m_rgchName ) ) return false; return true; } //----------------------------------------------------------------------------- // Purpose: Validates that column flags are set in valid combinations //----------------------------------------------------------------------------- void CColumnInfo::ValidateColFlags() const { // Check that column flags follow rules about how columns get expressed in SQL if ( m_nColFlags & k_nColFlagPrimaryKey ) { // a primary key must also be unique and indexed Assert( m_nColFlags & k_nColFlagUnique ); Assert( m_nColFlags & k_nColFlagIndexed ); } // a column with uniqueness constraint must also be indexed if ( m_nColFlags & k_nColFlagUnique ) Assert( m_nColFlags & k_nColFlagIndexed ); } CRecordInfo *CRecordInfo::Alloc() { CRecordInfo *pRecordInfo = sm_MemPoolRecordInfo.Alloc(); #ifdef _DEBUG AUTO_LOCK( sm_mutexMemPoolRecordInfo ); sm_mapPMemPoolRecordInfo.Insert( pRecordInfo ); #endif return pRecordInfo; } void CRecordInfo::DestroyThis() { #ifdef _DEBUG AUTO_LOCK( sm_mutexMemPoolRecordInfo ); sm_mapPMemPoolRecordInfo.Remove( this ); #endif sm_MemPoolRecordInfo.Free( this ); } #ifdef DBGFLAG_VALIDATE void CRecordInfo::ValidateStatics( CValidator &validator, const char *pchName ) { VALIDATE_SCOPE_STATIC( "CRecordInfo class statics" ); ValidateObj( sm_MemPoolRecordInfo ); #ifdef _DEBUG AUTO_LOCK( sm_mutexMemPoolRecordInfo ); ValidateObj( sm_mapPMemPoolRecordInfo ); FOR_EACH_MAP_FAST( sm_mapPMemPoolRecordInfo, i ) { sm_mapPMemPoolRecordInfo[i]->Validate( validator, "sm_mapPMemPoolRecordInfo[i]" ); } #endif } void CRecordInfo::Validate( CValidator &validator, const char *pchName ) { VALIDATE_SCOPE(); m_VecIndexes.Validate( validator, "m_VecIndexes" ); ValidateObj( m_VecFKData ); FOR_EACH_VEC( m_VecFKData, i ) { ValidateObj( m_VecFKData[i] ); } for ( int iIndex = 0; iIndex < m_VecIndexes.Count(); iIndex++ ) { ValidateObj( m_VecIndexes[iIndex] ); } ValidateObj( m_vecFTSFields ); ValidateObj( m_VecColumnInfo ); FOR_EACH_VEC( m_VecColumnInfo, nColumn ) { CColumnInfo &columnInfo = GetColumnInfo( nColumn ); ValidateObj( columnInfo ); } ValidateObj( m_MapIColumnInfo ); } void CColumnInfo::Validate( CValidator &validator, const char *pchName ) { VALIDATE_SCOPE(); } #endif // DBGFLAG_VALIDATE } // namespace GCSDK