summaryrefslogtreecommitdiff
path: root/gcsdk/sqlaccess/recordinfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gcsdk/sqlaccess/recordinfo.cpp')
-rw-r--r--gcsdk/sqlaccess/recordinfo.cpp915
1 files changed, 915 insertions, 0 deletions
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> CRecordInfo::sm_MemPoolRecordInfo( 10, UTLMEMORYPOOL_GROW_FAST );
+
+#ifdef _DEBUG
+// validation tracking
+CUtlRBTree<CRecordInfo *, int > 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<FieldSet_t> 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