Source code of Windows XP (NT5)
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.

397 lines
14 KiB

  1. //--------------------------------------------------------------------
  2. // Microsoft OLE-DB Monarch
  3. //
  4. // Copyright 1997 Microsoft Corporation. All Rights Reserved.
  5. //
  6. // @doc
  7. //
  8. // @module colname.cpp |
  9. //
  10. // Contains utility functions for maintaining property lists (symbol table?)
  11. //
  12. // @rev 0 | 12-Feb-97 | v-charca | Created
  13. // 1 | 24-Oct-98 | danleg | cleanup
  14. //
  15. #pragma hdrstop
  16. #include "msidxtr.h"
  17. const BYTE randomNumbers[] =
  18. { // Pseudorandom Permutation of the Integers 0 through 255: CACM 33 6 p678
  19. 1, 87, 49, 12, 176, 178, 102, 166, 121, 193, 6, 84, 249, 230, 44, 163,
  20. 14, 197, 213, 181, 161, 85, 218, 80, 64, 239, 24, 226, 236, 142, 38, 200,
  21. 110, 177, 104, 103, 141, 253, 255, 50, 77, 101, 81, 18, 45, 96, 31, 222,
  22. 25, 107, 190, 70, 86, 237, 240, 34, 72, 242, 20, 214, 244, 227, 149, 235,
  23. 97, 234, 57, 22, 60, 250, 82, 175, 208, 5, 127, 199, 111, 62, 135, 248,
  24. 174, 169, 211, 58, 66, 154, 106, 195, 245, 171, 17, 187, 182, 179, 0, 243,
  25. 132, 56, 148, 75, 128, 133, 158, 100, 130, 126, 91, 13, 153, 246, 216, 219,
  26. 119, 68, 223, 78, 83, 88, 201, 99, 122, 11, 92, 32, 136, 114, 52, 10,
  27. 138, 30, 48, 183, 156, 35, 61, 26, 143, 74, 251, 94, 129, 162, 63, 152,
  28. 170, 7, 115, 167, 241, 206, 3, 150, 55, 59, 151, 220, 90, 53, 23, 131,
  29. 125, 173, 15, 238, 79, 95, 89, 16, 105, 137, 225, 224, 217, 160, 37, 123,
  30. 118, 73, 2, 157, 46, 116, 9, 145, 134, 228, 207, 212, 202, 215, 69, 229,
  31. 27, 188, 67, 124, 168, 252, 42, 4, 29, 108, 21, 247, 19, 205, 39, 203,
  32. 233, 40, 186, 147, 198, 192, 155, 33, 164, 191, 98, 204, 165, 180, 117, 76,
  33. 140, 36, 210, 172, 41, 54, 159, 8, 185, 232, 113, 196, 231, 47, 146, 120,
  34. 51, 65, 28, 144, 254, 221, 93, 189, 194, 139, 112, 43, 71, 109, 184, 209
  35. };
  36. //-----------------------------------------------------------------------------
  37. // @mfunc Constructor
  38. //
  39. // @side No designed side effects.
  40. //
  41. //-----------------------------------------------------------------------------
  42. CPropertyList::CPropertyList(
  43. CPropertyList** ppGlobalPropertyList // in | caller's property list
  44. ) : m_aBucket( 47 ), // number of hash buckets (PRIME!)
  45. m_cMaxBucket( 47 ),
  46. m_ppGlobalPropertyList( ppGlobalPropertyList )
  47. {
  48. RtlZeroMemory( m_aBucket.Get(), m_aBucket.SizeOf() );
  49. }
  50. //-----------------------------------------------------------------------------
  51. // @mfunc Constructor
  52. //
  53. // @side No designed side effects.
  54. //
  55. //-----------------------------------------------------------------------------
  56. CPropertyList::~CPropertyList()
  57. {
  58. // delete the hash table
  59. for (int i=0; i<m_cMaxBucket; i++)
  60. {
  61. tagHASHENTRY* pHashEntry = m_aBucket[i];
  62. tagHASHENTRY* pNextHashEntry = NULL;
  63. while (NULL != pHashEntry)
  64. {
  65. delete [] pHashEntry->wcsFriendlyName;
  66. if ( DBKIND_GUID_NAME == pHashEntry->dbCol.eKind )
  67. delete [] pHashEntry->dbCol.uName.pwszName;
  68. pNextHashEntry = pHashEntry->pNextHashEntry;
  69. delete [] pHashEntry;
  70. pHashEntry = pNextHashEntry;
  71. }
  72. }
  73. }
  74. /* Hashing function described in */
  75. /* "Fast Hashing of Variable-Length Text Strings," */
  76. /* by Peter K. Pearson, CACM, June 1990. */
  77. inline UINT CPropertyList::GetHashValue(
  78. LPWSTR wszPropertyName //@parm IN | character string to hash
  79. )
  80. {
  81. int iHash = 0;
  82. char *szPropertyName = (char*) wszPropertyName;
  83. int cwch = wcslen(wszPropertyName)*2;
  84. for (int i=0; i<cwch; i++)
  85. iHash ^= randomNumbers[*szPropertyName++];
  86. return iHash % m_cMaxBucket;
  87. }
  88. //-----------------------------------------------------------------------------
  89. // @mfunc
  90. //
  91. // Method to create a property table to be used in a CITextToSelectTree call
  92. // (passthrough query). The global and local properties need to be stuffed
  93. // into a nice contiguous array.
  94. //
  95. // @side None
  96. // @rdesc CIPROPERTYDEF*
  97. //-----------------------------------------------------------------------------
  98. CIPROPERTYDEF* CPropertyList::GetPropertyTable(
  99. UINT * pcSize // @parm out | size of property table
  100. )
  101. {
  102. *pcSize = 0;
  103. for (int i=0; i<m_cMaxBucket; i++)
  104. {
  105. tagHASHENTRY* pHashEntry = (*m_ppGlobalPropertyList)->m_aBucket[i];
  106. while (NULL != pHashEntry)
  107. {
  108. pHashEntry = pHashEntry->pNextHashEntry;
  109. (*pcSize)++;
  110. }
  111. }
  112. for (i=0; i<m_cMaxBucket; i++)
  113. {
  114. tagHASHENTRY* pHashEntry = m_aBucket[i];
  115. while (NULL != pHashEntry)
  116. {
  117. pHashEntry = pHashEntry->pNextHashEntry;
  118. (*pcSize)++;
  119. }
  120. }
  121. XArray<CIPROPERTYDEF> xCiPropTable( *pcSize );
  122. TRY
  123. {
  124. RtlZeroMemory( xCiPropTable.Get(), xCiPropTable.SizeOf() );
  125. *pcSize = 0;
  126. for ( i=0; i<m_cMaxBucket; i++ )
  127. {
  128. tagHASHENTRY* pHashEntry = (*m_ppGlobalPropertyList)->m_aBucket[i];
  129. while ( NULL != pHashEntry )
  130. {
  131. xCiPropTable[*pcSize].wcsFriendlyName = CopyString( pHashEntry->wcsFriendlyName );
  132. xCiPropTable[*pcSize].dbType = pHashEntry->dbType;
  133. xCiPropTable[*pcSize].dbCol = pHashEntry->dbCol;
  134. if ( DBKIND_GUID_NAME == pHashEntry->dbCol.eKind )
  135. xCiPropTable[*pcSize].dbCol.uName.pwszName = CopyString( pHashEntry->dbCol.uName.pwszName );
  136. else
  137. xCiPropTable[*pcSize].dbCol.uName.pwszName = pHashEntry->dbCol.uName.pwszName;
  138. pHashEntry = pHashEntry->pNextHashEntry;
  139. (*pcSize)++;
  140. }
  141. }
  142. for (i=0; i<m_cMaxBucket; i++)
  143. {
  144. tagHASHENTRY* pHashEntry = m_aBucket[i];
  145. while (NULL != pHashEntry)
  146. {
  147. xCiPropTable[*pcSize].wcsFriendlyName = CopyString( pHashEntry->wcsFriendlyName );
  148. xCiPropTable[*pcSize].dbType = pHashEntry->dbType;
  149. xCiPropTable[*pcSize].dbCol = pHashEntry->dbCol;
  150. if ( DBKIND_GUID_NAME == pHashEntry->dbCol.eKind )
  151. xCiPropTable[*pcSize].dbCol.uName.pwszName = CopyString( pHashEntry->dbCol.uName.pwszName );
  152. else
  153. xCiPropTable[*pcSize].dbCol.uName.pwszName = pHashEntry->dbCol.uName.pwszName;
  154. pHashEntry = pHashEntry->pNextHashEntry;
  155. (*pcSize)++;
  156. }
  157. }
  158. }
  159. CATCH( CException, e )
  160. {
  161. // free the table
  162. for ( unsigned i=0; i<xCiPropTable.Count(); i++ )
  163. {
  164. delete [] xCiPropTable[i].wcsFriendlyName;
  165. if ( DBKIND_GUID_NAME == xCiPropTable[i].dbCol.eKind )
  166. delete [] xCiPropTable[i].dbCol.uName.pwszName;
  167. }
  168. RETHROW();
  169. }
  170. END_CATCH
  171. return xCiPropTable.Acquire();
  172. }
  173. //-----------------------------------------------------------------------------
  174. // @mfunc
  175. //
  176. // Method to delete a property table used in a CITextToSelectTree call
  177. // (passthrough query).
  178. //
  179. // @side None
  180. // @rdesc HRESULT
  181. //-----------------------------------------------------------------------------
  182. void CPropertyList::DeletePropertyTable(
  183. CIPROPERTYDEF* pCiPropTable, // @parm in | property table to be deleted
  184. UINT cSize // @parm in | size of property table
  185. )
  186. {
  187. for ( UINT i=0; i<cSize; i++ )
  188. {
  189. delete [] pCiPropTable[i].wcsFriendlyName;
  190. if ( DBKIND_GUID_NAME == pCiPropTable[i].dbCol.eKind )
  191. delete [] pCiPropTable[i].dbCol.uName.pwszName;
  192. }
  193. delete pCiPropTable;
  194. }
  195. //-----------------------------------------------------------------------------
  196. // @mfunc
  197. //
  198. // Method to retrieve the pointer to the CIPROPERTYDEF element
  199. // associated with this wszPropertyName, or NULL if name is
  200. // not in the table
  201. //
  202. // @side None
  203. // @rdesc CIPROPERDEF*
  204. //-----------------------------------------------------------------------------
  205. HASHENTRY *CPropertyList::FindPropertyEntry(
  206. LPWSTR wszPropertyName,
  207. UINT *puHashValue
  208. )
  209. {
  210. HASHENTRY *pHashEntry = NULL;
  211. *puHashValue = GetHashValue(wszPropertyName);
  212. for (pHashEntry = m_aBucket[*puHashValue]; pHashEntry; pHashEntry = pHashEntry->pNextHashEntry)
  213. {
  214. if ( (*puHashValue==pHashEntry->wHashValue) &&
  215. (_wcsicmp(wszPropertyName, pHashEntry->wcsFriendlyName)==0) )
  216. return pHashEntry;
  217. }
  218. return NULL;
  219. }
  220. //-----------------------------------------------------------------------------
  221. // @mfunc
  222. //
  223. // Method to retrieve the pointer to the CIPROPERTYDEF element
  224. // associated with this wszPropertyName, or NULL if name is
  225. // not in the table
  226. //
  227. // @side None
  228. // @rdesc CIPROPERDEF*
  229. //-----------------------------------------------------------------------------
  230. HASHENTRY *CPropertyList::GetPropertyEntry(
  231. LPWSTR wszPropertyName,
  232. UINT *puHashValue
  233. )
  234. {
  235. HASHENTRY *pHashEntry = NULL;
  236. if ( 0 != m_ppGlobalPropertyList && 0 != *m_ppGlobalPropertyList )
  237. {
  238. pHashEntry = (*m_ppGlobalPropertyList)->FindPropertyEntry( wszPropertyName, puHashValue );
  239. if ( 0 != pHashEntry )
  240. return pHashEntry;
  241. }
  242. pHashEntry = FindPropertyEntry( wszPropertyName, puHashValue );
  243. return pHashEntry;
  244. }
  245. //--------------------------------------------------------------------
  246. // @mfunc
  247. //
  248. // Method to retrieve the pointer to the CIPROPERTYDEF element
  249. // associated with this wszPropertyName, or NULL if name is
  250. // not in the table
  251. //
  252. // @side None
  253. // @rdesc HRESULT
  254. // S_OK successfull operation
  255. // E_FAIL property isn't defined
  256. // E_INVALIDARG ppct or pdbType was null
  257. // E_OUTOFMEMORY just what it says
  258. //--------------------------------------------------------------------
  259. HRESULT CPropertyList::LookUpPropertyName(
  260. LPWSTR wszPropertyName, // @parm IN
  261. DBCOMMANDTREE** ppct, // @parm OUT
  262. DBTYPE* pdbType // @parm OUT
  263. )
  264. {
  265. UINT uHashValue;
  266. if ( 0 == ppct || 0 == pdbType)
  267. return E_INVALIDARG;
  268. HASHENTRY *pHashEntry = GetPropertyEntry(wszPropertyName, &uHashValue);
  269. if ( 0 != pHashEntry )
  270. {
  271. *pdbType = (DBTYPE)pHashEntry->dbType;
  272. *ppct = PctCreateNode(DBOP_column_name, DBVALUEKIND_ID, NULL);
  273. if ( 0 != *ppct )
  274. {
  275. (*ppct)->value.pdbidValue->eKind = pHashEntry->dbCol.eKind;
  276. (*ppct)->value.pdbidValue->uGuid.guid = pHashEntry->dbCol.uGuid.guid;
  277. if ( DBKIND_GUID_NAME == pHashEntry->dbCol.eKind )
  278. (*ppct)->value.pdbidValue->uName.pwszName = CoTaskStrDup( pHashEntry->dbCol.uName.pwszName );
  279. else
  280. {
  281. Assert( DBKIND_GUID_PROPID == pHashEntry->dbCol.eKind );
  282. (*ppct)->value.pdbidValue->uName.pwszName = pHashEntry->dbCol.uName.pwszName;
  283. }
  284. return S_OK;
  285. }
  286. else
  287. return E_OUTOFMEMORY;
  288. }
  289. else
  290. return E_FAIL;
  291. }
  292. //-----------------------------------------------------------------------------
  293. // @func SetPropertyEntry
  294. //
  295. // Insert the specified property into the symbol table.
  296. // If it is already there, redefine its value.
  297. //
  298. // @rdesc HRESULT
  299. // @flag S_OK | ok
  300. // @flag E_OUTOFMEMORY | out of memory
  301. //-----------------------------------------------------------------------------
  302. HRESULT CPropertyList::SetPropertyEntry(
  303. LPWSTR wcsFriendlyName, // @parm IN | name of property
  304. DWORD dbType, // @parm IN | dbtype of property
  305. GUID guid, // @parm IN | GUID defining the property
  306. DBKIND eKind, // @parm IN | type of PropId (currently GUID_NAME or GUID_PROPID)
  307. LPWSTR pwszPropName, // @parm IN | either a name or propid
  308. BOOL fGlobal ) // @parm IN | TRUE if global definition; FALSE if local
  309. {
  310. SCODE sc = S_OK;
  311. TRY
  312. {
  313. UINT uhash=0;
  314. HASHENTRY* pHashEntry = GetPropertyEntry(wcsFriendlyName, &uhash);
  315. if ( 0 != pHashEntry )
  316. {
  317. // Redefining a user defined property.
  318. // Delete the old property definition.
  319. if ( DBKIND_GUID_NAME == pHashEntry->dbCol.eKind )
  320. {
  321. XPtrST<WCHAR> xName( CopyString(pwszPropName) );
  322. delete [] pHashEntry->dbCol.uName.pwszName;
  323. pHashEntry->dbCol.uName.pwszName = xName.Acquire();
  324. }
  325. pHashEntry->dbType = dbType;
  326. pHashEntry->dbCol.uGuid.guid = guid;
  327. pHashEntry->dbCol.eKind = eKind;
  328. }
  329. else
  330. {
  331. XPtr<HASHENTRY> xHashEntry( new HASHENTRY );
  332. xHashEntry->wHashValue = uhash;
  333. XPtrST<WCHAR> xName( CopyString(wcsFriendlyName) );
  334. xHashEntry->dbType = dbType;
  335. xHashEntry->dbCol.uGuid.guid = guid;
  336. xHashEntry->dbCol.eKind = eKind;
  337. if ( DBKIND_GUID_NAME == eKind )
  338. xHashEntry->dbCol.uName.pwszName = CopyString( pwszPropName );
  339. else
  340. xHashEntry->dbCol.uName.pwszName = pwszPropName;
  341. xHashEntry->wcsFriendlyName = xName.Acquire();
  342. xHashEntry->pNextHashEntry = m_aBucket[uhash]; // Add to head of singly-linked list
  343. m_aBucket[uhash] = xHashEntry.Acquire();
  344. }
  345. }
  346. CATCH( CException, e )
  347. {
  348. sc = e.GetErrorCode();
  349. }
  350. END_CATCH
  351. return sc;
  352. } // SetPropertyEntry