//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //============================================================================= #include "stdafx.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" namespace GCSDK { //----------------------------------------------------------------------------- // Purpose: Destructor //----------------------------------------------------------------------------- CRecordBase::~CRecordBase() { Cleanup(); } //----------------------------------------------------------------------------- // Purpose: Copy constructor // Input: that - CRecord to copy from //----------------------------------------------------------------------------- CRecordBase::CRecordBase( const CRecordBase &that ) { *this = that; } //----------------------------------------------------------------------------- // Purpose: Assignment operator - COPIES the record data // Input: that - CRecord to copy from //----------------------------------------------------------------------------- CRecordBase& CRecordBase::operator = ( const CRecordBase & that ) { Assert( GetITable() == that.GetITable() ); // COPY that record Copy( that ); return *this; } //----------------------------------------------------------------------------- // Purpose: Copies the data in the record. This is overridden by CRecordVar and // CRecordExternal // Input: that - CRecord to copy from //----------------------------------------------------------------------------- void CRecordBase::Copy( const CRecordBase & that ) { Cleanup(); Q_memcpy( PubRecordFixed(), that.PubRecordFixed(), GetPSchema()->CubRecordFixed() ); } //----------------------------------------------------------------------------- // Purpose: Return the record info for this record's schema //----------------------------------------------------------------------------- const CRecordInfo *CRecordBase::GetPRecordInfo() const { return GetPSchema()->GetRecordInfo(); } //----------------------------------------------------------------------------- // Purpose: Copies the data in the var record. // Input: that - CRecord to copy from //----------------------------------------------------------------------------- void CRecordVar::Copy( const CRecordBase & baseThat ) { const CRecordVar & that = (const CRecordVar &)baseThat; // COPY that record Cleanup(); m_pSchema = that.m_pSchema; Q_memcpy( PubRecordFixed(), that.PubRecordFixed(), GetPSchema()->CubRecordFixed() ); SetFlag( k_EAllocatedVarBlock, false ); if ( VarFieldBlockInfo_t *pVarBlockInfo = GetPSchema()->PVarFieldBlockInfoFromRecord( PubRecordFixed() ) ) { if ( pVarBlockInfo->m_cubBlock ) { void *pvNewBlock = malloc( pVarBlockInfo->m_cubBlock ); Q_memcpy( pvNewBlock, pVarBlockInfo->m_pubBlock, pVarBlockInfo->m_cubBlock ); pVarBlockInfo->m_pubBlock = ( uint8 * )pvNewBlock; SetFlag( k_EAllocatedVarBlock, true ); } } } //----------------------------------------------------------------------------- // Purpose: Copies the data in the var record. // Input: that - CRecord to copy from //----------------------------------------------------------------------------- void CRecordExternal::Copy( const CRecordBase & baseThat ) { const CRecordExternal & that = (const CRecordExternal &)baseThat; Cleanup(); m_pSchema = that.m_pSchema; m_pubRecordFixedExternal = ( uint8 * )malloc( m_pSchema->CubRecordFixed() ); Q_memcpy( m_pubRecordFixedExternal, that.PubRecordFixed(), m_pSchema->CubRecordFixed() ); SetFlag( k_EAllocatedFixed, true ); SetFlag( k_EAllocatedVarBlock, false ); if ( VarFieldBlockInfo_t *pVarBlockInfo = m_pSchema->PVarFieldBlockInfoFromRecord( PubRecordFixed() ) ) { if ( pVarBlockInfo->m_cubBlock ) { void *pvNewBlock = malloc( pVarBlockInfo->m_cubBlock ); Q_memcpy( pvNewBlock, pVarBlockInfo->m_pubBlock, pVarBlockInfo->m_cubBlock ); pVarBlockInfo->m_pubBlock = ( uint8 * )pvNewBlock; SetFlag( k_EAllocatedVarBlock, true ); } } } //----------------------------------------------------------------------------- // Purpose: Initialize to an empty record // Input: pSchema - Schema for the record this will hold //----------------------------------------------------------------------------- void CRecordExternal::Init( CSchema *pSchema ) { Cleanup(); m_pSchema = pSchema; m_pubRecordFixedExternal = ( uint8 * )malloc( m_pSchema->CubRecordFixed() ); Q_memset( m_pubRecordFixedExternal, 0, m_pSchema->CubRecordFixed() ); SetFlag( k_EAllocatedFixed, true ); } //----------------------------------------------------------------------------- // Purpose: Initialize pointing to a record expanded in memory // Input: pSchema - Schema for the record this will hold // pubRecord - Pointer to fixed record data // bTakeOwnership - Should we delete the record when destroyed // Output: Size of the record's data //----------------------------------------------------------------------------- int CRecordBase::InitFromBytes( uint8 *pubRecord ) { Cleanup(); Q_memcpy( PubRecordFixed(), pubRecord, GetPSchema()->CubRecordFixed() ); int cubRead = GetPSchema()->CubRecordFixed(); return cubRead; } int CRecordVar::InitFromBytes( uint8 *pubRecord ) { Cleanup(); Q_memcpy( PubRecordFixed(), pubRecord, GetPSchema()->CubRecordFixed() ); int cubRead = GetPSchema()->CubRecordFixed(); if ( VarFieldBlockInfo_t *pVarBlockInfo = GetPSchema()->PVarFieldBlockInfoFromRecord( PubRecordFixed() ) ) { if ( pVarBlockInfo->m_cubBlock ) { void *pvNewBlock = malloc( pVarBlockInfo->m_cubBlock ); Q_memcpy( pvNewBlock, pVarBlockInfo->m_pubBlock, pVarBlockInfo->m_cubBlock ); pVarBlockInfo->m_pubBlock = ( uint8 * )pvNewBlock; SetFlag( k_EAllocatedVarBlock, true ); cubRead += pVarBlockInfo->m_cubBlock; } } return cubRead; } int CRecordExternal::Init( CSchema *pSchema, uint8 *pubRecord, bool bTakeOwnership ) { m_pSchema = pSchema; m_pubRecordFixedExternal = pubRecord; SetFlag( k_EAllocatedFixed, bTakeOwnership ); SetFlag( k_EAllocatedVarBlock, bTakeOwnership ); int cubRead = m_pSchema->CubRecordFixed() + CubRecordVarBlock(); return cubRead; } CSchema *CRecordBase::GetPSchema() { return GetPSchemaImpl(); } CSchema *CRecordBase::GetPSchemaImpl() { CSchema *pSchema = NULL; int i = GetITable(); if ( i != -1 ) pSchema = &GSchemaFull().GetSchema( i ); return pSchema; } //----------------------------------------------------------------------------- // Purpose: Render a field to a buffer // Input: unColumn - field to render // cchBuffer - size of render buffer // pchBuffer - buffer to render into //----------------------------------------------------------------------------- void CRecordBase::RenderField( uint32 unColumn, int cchBuffer, char *pchBuffer ) const { Q_strncpy( pchBuffer, "", cchBuffer ); uint8 *pubData; uint32 cubData; if ( !BGetField( unColumn, &pubData, &cubData ) ) return; // Get the column info and figure out how to interpret the data ConvertFieldToText( GetPRecordInfo()->GetColumnInfo( unColumn ).GetType(), pubData, cubData, pchBuffer, cchBuffer, false ); } //----------------------------------------------------------------------------- // Purpose: Reset to base state, freeing any memory we are responsible for //----------------------------------------------------------------------------- void CRecordBase::Cleanup() { } void CRecordVar::Cleanup() { // Must do this before freeing memory that encloses it // (eg releasing the net packet) if ( BFlagSet( k_EAllocatedVarBlock ) ) { void *pvVarBlock = m_pSchema->PVarFieldBlockInfoFromRecord( PubRecordFixed() )->m_pubBlock; free( pvVarBlock ); m_pSchema->PVarFieldBlockInfoFromRecord( PubRecordFixed() )->m_pubBlock = NULL; SetFlag( k_EAllocatedVarBlock, false ); } } void CRecordExternal::Cleanup() { // clean up the variable-length memory we might have allocated if ( BFlagSet( k_EAllocatedVarBlock ) ) { void *pvVarBlock = m_pSchema->PVarFieldBlockInfoFromRecord( PubRecordFixed() )->m_pubBlock; free( pvVarBlock ); m_pSchema->PVarFieldBlockInfoFromRecord( PubRecordFixed() )->m_pubBlock = NULL; SetFlag( k_EAllocatedVarBlock, false ); } // clean up the external memory we might have allocated if ( BFlagSet( k_EAllocatedFixed ) ) free( m_pubRecordFixedExternal ); SetFlag( k_EAllocatedFixed, false ); m_pubRecordFixedExternal = NULL; // clean up the lowest layer, not calling CRecordVar CRecordBase::Cleanup(); } //----------------------------------------------------------------------------- // Purpose: Deserializes a block of memory into this record // Input: pubData - Memory block to deserialize from //----------------------------------------------------------------------------- void CRecordExternal::DeSerialize( uint8 *pubData ) { InitFromBytes( pubData ); } //----------------------------------------------------------------------------- // Purpose: Calculates the size of this record when serialized // Output: Size of serialized message //----------------------------------------------------------------------------- uint32 CRecordBase::CubSerialized() { return CubRecordFixed() + CubRecordVarBlock(); } //----------------------------------------------------------------------------- // Purpose: Get pointer to fixed part of record // Output: pubRecordFixed //----------------------------------------------------------------------------- uint8* CRecordBase::PubRecordFixed() { return ( uint8 * )( this + 1 ); } uint8* CRecordExternal::PubRecordFixed() { Assert( m_pubRecordFixedExternal ); return m_pubRecordFixedExternal; } uint8* CRecordVar::PubRecordFixed() { return ( uint8 * )( this + 1 ); } //----------------------------------------------------------------------------- // Purpose: Get pointer to fixed part of record // Output: pubRecordFixed //----------------------------------------------------------------------------- const uint8* CRecordBase::PubRecordFixed() const { return const_cast( this )->PubRecordFixed(); } const uint8* CRecordVar::PubRecordFixed() const { return const_cast( this )->PubRecordFixed(); } const uint8* CRecordExternal::PubRecordFixed() const { return const_cast( this )->PubRecordFixed(); } //----------------------------------------------------------------------------- // Purpose: Get size of fixed part of record // Output: size in bytes of fixed part //----------------------------------------------------------------------------- uint32 CRecordBase::CubRecordFixed() const { return GetPSchema()->CubRecordFixed(); } //----------------------------------------------------------------------------- // Purpose: Get pointer to variable part of record // Output: Pointer to variable-length block -- may be NULL if this record // has no var-length fields or they are all empty //----------------------------------------------------------------------------- uint8* CRecordBase::PubRecordVarBlock() { VarFieldBlockInfo_t *pVarFieldBlockInfo = GetPSchema()->PVarFieldBlockInfoFromRecord( PubRecordFixed() ); if ( pVarFieldBlockInfo ) { return pVarFieldBlockInfo->m_pubBlock; } else { return NULL; } } //----------------------------------------------------------------------------- // Purpose: Get pointer to variable part of record // Output: Pointer to variable-length block -- may be NULL if this record // has no var-length fields or they are all empty //----------------------------------------------------------------------------- const uint8* CRecordBase::PubRecordVarBlock() const { return const_cast( this )->PubRecordVarBlock(); } //----------------------------------------------------------------------------- // Purpose: Get size of variable part of record // Output: Size in bytes of var-length block - may be zero if this record // has no var-length fields or they are all empty //----------------------------------------------------------------------------- uint32 CRecordBase::CubRecordVarBlock() const { VarFieldBlockInfo_t *pVarFieldBlockInfo = GetPSchema()->PVarFieldBlockInfoFromRecord( PubRecordFixed() ); if ( pVarFieldBlockInfo ) { return pVarFieldBlockInfo->m_cubBlock; } else { return 0; } } //----------------------------------------------------------------------------- // Purpose: Get size of variable part of record // Output: Size in bytes of var-length block - may be zero if this record // has no var-length fields or they are all empty //----------------------------------------------------------------------------- bool CRecordBase::BAssureRecordVarStorage( uint32 cVariableBytes ) { // get the variable field block VarFieldBlockInfo_t *pVarFieldBlockInfo = GetPSchema()->PVarFieldBlockInfoFromRecord( PubRecordFixed() ); if ( pVarFieldBlockInfo ) { // if we have it, see if it's got enough storage if ( pVarFieldBlockInfo->m_cubBlock >= cVariableBytes ) { // already there return true; } // allocate it uint8* pubData = (uint8*) malloc( cVariableBytes ); if ( pubData == NULL ) return false; // do we have something right now? if ( pVarFieldBlockInfo->m_cubBlock != 0 ) { // sure do. copy it over. Q_memcpy( pubData, pVarFieldBlockInfo->m_pubBlock, pVarFieldBlockInfo->m_cubBlock ); // free what was there free( pVarFieldBlockInfo->m_pubBlock ); } // hook up our buffer pVarFieldBlockInfo->m_cubBlockFree = cVariableBytes - pVarFieldBlockInfo->m_cubBlock; pVarFieldBlockInfo->m_cubBlock = cVariableBytes; pVarFieldBlockInfo->m_pubBlock = pubData; return true; } else { // we don't have one; // we've got no variable length fields, and so can't preallocate for them! return false; } } //----------------------------------------------------------------------------- // Purpose: Initialize this whole record to random data // Input: unPrimaryIndex - Primary index to set //----------------------------------------------------------------------------- void CRecordExternal::InitRecordRandom( uint32 unPrimaryIndex ) { bool bRealloced = false; GetPSchema()->InitRecordRandom( PubRecordFixed(), unPrimaryIndex, &bRealloced, BFlagSet( k_EAllocatedVarBlock ) ); if ( bRealloced ) SetFlag( k_EAllocatedVarBlock, true ); } //----------------------------------------------------------------------------- // Purpose: Set a field in this record to random bits // Input: iField - Field to set //----------------------------------------------------------------------------- void CRecordExternal::SetFieldRandom( int iField ) { bool bRealloced = false; GetPSchema()->SetFieldRandom( PubRecordFixed(), iField, &bRealloced, BFlagSet( k_EAllocatedVarBlock ) ); if ( bRealloced ) SetFlag( k_EAllocatedVarBlock, true ); } //----------------------------------------------------------------------------- // Purpose: Get a field (var or fixed) from this record // Input: iField - Field to set // ppubData - Receives pointer to fields data // pcubField - Receives count of bytes of data (will count the null for strings) // Output: true if succeeds //----------------------------------------------------------------------------- bool CRecordBase::BGetField( int iField, uint8 **ppubData, uint32 *pcubField ) const { return GetPSchema()->BGetFieldData( PubRecordFixed(), iField, ppubData, pcubField ); } //----------------------------------------------------------------------------- // Purpose: Sets the data for a field, whether fixed or variable length // Input: iField - index of field to set // pubData - pointer to field data to copy from // cubData - size in bytes of that data // Output: true if successful //----------------------------------------------------------------------------- bool CRecordBase::BSetField( int iField, void *pvData, uint32 cubData ) { bool bRealloced = false; bool bResult = BSetField( iField, pvData, cubData, &bRealloced ); Assert( !bRealloced ); return bResult; } bool CRecordBase::BSetField( int iField, void *pvData, uint32 cubData, bool *pbRealloced ) { uint8 *pubData = reinterpret_cast( pvData ); if ( !GetPSchema()->BSetFieldData( PubRecordFixed(), iField, pubData, cubData, pbRealloced ) ) return false; return true; } bool CRecordVar::BSetField( int iField, void *pvData, uint32 cubData ) { bool bRealloced = false; bool bResult = CRecordBase::BSetField( iField, pvData, cubData, &bRealloced ); if ( bRealloced ) SetFlag( k_EAllocatedVarBlock, true ); return bResult; } //----------------------------------------------------------------------------- // Purpose: Erases a field, setting it to 0 length (if possible) and filling with nulls // Input: iField - index of field to wipe // NOTE: This relies on CSchema::BSetFieldData nulling out the rest of a field when it is set to 0 length! //----------------------------------------------------------------------------- void CRecordBase::WipeField( int iField ) { bool bRealloced = false; // Empty Data uint32 un = 0; // Length should be 0, except for non-variable length strings where length should be 1 (for an empty string "") int cub = 0; Field_t &field = GetPSchema()->GetField( iField ); Assert( !field.BIsVariableLength() ); if ( field.BIsStringType() ) cub = 1; GetPSchema()->BSetFieldData( PubRecordFixed(), iField, ( uint8 * ) &un, cub, &bRealloced ); Assert( !bRealloced ); } void CRecordVar::WipeField( int iField ) { bool bRealloced = false; // Empty Data uint32 un = 0; // Length should be 0, except for non-variable length strings where length should be 1 (for an empty string "") int cub = 0; Field_t &field = GetPSchema()->GetField( iField ); if ( field.BIsStringType() && !field.BIsVariableLength() ) cub = 1; GetPSchema()->BSetFieldData( PubRecordFixed(), iField, ( uint8 * ) &un, cub, &bRealloced ); if ( bRealloced ) SetFlag( k_EAllocatedVarBlock, true ); } //----------------------------------------------------------------------------- // Purpose: Get a string field - will return empty string instead of NULL if field has no datas // Input: iField - Field to get // pcubField - Receives count of bytes of data (will count the null for strings) // Output: const pointer to string data (to an empty string if no data) //----------------------------------------------------------------------------- const char * CRecordBase::GetStringField( int iField, uint32 *pcubField ) { uint8 * pubData = NULL; *pcubField = 0; if ( BGetField( iField, &pubData, pcubField ) && *pcubField > 0 ) return ( const char * ) pubData; else return ""; } //----------------------------------------------------------------------------- // Purpose: Get an int field // Input: iField - Field to get // Output: Int (0 if no data) //----------------------------------------------------------------------------- int CRecordBase::GetInt( int iField ) { return ( int ) GetUint32( iField ); } //----------------------------------------------------------------------------- // Purpose: Get a uint16 field // Input: iField - Field to get // Output: uint16 (0 if no data) //----------------------------------------------------------------------------- uint16 CRecordBase::GetUint16( int iField ) { uint8 * pubData = NULL; uint32 cubField = 0; DbgVerify( BGetField( iField, &pubData, &cubField ) ); Assert( 0 < cubField ); if ( NULL != pubData ) return *( uint16 * ) pubData; else return 0; } //----------------------------------------------------------------------------- // Purpose: Get a uint32 field // Input: iField - Field to get // Output: uint32 (0 if no data) //----------------------------------------------------------------------------- uint32 CRecordBase::GetUint32( int iField ) { uint8 * pubData = NULL; uint32 cubField = 0; DbgVerify( BGetField( iField, &pubData, &cubField ) ); Assert( 0 < cubField ); if ( NULL != pubData ) return *( uint32 * ) pubData; else return 0; } //----------------------------------------------------------------------------- // Purpose: Get a uint64 field // Input: iField - Field to get // Output: uint64 (0 if no data) //----------------------------------------------------------------------------- uint64 CRecordBase::GetUint64( int iField ) { uint8 * pubData = NULL; uint32 cubField = 0; DbgVerify( BGetField( iField, &pubData, &cubField ) ); Assert( 0 < cubField ); if ( NULL != pubData ) return *( uint64 * ) pubData; else return 0; } const char * CRecordBase::ReadVarCharField( const CVarCharField &field ) const { Assert( false ); return NULL; } const uint8 * CRecordBase::ReadVarDataField( const CVarField &field, uint32 *pcubField ) const { Assert( false ); return NULL; } // These may cause a realloc bool CRecordBase::SetVarCharField( CVarCharField &field, const char *pchString, bool bTruncate, int32 iField ) { Assert( false ); return false ; } void CRecordBase::SetVarDataField( CVarField &field, const void *pvData, uint32 cubData ) { Assert( false ); } //----------------------------------------------------------------------------- // Purpose: Read data from a varchar field // Input: field - opaque field object to read from // Output: pointer to data - may be NULL if that field is empty. //----------------------------------------------------------------------------- const char * CRecordVar::ReadVarCharField( const CVarCharField &field ) const { Assert ( GetPSchema()->BHasVariableFields() ); uint8 *pubData; uint32 cubData; if ( GetPSchema()->BGetVarField( PubRecordFixed(), &field, &pubData, &cubData ) ) return (const char *)pubData; else return ""; } //----------------------------------------------------------------------------- // Purpose: Read data from a vardata field // Input: field - opaque field object to read from // Output: pointer to data - may be NULL if that field is empty. //----------------------------------------------------------------------------- const uint8 *CRecordVar::ReadVarDataField( const CVarField &field, uint32 *pcubField ) const { Assert ( GetPSchema()->BHasVariableFields() ); uint8 *pubData; *pcubField = 0; if ( GetPSchema()->BGetVarField( PubRecordFixed(), &field, &pubData, pcubField ) ) return pubData; else return NULL; } //----------------------------------------------------------------------------- // Purpose: Update (in memory) a varchar field // Input: field - opaque field object to update // pchString - string data to set //----------------------------------------------------------------------------- bool CRecordVar::SetVarCharField( CVarCharField &field, const char *pchString, bool bTruncate, int32 iField ) { Assert ( GetPSchema()->BHasVariableFields() ); if( iField < 0 ) { AssertMsg1( false, "Encountered a bad call to SetVarCharField with an invalid field specified: %d", iField ); return false; } bool bTruncated = false; int cchLen = Q_strlen( pchString ) + 1; // since we're a VARCHAR field, cbMaxLength is the length in characters const int cchMaxLength = m_pSchema->GetField( iField ).m_cchMaxLength; if ( ( cchMaxLength > 0 ) && ( cchLen > cchMaxLength ) ) { if( bTruncate ) { bTruncated = true; cchLen = cchMaxLength; } else { // caller should check his data and not pass stuff that wont fit AssertMsg4( false, "Overflow in SetVarCharField (%u > %u) for column %s in table %s", cchLen, cchMaxLength, m_pSchema->GetField( iField ).m_rgchName, m_pSchema->GetPchName() ); return false; } } bool bRealloced = false; bool fSuccess = GetPSchema()->BSetVarField( PubRecordFixed(), &field, pchString, cchLen, &bRealloced, BFlagSet( k_EAllocatedVarBlock ) ); if( fSuccess && bTruncated ) { //make sure the last character is NULL if we truncated VarFieldBlockInfo_t *pBlock = GetPSchema()->PVarFieldBlockInfoFromRecord( PubRecordFixed() ); uint8 *pubVarBlock = pBlock->m_pubBlock; char* pField = ( char* )( pubVarBlock + field.m_dubOffset ); pField[ cchLen - 1 ] = '\0'; } if ( bRealloced ) SetFlag( k_EAllocatedVarBlock, true ); return fSuccess; } //----------------------------------------------------------------------------- // Purpose: Update (in memory) a vardata field // Input: field - opaque field object to update // pvData - pointer to data to put there // cubData - size in bytes of the data //----------------------------------------------------------------------------- void CRecordVar::SetVarDataField( CVarField &field, const void *pvData, uint32 cubData ) { Assert ( GetPSchema()->BHasVariableFields() ); bool bRealloced = false; GetPSchema()->BSetVarField( PubRecordFixed(), &field, pvData, cubData, &bRealloced, BFlagSet( k_EAllocatedVarBlock ) ); if ( bRealloced ) SetFlag( k_EAllocatedVarBlock, true ); } //----------------------------------------------------------------------------- // Purpose: Set or clear the specified flag in m_nFlags // Input: eFlag - flag (single bit) to change // bSet - Set it, else clear it //----------------------------------------------------------------------------- void CRecordVar::SetFlag( int eFlag, bool bSet ) { if ( bSet ) m_nFlags |= eFlag; else m_nFlags &= ~eFlag; } //----------------------------------------------------------------------------- // Purpose: Get the state of the specified flag // Input: eFlag - flag (single bit) to check //----------------------------------------------------------------------------- bool CRecordVar::BFlagSet( int eFlag ) const { return 0 != ( m_nFlags & eFlag ); } #ifdef DBGFLAG_VALIDATE //----------------------------------------------------------------------------- // Purpose: Run a global validation pass on all of our data structures and memory // allocations. // Input: validator - Our global validator object // pchName - Our name (typically a member var in our container) //----------------------------------------------------------------------------- void CRecordBase::Validate( CValidator &validator, const char *pchName ) { VALIDATE_SCOPE(); } void CRecordVar::Validate( CValidator &validator, const char *pchName ) { VALIDATE_SCOPE(); if ( BFlagSet( k_EAllocatedVarBlock ) ) { validator.ClaimMemory( GetPSchema()->PVarFieldBlockInfoFromRecord( PubRecordFixed() )->m_pubBlock ); } } void CRecordExternal::Validate( CValidator &validator, const char *pchName ) { if ( BFlagSet( k_EAllocatedFixed ) ) { validator.ClaimMemory( m_pubRecordFixedExternal ); } CRecordBase::Validate( validator, pchName ); } void CRecordBase::ValidateStatics( CValidator &validator, const char *pchName ) { VALIDATE_SCOPE_STATIC( "CRecordBase class statics" ); } #endif // DBGFLAG_VALIDATE //----------------------------------------------------------------------------- // Purpose: Return the schema for this record type //----------------------------------------------------------------------------- CSchema *CRecordType::GetSchema() const { return &GSchemaFull().GetSchema( GetITable() ); } //----------------------------------------------------------------------------- // Purpose: Return the CRecordInfo for this record type //----------------------------------------------------------------------------- CRecordInfo *CRecordType::GetRecordInfo() const { return GetSchema()->GetRecordInfo(); } } // namespace GCSDK