Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

915 lines
26 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================
  7. #include "stdafx.h"
  8. //#include "sqlaccess.h"
  9. // memdbgon must be the last include file in a .cpp file!!!
  10. #include "tier0/memdbgon.h"
  11. namespace GCSDK
  12. {
  13. // Memory pool for CRecordInfo
  14. CThreadSafeClassMemoryPool<CRecordInfo> CRecordInfo::sm_MemPoolRecordInfo( 10, UTLMEMORYPOOL_GROW_FAST );
  15. #ifdef _DEBUG
  16. // validation tracking
  17. CUtlRBTree<CRecordInfo *, int > CRecordInfo::sm_mapPMemPoolRecordInfo( DefLessFunc( CRecordInfo *) );
  18. CThreadMutex CRecordInfo::sm_mutexMemPoolRecordInfo;
  19. #endif
  20. //-----------------------------------------------------------------------------
  21. // determine if this fieldset is equal to the other one
  22. //-----------------------------------------------------------------------------
  23. /* static */
  24. bool FieldSet_t::CompareFieldSets( const FieldSet_t& refThis, CRecordInfo* pRecordInfoThis,
  25. const FieldSet_t& refOther, CRecordInfo* pRecordInfoOther )
  26. {
  27. // same number of columns?
  28. int cColumns = refThis.GetCount();
  29. if ( refOther.GetCount() != cColumns )
  30. return false;
  31. int cIncludedColumns = refThis.GetIncludedCount();
  32. if ( refOther.GetIncludedCount() != cIncludedColumns )
  33. return false;
  34. // do the regular columns first; this is order-dependent
  35. for ( int m = 0; m < cColumns; m++ )
  36. {
  37. int nThisField = refThis.GetField( m );
  38. const CColumnInfo& refThisColumn = pRecordInfoThis->GetColumnInfo( nThisField );
  39. int nOtherField = refOther.GetField( m );
  40. const CColumnInfo& refOtherColumn = pRecordInfoOther->GetColumnInfo( nOtherField );
  41. if ( refOtherColumn != refThisColumn )
  42. {
  43. return false;
  44. }
  45. }
  46. // do the included columns now; order independent
  47. for ( int m = 0; m < cIncludedColumns; m++ )
  48. {
  49. int nThisField = refThis.GetIncludedField( m );
  50. const CColumnInfo& refThisColumn = pRecordInfoThis->GetColumnInfo( nThisField );
  51. bool bFoundMatch = false;
  52. for ( int n = 0; n < cIncludedColumns; n++ )
  53. {
  54. int nOtherField = refOther.GetIncludedField( n );
  55. const CColumnInfo& refOtherColumn = pRecordInfoOther->GetColumnInfo( nOtherField );
  56. if ( refOtherColumn == refThisColumn )
  57. {
  58. bFoundMatch = true;
  59. break;
  60. }
  61. }
  62. if ( !bFoundMatch )
  63. return false;
  64. }
  65. return true;
  66. }
  67. //-----------------------------------------------------------------------------
  68. // Purpose: Constructor
  69. //-----------------------------------------------------------------------------
  70. CRecordInfo::CRecordInfo()
  71. : m_MapIColumnInfo( 0, 0, CaselessStringLessThan )
  72. {
  73. m_rgchName[0] = 0;
  74. m_bPreparedForUse = false;
  75. m_bAllColumnsAdded = false;
  76. m_bHaveChecksum = false;
  77. m_bHaveColumnNameIndex = false;
  78. m_nHasPrimaryKey = k_EPrimaryKeyTypeNone;
  79. m_iPKIndex = -1;
  80. m_cubFixedSize = 0;
  81. m_nChecksum = 0;
  82. m_eSchemaCatalog = k_ESchemaCatalogInvalid;
  83. m_nTableID = 0;
  84. }
  85. //-----------------------------------------------------------------------------
  86. // Purpose: Initializes this record info from DS equivalent information
  87. //-----------------------------------------------------------------------------
  88. void CRecordInfo::InitFromDSSchema( CSchema *pSchema )
  89. {
  90. // copy the name over
  91. SetName( pSchema->GetPchName() );
  92. // copy each of the fields, preallocating capacity
  93. int cFields = pSchema->GetCField();
  94. m_VecColumnInfo.EnsureCapacity( cFields );
  95. for ( int iField = 0; iField < cFields; iField++ )
  96. {
  97. Field_t &field = pSchema->GetField( iField );
  98. AddColumn( field.m_rgchSQLName, iField+1, field.m_EType, field.m_cubLength, field.m_nColFlags, field.m_cchMaxLength );
  99. }
  100. m_nTableID = pSchema->GetITable();
  101. // copy the list of PK index fields
  102. m_iPKIndex = pSchema->GetPKIndex( );
  103. // copy the list of Indexes
  104. m_VecIndexes = pSchema->GetIndexes( );
  105. // which schema?
  106. m_eSchemaCatalog = pSchema->GetESchemaCatalog();
  107. // copy full-text column list
  108. // and the index of the catalog it will create on
  109. m_vecFTSFields = pSchema->GetFTSColumns();
  110. m_nFullTextCatalogIndex = pSchema->GetFTSIndexCatalog();
  111. // Copy over the FK data
  112. int cFKs = pSchema->GetFKCount();
  113. for ( int i = 0; i < cFKs; ++i )
  114. {
  115. FKData_t &fkData = pSchema->GetFKData( i );
  116. AddFK( fkData );
  117. }
  118. // prepare for use
  119. PrepareForUse( );
  120. }
  121. //-----------------------------------------------------------------------------
  122. // Purpose: Adds a new column to this record info
  123. // Input: pchName - column name
  124. // nSQLColumn - column index in SQL to bind to (1-based)
  125. // eType - data type of column
  126. // cubFixedSize - for fixed-size fields, the size
  127. // nColFlags - attributes
  128. //-----------------------------------------------------------------------------
  129. void CRecordInfo::AddColumn( const char *pchName, int nSQLColumn, EGCSQLType eType, int cubFixedSize, int nColFlags, int cchMaxSize )
  130. {
  131. Assert( !m_bPreparedForUse );
  132. if ( m_bPreparedForUse )
  133. return;
  134. uint32 unColumn = m_VecColumnInfo.AddToTail();
  135. CColumnInfo &columnInfo = m_VecColumnInfo[unColumn];
  136. columnInfo.Set( pchName, nSQLColumn, eType, cubFixedSize, nColFlags, cchMaxSize );
  137. }
  138. //-----------------------------------------------------------------------------
  139. // Purpose: Adds a new FK to this record info
  140. //-----------------------------------------------------------------------------
  141. void CRecordInfo::AddFK( const FKData_t &fkData )
  142. {
  143. m_VecFKData.AddToTail( fkData );
  144. }
  145. //-----------------------------------------------------------------------------
  146. // Purpose: compare function to sort by column name
  147. //-----------------------------------------------------------------------------
  148. int __cdecl CompareColumnInfo( const CColumnInfo *pColumnInfoLeft, const CColumnInfo *pColumnInfoRight )
  149. {
  150. const char *pchLeft = ( (CColumnInfo *) pColumnInfoLeft )->GetName();
  151. const char *pchRight = ( (CColumnInfo *) pColumnInfoRight )->GetName();
  152. Assert( pchLeft && pchLeft[0] );
  153. Assert( pchRight && pchRight[0] );
  154. return Q_stricmp( pchLeft, pchRight );
  155. }
  156. //-----------------------------------------------------------------------------
  157. // Purpose: compares this record info to another record info
  158. //-----------------------------------------------------------------------------
  159. bool CRecordInfo::EqualTo( CRecordInfo* pOther )
  160. {
  161. int nOurs = GetChecksum();
  162. int nTheirs = pOther->GetChecksum();
  163. // if this much isn't equal, we're no good
  164. if (nOurs != nTheirs)
  165. return false;
  166. if ( !CompareIndexLists( pOther ) )
  167. return false;
  168. if ( !CompareFKs( pOther ) )
  169. return false;
  170. return CompareFTSIndexLists( pOther );
  171. }
  172. //-----------------------------------------------------------------------------
  173. // Purpose: format the index list into a string
  174. //-----------------------------------------------------------------------------
  175. void CRecordInfo::GetIndexFieldList( CFmtStr1024 *pstr, int nIndents ) const
  176. {
  177. // table name at first
  178. pstr->sprintf( "Table %s:\n", this->GetName() );
  179. // for each of the indexes ...
  180. for ( int n = 0; n < m_VecIndexes.Count(); n++ )
  181. {
  182. const FieldSet_t& fs = m_VecIndexes[n];
  183. // indent enough
  184. for ( int x = 0; x < nIndents; x++ )
  185. {
  186. pstr->Append( "\t" );
  187. }
  188. // show if it is clustered or not
  189. pstr->AppendFormat( "Index %d (%s): %sclustered, %sunique {", n,
  190. fs.GetIndexName(),
  191. fs.IsClustered() ? "" : "non-",
  192. fs.IsUnique() ? "" : "non-" );
  193. // then show all the columns
  194. for (int m = 0; m < fs.GetCount(); m++ )
  195. {
  196. int x = fs.GetField( m );
  197. const char* pstrName = m_VecColumnInfo[x].GetName();
  198. pstr->AppendFormat( "%s %s", ( m == 0 ) ? "" : ",", pstrName );
  199. }
  200. // then the included columns, too
  201. for ( int m = 0; m < fs.GetIncludedCount(); m++ )
  202. {
  203. int x = fs.GetIncludedField( m );
  204. const char* pstrName = m_VecColumnInfo[x].GetName();
  205. pstr->AppendFormat( ", *%s", pstrName );
  206. }
  207. pstr->Append( " }\n" );
  208. }
  209. return;
  210. }
  211. //-----------------------------------------------------------------------------
  212. // Purpose: Get the number of foreign key constraints defined for the table
  213. //-----------------------------------------------------------------------------
  214. int CRecordInfo::GetFKCount()
  215. {
  216. return m_VecFKData.Count();
  217. }
  218. //-----------------------------------------------------------------------------
  219. // Purpose: Get data for a foreign key by index (valid for 0...GetFKCount()-1)
  220. //-----------------------------------------------------------------------------
  221. FKData_t &CRecordInfo::GetFKData( int iIndex )
  222. {
  223. return m_VecFKData[iIndex];
  224. }
  225. //-----------------------------------------------------------------------------
  226. // Purpose: format the FK list into a string
  227. //-----------------------------------------------------------------------------
  228. void CRecordInfo::GetFKListString( CFmtStr1024 *pstr, int nIndents )
  229. {
  230. // table name at first
  231. pstr->sprintf( "Table %s Foreign Keys: \n", this->GetName() );
  232. if ( m_VecFKData.Count() == 0 )
  233. {
  234. // indent enough
  235. pstr->AppendIndent( nIndents );
  236. pstr->Append( "No foreign keys for table\n" );
  237. }
  238. else
  239. {
  240. for ( int n = 0; n < m_VecFKData.Count(); n++ )
  241. {
  242. // indent enough
  243. pstr->AppendIndent( nIndents );
  244. FKData_t &fkData = m_VecFKData[n];
  245. CFmtStr sColumns, sParentColumns;
  246. FOR_EACH_VEC( fkData.m_VecColumnRelations, i )
  247. {
  248. FKColumnRelation_t &colRelation = fkData.m_VecColumnRelations[i];
  249. if ( i > 0)
  250. {
  251. sColumns += ",";
  252. sParentColumns += ",";
  253. }
  254. sColumns += colRelation.m_rgchCol;
  255. sParentColumns += colRelation.m_rgchParentCol;
  256. }
  257. pstr->AppendFormat( "CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s(%s) ON DELETE %s ON UPDATE %s\n",
  258. fkData.m_rgchName, sColumns.Access(), fkData.m_rgchParentTableName, sParentColumns.Access(),
  259. PchNameFromEForeignKeyAction( fkData.m_eOnDeleteAction ), PchNameFromEForeignKeyAction( fkData.m_eOnUpdateAction ) );
  260. }
  261. }
  262. return;
  263. }
  264. //-----------------------------------------------------------------------------
  265. //-----------------------------------------------------------------------------
  266. void CRecordInfo::AddFTSFields( CUtlVector< int > &vecFields )
  267. {
  268. AssertMsg( m_vecFTSFields.Count() == 0, "Only one FTS index per table" );
  269. FOR_EACH_VEC( vecFields, n )
  270. {
  271. int nField = vecFields[n];
  272. m_vecFTSFields.AddToTail( nField );
  273. }
  274. return;
  275. }
  276. //-----------------------------------------------------------------------------
  277. // Purpose: compares FK lists in this record with those of another
  278. //-----------------------------------------------------------------------------
  279. bool CRecordInfo::CompareFKs( CRecordInfo *pOther )
  280. {
  281. if ( pOther->m_VecFKData.Count() != m_VecFKData.Count() )
  282. return false;
  283. for( int i=0; i < m_VecFKData.Count(); ++i )
  284. {
  285. FKData_t &fkDataMine = m_VecFKData[i];
  286. bool bFoundInOther = false;
  287. for ( int j=0; j < pOther->m_VecFKData.Count(); ++j )
  288. {
  289. FKData_t &fkDataOther = pOther->m_VecFKData[j];
  290. if ( fkDataMine == fkDataOther )
  291. {
  292. bFoundInOther = true;
  293. break;
  294. }
  295. }
  296. if ( !bFoundInOther )
  297. return false;
  298. }
  299. return true;
  300. }
  301. //-----------------------------------------------------------------------------
  302. // Purpose: Locate an index by its properties (ignoring the name).
  303. // Returns position of index in the index array, or -1 if not found.
  304. //-----------------------------------------------------------------------------
  305. int CRecordInfo::FindIndex( CRecordInfo *pRec, const FieldSet_t& fieldSet )
  306. {
  307. for ( int i = 0; i < m_VecIndexes.Count(); i++ )
  308. {
  309. if ( FieldSet_t::CompareFieldSets( m_VecIndexes[i], this, fieldSet, pRec ) )
  310. return i;
  311. }
  312. // Not found
  313. return -1;
  314. }
  315. //-----------------------------------------------------------------------------
  316. // Purpose: Locate an index with the given name.
  317. // Returns position of index in the index array, or -1 if not found.
  318. //-----------------------------------------------------------------------------
  319. int CRecordInfo::FindIndexByName( const char *pszName ) const
  320. {
  321. for ( int i = 0; i < m_VecIndexes.Count(); i++ )
  322. {
  323. if ( V_stricmp( m_VecIndexes[i].GetIndexName(), pszName )== 0 )
  324. return i;
  325. }
  326. // Not found
  327. return -1;
  328. }
  329. //-----------------------------------------------------------------------------
  330. // Purpose: compares index lists in this record with those of another
  331. //-----------------------------------------------------------------------------
  332. bool CRecordInfo::CompareIndexLists( CRecordInfo* pOther )
  333. {
  334. // compare the index lists (but don't use CRCs)
  335. // different size? can't be the same
  336. if ( pOther->GetIndexFieldCount() != GetIndexFieldCount() )
  337. {
  338. return false;
  339. }
  340. // We have to loop through both lists of indexes and try to find a match.
  341. // We also must make sure the match is exact, and that no previous match
  342. // can alias another attempt at a match. Pretty messy, but with no available
  343. // identity over index objects, we're forced to a suboptimal solution.
  344. int nIndexes = GetIndexFieldCount();
  345. // get a copy of the other index vector, which we'll remove items from as
  346. // matches are found.
  347. CUtlVector<FieldSet_t> vecOtherIndexes;
  348. vecOtherIndexes.CopyArray( pOther->GetIndexFields().Base(), nIndexes );
  349. for ( int nOurs = 0; nOurs < nIndexes; nOurs++ )
  350. {
  351. int nOtherMatchIndex = -1;
  352. const FieldSet_t& refOurs = GetIndexFields()[nOurs];
  353. // rip through copy of other to find one that matches
  354. for ( int nOther = 0; nOther < vecOtherIndexes.Count(); nOther++ )
  355. {
  356. const FieldSet_t& refOther = vecOtherIndexes[nOther];
  357. if ( FieldSet_t::CompareFieldSets( refOurs, this, refOther, pOther ) )
  358. {
  359. nOtherMatchIndex = nOther;
  360. break;
  361. }
  362. }
  363. if ( nOtherMatchIndex >= 0 )
  364. {
  365. // this works! remove it from other copy
  366. vecOtherIndexes.Remove( nOtherMatchIndex );
  367. }
  368. else
  369. {
  370. // something didn't match, so bail out early
  371. return false;
  372. }
  373. }
  374. return true;
  375. }
  376. //-----------------------------------------------------------------------------
  377. // Purpose: compares full-text indexes for this record with those of another
  378. // column order in an FTS is irrelevant, so this is a simple match
  379. //-----------------------------------------------------------------------------
  380. bool CRecordInfo::CompareFTSIndexLists( CRecordInfo* pOther ) const
  381. {
  382. // compare full-text index columns
  383. if ( m_vecFTSFields.Count() != pOther->m_vecFTSFields.Count() )
  384. {
  385. // counts don't match, so obviously no good
  386. return false;
  387. }
  388. for ( int nColumnIndex = 0; nColumnIndex < m_vecFTSFields.Count(); nColumnIndex++ )
  389. {
  390. bool bFound = false;
  391. for ( int nInnerIndex = 0; nInnerIndex < pOther->m_vecFTSFields.Count(); nInnerIndex++ )
  392. {
  393. if ( m_vecFTSFields[nInnerIndex] == pOther->m_vecFTSFields[nColumnIndex] )
  394. {
  395. bFound = true;
  396. break;
  397. }
  398. }
  399. if ( !bFound )
  400. return false;
  401. }
  402. return true;
  403. }
  404. //-----------------------------------------------------------------------------
  405. // Purpose: Returns the checksum for this record info
  406. //-----------------------------------------------------------------------------
  407. int CRecordInfo::GetChecksum()
  408. {
  409. Assert( m_bPreparedForUse );
  410. // calculate it now if we haven't already
  411. if ( !m_bHaveChecksum )
  412. CalculateChecksum();
  413. return m_nChecksum;
  414. }
  415. //-----------------------------------------------------------------------------
  416. // Purpose: Prepares this object for use after all columns have been added
  417. //-----------------------------------------------------------------------------
  418. void CRecordInfo::PrepareForUse()
  419. {
  420. Assert( !m_bPreparedForUse );
  421. Assert( 0 == m_cubFixedSize );
  422. Assert( 0 == m_nChecksum );
  423. SetAllColumnsAdded();
  424. FOR_EACH_VEC( m_VecColumnInfo, nColumn )
  425. {
  426. CColumnInfo &columnInfo = m_VecColumnInfo[nColumn];
  427. // keep track of total fixed size of all columns
  428. if ( !columnInfo.BIsVariableLength() )
  429. m_cubFixedSize += columnInfo.GetFixedSize();
  430. if ( columnInfo.BIsPrimaryKey() )
  431. {
  432. // a PK column! if we have seen one before,
  433. // know we have a-column PK; otherwise, a single column PK
  434. if (m_nHasPrimaryKey == k_EPrimaryKeyTypeNone)
  435. m_nHasPrimaryKey = k_EPrimaryKeyTypeSingle;
  436. else
  437. m_nHasPrimaryKey = k_EPrimaryKeyTypeMulti;
  438. }
  439. }
  440. // make sure count matches the enum
  441. /*
  442. Assert( ( m_nHasPrimaryKey == k_EPrimaryKeyTypeNone && m_VecPKFields.Count() == 0 ) ||
  443. ( m_nHasPrimaryKey == k_EPrimaryKeyTypeMulti && m_VecPKFields.Count() > 1) ||
  444. ( m_nHasPrimaryKey == k_EPrimaryKeyTypeSingle && m_VecPKFields.Count() == 1) );
  445. */
  446. m_bPreparedForUse = true;
  447. }
  448. //-----------------------------------------------------------------------------
  449. // Purpose: Returns index of column with specified name
  450. // Input: pchName - column name
  451. // punColumn - pointer to fill in with index
  452. // Output: return true if found, false otherwise
  453. //-----------------------------------------------------------------------------
  454. bool CRecordInfo::BFindColumnByName( const char *pchName, int *punColumn )
  455. {
  456. Assert( m_bAllColumnsAdded );
  457. Assert( pchName && *pchName );
  458. Assert( punColumn );
  459. *punColumn = -1;
  460. // if we haven't already built the name index, build it now
  461. if ( !m_bHaveColumnNameIndex )
  462. BuildColumnNameIndex();
  463. *punColumn = m_MapIColumnInfo.Find( pchName );
  464. return ( m_MapIColumnInfo.InvalidIndex() != *punColumn );
  465. }
  466. //-----------------------------------------------------------------------------
  467. // Purpose: Sets the name of this record info
  468. // Input: pchName - name
  469. // Notes: record info that describes a table will have a name (the table name);
  470. // record info that describes a result set will not
  471. //-----------------------------------------------------------------------------
  472. void CRecordInfo::SetName( const char *pchName )
  473. {
  474. Assert( pchName && *pchName );
  475. Assert( !m_bPreparedForUse ); // don't change this after prepared for use
  476. Q_strncpy( m_rgchName, pchName, Q_ARRAYSIZE( m_rgchName ) );
  477. }
  478. //-----------------------------------------------------------------------------
  479. // Purpose: Builds the column name index for fast lookup by name
  480. //-----------------------------------------------------------------------------
  481. void CRecordInfo::BuildColumnNameIndex()
  482. {
  483. AUTO_LOCK( m_Mutex );
  484. if ( m_bHaveColumnNameIndex )
  485. return;
  486. Assert( m_bAllColumnsAdded );
  487. Assert( 0 == m_MapIColumnInfo.Count() );
  488. FOR_EACH_VEC( m_VecColumnInfo, nColumn )
  489. {
  490. // build name->column index map
  491. CColumnInfo &columnInfo = m_VecColumnInfo[nColumn];
  492. m_MapIColumnInfo.Insert( columnInfo.GetName(), nColumn );
  493. }
  494. m_bHaveColumnNameIndex = true;
  495. }
  496. //-----------------------------------------------------------------------------
  497. // Purpose: Calculates the checksum for this record info
  498. //-----------------------------------------------------------------------------
  499. void CRecordInfo::CalculateChecksum()
  500. {
  501. AUTO_LOCK( m_Mutex );
  502. if ( m_bHaveChecksum )
  503. return;
  504. // build the column name index if necessary
  505. if ( !m_bHaveColumnNameIndex )
  506. BuildColumnNameIndex();
  507. CRC32_t crc32;
  508. CRC32_Init( &crc32 );
  509. FOR_EACH_MAP( m_MapIColumnInfo, iMapItem )
  510. {
  511. uint32 unColumn = m_MapIColumnInfo[iMapItem];
  512. CColumnInfo &columnInfo = m_VecColumnInfo[unColumn];
  513. // calculate checksum of all of our columns
  514. columnInfo.CalculateChecksum();
  515. int nChecksum = columnInfo.GetChecksum();
  516. CRC32_ProcessBuffer( &crc32, (void*) &nChecksum, sizeof( nChecksum ) );
  517. }
  518. // keep checksum for entire record info
  519. CRC32_Final( &crc32 );
  520. m_nChecksum = crc32;
  521. m_bHaveChecksum = true;
  522. }
  523. //-----------------------------------------------------------------------------
  524. // Purpose: add another index disallowing duplicates. If a duplicate item is
  525. // found, we'll set the flags on the new item from the existing one.
  526. //-----------------------------------------------------------------------------
  527. int CRecordInfo::AddIndex( const FieldSet_t& fieldSet )
  528. {
  529. for ( int n = 0; n < m_VecIndexes.Count(); n++ )
  530. {
  531. FieldSet_t& fs = m_VecIndexes[n];
  532. if ( FieldSet_t::CompareFieldSets( fieldSet, this, fs, this ) )
  533. {
  534. fs.SetClustered( fs.IsClustered() );
  535. return -1;
  536. }
  537. }
  538. int nRet = m_VecIndexes.AddToTail( fieldSet );
  539. return nRet;
  540. }
  541. //-----------------------------------------------------------------------------
  542. // Purpose: Returns true if there is an IDENTITY column in the record info
  543. //-----------------------------------------------------------------------------
  544. bool CRecordInfo::BHasIdentity() const
  545. {
  546. FOR_EACH_VEC( m_VecColumnInfo, nColumn)
  547. {
  548. if( m_VecColumnInfo[nColumn].BIsAutoIncrement() )
  549. return true;
  550. }
  551. return false;
  552. }
  553. //-----------------------------------------------------------------------------
  554. // Purpose: Constructor
  555. //-----------------------------------------------------------------------------
  556. CColumnInfo::CColumnInfo()
  557. {
  558. m_rgchName[0] = 0;
  559. m_nSQLColumn = 0;
  560. m_eType = k_EGCSQLTypeInvalid;
  561. m_nColFlags = 0;
  562. m_cubFixedSize = 0;
  563. m_cchMaxSize = 0;
  564. m_nChecksum = 0;
  565. m_bHaveChecksum = false;
  566. }
  567. //-----------------------------------------------------------------------------
  568. // Purpose: Sets column info for this column
  569. // Input: pchName - column name
  570. // nSQLColumn - column index in SQL to bind to (1-based)
  571. // eType - data type of column
  572. // cubFixedSize - for fixed-size fields, the size
  573. // nColFlags - attributes
  574. //-----------------------------------------------------------------------------
  575. void CColumnInfo::Set( const char *pchName, int nSQLColumn, EGCSQLType eType, int cubFixedSize, int nColFlags, int cchMaxSize )
  576. {
  577. Assert( !m_rgchName[0] );
  578. Q_strncpy( m_rgchName, pchName, Q_ARRAYSIZE( m_rgchName ) );
  579. m_nSQLColumn = nSQLColumn;
  580. m_eType = eType;
  581. m_nColFlags = nColFlags;
  582. ValidateColFlags();
  583. if ( !BIsVariableLength() )
  584. {
  585. Assert( cubFixedSize > 0 );
  586. m_cubFixedSize = cubFixedSize;
  587. m_cchMaxSize = 0;
  588. }
  589. else
  590. {
  591. // it's variable length, so we need a max length
  592. m_cchMaxSize = cchMaxSize;
  593. m_cubFixedSize = 0;
  594. }
  595. }
  596. //-----------------------------------------------------------------------------
  597. // Purpose: returns whether this column is variable length
  598. //-----------------------------------------------------------------------------
  599. bool CColumnInfo::BIsVariableLength() const
  600. {
  601. return m_eType == k_EGCSQLType_Blob || m_eType == k_EGCSQLType_String || m_eType == k_EGCSQLType_Image;
  602. }
  603. //-----------------------------------------------------------------------------
  604. // Purpose: convert column flags to a visible representation
  605. //-----------------------------------------------------------------------------
  606. void CColumnInfo::GetColFlagDescription( char* pstrOut, int cubOutLength ) const
  607. {
  608. if ( m_nColFlags == 0 )
  609. Q_strncpy( pstrOut, "(none)", cubOutLength );
  610. else
  611. {
  612. pstrOut[0] = 0;
  613. if ( m_nColFlags & k_nColFlagIndexed )
  614. Q_strncat( pstrOut, "(Indexed)", cubOutLength );
  615. if ( m_nColFlags & k_nColFlagUnique )
  616. Q_strncat( pstrOut, "(Unique)", cubOutLength );
  617. if ( m_nColFlags & k_nColFlagPrimaryKey )
  618. Q_strncat( pstrOut, "(PrimaryKey)", cubOutLength );
  619. if ( m_nColFlags & k_nColFlagAutoIncrement )
  620. Q_strncat( pstrOut, "(AutoIncrement)", cubOutLength );
  621. if ( m_nColFlags & k_nColFlagClustered )
  622. Q_strncat( pstrOut, "(Clustered)", cubOutLength );
  623. }
  624. return;
  625. }
  626. //-----------------------------------------------------------------------------
  627. // Purpose: sets column flag bits
  628. // Input: nColFlag - bits to set. (Other bits are not cleared.)
  629. //-----------------------------------------------------------------------------
  630. void CColumnInfo::SetColFlagBits( int nColFlag )
  631. {
  632. ValidateColFlags();
  633. m_nColFlags |= nColFlag; // set these bits
  634. ValidateColFlags();
  635. }
  636. //-----------------------------------------------------------------------------
  637. // Purpose: Calculates the checksum for this column
  638. //-----------------------------------------------------------------------------
  639. void CColumnInfo::CalculateChecksum()
  640. {
  641. if ( m_bHaveChecksum )
  642. return;
  643. // calculate checksum of this column for easy comparsion
  644. CRC32_t crc32;
  645. CRC32_Init( &crc32 );
  646. CRC32_ProcessBuffer( &crc32, (void*) m_rgchName, Q_strlen( m_rgchName ) );
  647. CRC32_ProcessBuffer( &crc32, (void*) &m_nColFlags, sizeof( m_nColFlags ) );
  648. CRC32_ProcessBuffer( &crc32, (void*) &m_eType, sizeof( m_eType ) );
  649. CRC32_ProcessBuffer( &crc32, (void*) &m_cubFixedSize, sizeof( m_cubFixedSize ) );
  650. CRC32_ProcessBuffer( &crc32, (void*) &m_cchMaxSize, sizeof( m_cchMaxSize ) );
  651. CRC32_Final( &crc32 );
  652. m_nChecksum = crc32;
  653. m_bHaveChecksum = true;
  654. }
  655. //-----------------------------------------------------------------------------
  656. // determine if this CColumnInfo is the same as the referenced
  657. //-----------------------------------------------------------------------------
  658. bool CColumnInfo::operator==( const CColumnInfo& refOther ) const
  659. {
  660. if ( m_eType != refOther.m_eType )
  661. return false;
  662. if ( m_cubFixedSize != refOther.m_cubFixedSize )
  663. return false;
  664. if ( m_cchMaxSize != refOther.m_cchMaxSize )
  665. return false;
  666. if ( m_nColFlags != refOther.m_nColFlags )
  667. return false;
  668. if ( 0 != Q_strcmp( m_rgchName, refOther.m_rgchName ) )
  669. return false;
  670. return true;
  671. }
  672. //-----------------------------------------------------------------------------
  673. // Purpose: Validates that column flags are set in valid combinations
  674. //-----------------------------------------------------------------------------
  675. void CColumnInfo::ValidateColFlags() const
  676. {
  677. // Check that column flags follow rules about how columns get expressed in SQL
  678. if ( m_nColFlags & k_nColFlagPrimaryKey )
  679. {
  680. // a primary key must also be unique and indexed
  681. Assert( m_nColFlags & k_nColFlagUnique );
  682. Assert( m_nColFlags & k_nColFlagIndexed );
  683. }
  684. // a column with uniqueness constraint must also be indexed
  685. if ( m_nColFlags & k_nColFlagUnique )
  686. Assert( m_nColFlags & k_nColFlagIndexed );
  687. }
  688. CRecordInfo *CRecordInfo::Alloc()
  689. {
  690. CRecordInfo *pRecordInfo = sm_MemPoolRecordInfo.Alloc();
  691. #ifdef _DEBUG
  692. AUTO_LOCK( sm_mutexMemPoolRecordInfo );
  693. sm_mapPMemPoolRecordInfo.Insert( pRecordInfo );
  694. #endif
  695. return pRecordInfo;
  696. }
  697. void CRecordInfo::DestroyThis()
  698. {
  699. #ifdef _DEBUG
  700. AUTO_LOCK( sm_mutexMemPoolRecordInfo );
  701. sm_mapPMemPoolRecordInfo.Remove( this );
  702. #endif
  703. sm_MemPoolRecordInfo.Free( this );
  704. }
  705. #ifdef DBGFLAG_VALIDATE
  706. void CRecordInfo::ValidateStatics( CValidator &validator, const char *pchName )
  707. {
  708. VALIDATE_SCOPE_STATIC( "CRecordInfo class statics" );
  709. ValidateObj( sm_MemPoolRecordInfo );
  710. #ifdef _DEBUG
  711. AUTO_LOCK( sm_mutexMemPoolRecordInfo );
  712. ValidateObj( sm_mapPMemPoolRecordInfo );
  713. FOR_EACH_MAP_FAST( sm_mapPMemPoolRecordInfo, i )
  714. {
  715. sm_mapPMemPoolRecordInfo[i]->Validate( validator, "sm_mapPMemPoolRecordInfo[i]" );
  716. }
  717. #endif
  718. }
  719. void CRecordInfo::Validate( CValidator &validator, const char *pchName )
  720. {
  721. VALIDATE_SCOPE();
  722. m_VecIndexes.Validate( validator, "m_VecIndexes" );
  723. ValidateObj( m_VecFKData );
  724. FOR_EACH_VEC( m_VecFKData, i )
  725. {
  726. ValidateObj( m_VecFKData[i] );
  727. }
  728. for ( int iIndex = 0; iIndex < m_VecIndexes.Count(); iIndex++ )
  729. {
  730. ValidateObj( m_VecIndexes[iIndex] );
  731. }
  732. ValidateObj( m_vecFTSFields );
  733. ValidateObj( m_VecColumnInfo );
  734. FOR_EACH_VEC( m_VecColumnInfo, nColumn )
  735. {
  736. CColumnInfo &columnInfo = GetColumnInfo( nColumn );
  737. ValidateObj( columnInfo );
  738. }
  739. ValidateObj( m_MapIColumnInfo );
  740. }
  741. void CColumnInfo::Validate( CValidator &validator, const char *pchName )
  742. {
  743. VALIDATE_SCOPE();
  744. }
  745. #endif // DBGFLAG_VALIDATE
  746. } // namespace GCSDK