Leaked source code of windows server 2003
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.

409 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. {
  279. WCHAR * pwcName = CoTaskStrDup( pHashEntry->dbCol.uName.pwszName );
  280. if ( 0 == pwcName )
  281. {
  282. (*ppct)->value.pdbidValue->eKind = DBKIND_GUID_PROPID;
  283. DeleteDBQT( *ppct );
  284. *ppct = 0;
  285. return E_OUTOFMEMORY;
  286. }
  287. (*ppct)->value.pdbidValue->uName.pwszName = pwcName;
  288. }
  289. else
  290. {
  291. Assert( DBKIND_GUID_PROPID == pHashEntry->dbCol.eKind );
  292. (*ppct)->value.pdbidValue->uName.pwszName = pHashEntry->dbCol.uName.pwszName;
  293. }
  294. return S_OK;
  295. }
  296. else
  297. return E_OUTOFMEMORY;
  298. }
  299. else
  300. return E_FAIL;
  301. }
  302. //-----------------------------------------------------------------------------
  303. // @func SetPropertyEntry
  304. //
  305. // Insert the specified property into the symbol table.
  306. // If it is already there, redefine its value.
  307. //
  308. // @rdesc HRESULT
  309. // @flag S_OK | ok
  310. // @flag E_OUTOFMEMORY | out of memory
  311. //-----------------------------------------------------------------------------
  312. HRESULT CPropertyList::SetPropertyEntry(
  313. LPWSTR wcsFriendlyName, // @parm IN | name of property
  314. DWORD dbType, // @parm IN | dbtype of property
  315. GUID guid, // @parm IN | GUID defining the property
  316. DBKIND eKind, // @parm IN | type of PropId (currently GUID_NAME or GUID_PROPID)
  317. LPWSTR pwszPropName, // @parm IN | either a name or propid
  318. BOOL fGlobal ) // @parm IN | TRUE if global definition; FALSE if local
  319. {
  320. SCODE sc = S_OK;
  321. TRY
  322. {
  323. UINT uhash=0;
  324. HASHENTRY* pHashEntry = GetPropertyEntry(wcsFriendlyName, &uhash);
  325. if ( 0 != pHashEntry )
  326. {
  327. // Redefining a user defined property.
  328. // Delete the old property definition.
  329. if ( DBKIND_GUID_NAME == pHashEntry->dbCol.eKind )
  330. {
  331. XPtrST<WCHAR> xName( CopyString(pwszPropName) );
  332. delete [] pHashEntry->dbCol.uName.pwszName;
  333. pHashEntry->dbCol.uName.pwszName = xName.Acquire();
  334. }
  335. pHashEntry->dbType = dbType;
  336. pHashEntry->dbCol.uGuid.guid = guid;
  337. pHashEntry->dbCol.eKind = eKind;
  338. }
  339. else
  340. {
  341. XPtr<HASHENTRY> xHashEntry( new HASHENTRY );
  342. xHashEntry->wHashValue = uhash;
  343. XPtrST<WCHAR> xName( CopyString(wcsFriendlyName) );
  344. xHashEntry->dbType = dbType;
  345. xHashEntry->dbCol.uGuid.guid = guid;
  346. xHashEntry->dbCol.eKind = eKind;
  347. if ( DBKIND_GUID_NAME == eKind )
  348. xHashEntry->dbCol.uName.pwszName = CopyString( pwszPropName );
  349. else
  350. xHashEntry->dbCol.uName.pwszName = pwszPropName;
  351. xHashEntry->wcsFriendlyName = xName.Acquire();
  352. xHashEntry->pNextHashEntry = m_aBucket[uhash]; // Add to head of singly-linked list
  353. m_aBucket[uhash] = xHashEntry.Acquire();
  354. }
  355. }
  356. CATCH( CException, e )
  357. {
  358. sc = e.GetErrorCode();
  359. }
  360. END_CATCH
  361. return sc;
  362. } // SetPropertyEntry