From 3bf9df6b2785fa6d951086978a3e66f49427166a Mon Sep 17 00:00:00 2001 From: FluorescentCIAAfricanAmerican <0934gj3049fk@protonmail.com> Date: Wed, 22 Apr 2020 12:56:21 -0400 Subject: 1 --- gcsdk/sqlaccess/recordinfo.cpp | 915 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 915 insertions(+) create mode 100644 gcsdk/sqlaccess/recordinfo.cpp (limited to 'gcsdk/sqlaccess/recordinfo.cpp') diff --git a/gcsdk/sqlaccess/recordinfo.cpp b/gcsdk/sqlaccess/recordinfo.cpp new file mode 100644 index 0000000..57fb435 --- /dev/null +++ b/gcsdk/sqlaccess/recordinfo.cpp @@ -0,0 +1,915 @@ +//========= 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 -- cgit v1.2.3