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.

13291 lines
407 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2001.
  5. //
  6. // File: tdbv1.CXX
  7. //
  8. // Contents: Test program for OLE-DB phase 3 interface classes.
  9. //
  10. // TODO:
  11. // Large result sets
  12. //
  13. // History: 30 June 1994 Alanw Created (from cidrt)
  14. // 10 Nov. 1994 Alanw Converted for OLE-DB phase 3 interfaces
  15. // 01 Oct. 1996 Alanw Converted for OLE-DB V1.0 interfaces
  16. //
  17. //--------------------------------------------------------------------------
  18. #define DO_NOTIFICATION
  19. #define DO_CATEG_TESTS
  20. #define DO_CONTENT_TESTS
  21. #define DO_MULTI_LEVEL_CATEG_TEST
  22. extern "C"
  23. {
  24. #include <nt.h>
  25. #include <ntrtl.h>
  26. #include <nturtl.h>
  27. #include <olectl.h>
  28. }
  29. #include <windows.h>
  30. #if !defined(UNIT_TEST)
  31. #define DBINITCONSTANTS
  32. #if !defined(OLEDBVER)
  33. #define OLEDBVER 0x0250
  34. #endif // !OLEDBVER
  35. #endif // !UNIT_TEST
  36. #include <oledb.h>
  37. #include <oledberr.h>
  38. #include <ntquery.h>
  39. #include <query.h>
  40. #include <ciintf.h>
  41. #include <cierror.h>
  42. #include <stgprop.h>
  43. #include <vquery.hxx>
  44. #include <dbcmdtre.hxx>
  45. #include <crt\io.h>
  46. #include <stdlib.h>
  47. #include <stdio.h>
  48. #include <stddef.h>
  49. #include <string.h>
  50. #include <time.h>
  51. #include <process.h>
  52. #include <propapi.h>
  53. #include <propvar.h>
  54. #include <oleext.h>
  55. #include <initguid.h>
  56. #include <srvprvdr.h>
  57. #if defined(UNIT_TEST)
  58. #define PROG_NAME "tdbv1"
  59. //#include "tabledbg.hxx"
  60. #else // !UNIT_TEST
  61. #define PROG_NAME "fsdbdrt"
  62. #endif // UNIT_TEST
  63. #if defined(UNIT_TEST)
  64. #include <compare.hxx>
  65. #include <coldesc.hxx>
  66. #endif
  67. WCHAR *pwcThisMachine = L".";
  68. #define TEST_MACHINE ( pwcThisMachine )
  69. WCHAR const wcsDefaultTestCatalog[] = L"::_noindex_::";
  70. #define TEST_CATALOG ( wcsTestCatalog )
  71. WCHAR const wcsDefaultContentCatalog[] = L"system";
  72. #define CONTENT_CATALOG ( wcsDefaultContentCatalog )
  73. BOOL isEven(unsigned n)
  74. {
  75. return !(n & 0x1);
  76. }
  77. //
  78. // Maximum time for test to complete.
  79. //
  80. int const MAXTIME = 120;
  81. int const MINREPORTTIME = 5;
  82. int const MAXWAITTIME = 10;
  83. int const MAXCOLUMNS = 20;
  84. const int cbPV = sizeof PROPVARIANT;
  85. const int cbPPV = sizeof( PROPVARIANT * );
  86. const HCHAPTER DBCHP_FIRST = 1;
  87. time_t tstart;
  88. BOOL CheckTime();
  89. //
  90. // Test files
  91. //
  92. WCHAR const wcsTestDir[] = L"QueryTest";
  93. WCHAR const wcsTestFile[] = L"Test file for OFS Query";
  94. WCHAR const wcsPropFile[] = L"Test file for Property Query.txt";
  95. WCHAR const wcsPropFile2[] = L"Test file for Property Query2.txt";
  96. WCHAR const wcsTestCiFile1[] = L"Test file for OFS Content Query1.txt";
  97. WCHAR const wcsTestCiFile2[] = L"Test file for OFS Content Query2.txt";
  98. WCHAR const wcsTestCiFile3[] = L"Test file for OFS Content Query3.txt";
  99. DBOBJECT dbPersistObject;
  100. // For testing safearrays of various types.
  101. GUID const guidArray = { 0x92452ac2, 0xfcbb, 0x11d1,
  102. 0xb7, 0xca, 0x00, 0xa0, 0xc9, 0x06, 0xb2, 0x39 };
  103. //
  104. // Storage Properties
  105. //
  106. #define PSID_PSSecurityTest { 0xa56168e0, \
  107. 0x0ef3, 0x11cf, \
  108. 0xbb, 0x01, 0x00, 0x00, 0x4c, 0x75, 0x2a, 0x9a }
  109. #define PSID_PSMyPropSet { 0x49691CF4, \
  110. 0x7E17, 0x101A, \
  111. 0xA9, 0x1C, 0x08, 0x00, 0x2B, 0x2E, 0xCD, 0xA9 }
  112. #define guidZero { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
  113. GUID const guidMyPropSet = PSID_PSMyPropSet;
  114. GUID const guidSecurityTest = PSID_PSSecurityTest;
  115. const DBID dbcolNull = { {0,0,0,{0,0,0,0,0,0,0,0}},DBKIND_GUID_PROPID,0};
  116. const GUID guidQueryExt = DBPROPSET_QUERYEXT;
  117. const GUID guidFsCiFrmwrkExt = DBPROPSET_FSCIFRMWRK_EXT;
  118. const GUID guidCiFrmwrkExt = DBPROPSET_CIFRMWRKCORE_EXT;
  119. const GUID guidMsidxsExt = DBPROPSET_MSIDXS_ROWSETEXT;
  120. CDbColId const psSecurityTest = CDbColId( guidSecurityTest, 2 );
  121. CDbColId const psTestProperty1 = CDbColId( guidMyPropSet, 2 );
  122. CDbColId const psTestProperty2 = CDbColId( guidMyPropSet, L"A Property" );
  123. CDbColId const psTestProperty10 = CDbColId( guidMyPropSet, L"An Empty Property" );
  124. CDbColId const psTestProperty11 = CDbColId( guidMyPropSet, L"A Bstr Property" );
  125. CDbColId const psTestProperty12 = CDbColId( guidMyPropSet, L"A Bstr Vector Property" );
  126. CDbColId const psBlobTest = CDbColId( guidMyPropSet,
  127. L"BlobTest" );
  128. CDbColId const psGuidTest = CDbColId( guidMyPropSet,
  129. L"GuidTest" );
  130. CDbColId const psTestProperty13 = CDbColId( guidMyPropSet, 13 );
  131. CDbColId const psTestProperty14 = CDbColId( guidMyPropSet, 14 );
  132. CDbColId const psTestProperty15 = CDbColId( guidMyPropSet, 15 );
  133. CDbColId const psTestProperty16 = CDbColId( guidMyPropSet, 16 );
  134. CDbColId const psTestProperty17 = CDbColId( guidMyPropSet, 17 );
  135. CDbColId const psTestProperty18 = CDbColId( guidMyPropSet, 18 );
  136. CDbColId const psTestProperty19 = CDbColId( guidMyPropSet, 19 );
  137. CDbColId const psTestProperty20 = CDbColId( guidMyPropSet, 20 );
  138. CDbColId const psTestProperty21 = CDbColId( guidMyPropSet, 21 );
  139. CDbColId const psTestProperty22 = CDbColId( guidMyPropSet, 22 );
  140. #ifndef PROPID_PSDocument
  141. //#include <winole.h>
  142. #define PSID_PSDocument { \
  143. 0xF29F85E0, \
  144. 0x4FF9, 0x1068, \
  145. 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9 \
  146. }
  147. #define PROPID_PSDocument_Author 4
  148. #define PROPID_PSDocument_Keywords 5
  149. #endif // PROPID_PSDocument
  150. static GUID guidDocument = PSID_PSDocument;
  151. CDbColId const psAuthor = CDbColId( guidDocument,
  152. PROPID_PSDocument_Author );
  153. CDbColId const psKeywords = CDbColId( guidDocument,
  154. PROPID_PSDocument_Keywords );
  155. CDbColId const psRelevantWords = CDbColId( guidMyPropSet,
  156. L"RelevantWords" );
  157. CDbColId const psManyRW = CDbColId( guidMyPropSet,
  158. L"ManyRW" );
  159. PROPVARIANT varProp1;
  160. PROPVARIANT varProp2;
  161. PROPVARIANT varProp3;
  162. PROPVARIANT varProp4;
  163. PROPVARIANT varProp5;
  164. PROPVARIANT varProp6;
  165. PROPVARIANT varProp7;
  166. PROPVARIANT varProp8, varProp8A;
  167. PROPVARIANT varProp9;
  168. PROPVARIANT varProp10;
  169. PROPVARIANT varProp11, varProp11A;
  170. PROPVARIANT varProp12;
  171. // for coercion test
  172. PROPVARIANT varProp13;
  173. PROPVARIANT varProp14;
  174. PROPVARIANT varProp15;
  175. PROPVARIANT varProp16;
  176. PROPVARIANT varProp17;
  177. PROPVARIANT varProp18, varProp18A;
  178. PROPVARIANT varProp19;
  179. PROPVARIANT varProp20;
  180. PROPVARIANT varProp21;
  181. PROPVARIANT varProp22;
  182. VARTYPE const PROP1_TYPE = VT_I4;
  183. VARTYPE const PROP2_TYPE = VT_LPWSTR;
  184. VARTYPE const PROP3_TYPE = VT_LPWSTR;
  185. VARTYPE const PROP4_TYPE = (VT_VECTOR|VT_LPWSTR);
  186. VARTYPE const PROP5_TYPE = (VT_VECTOR|VT_I4);
  187. VARTYPE const PROP6_TYPE = VT_BLOB;
  188. VARTYPE const PROP7_TYPE = VT_CLSID;
  189. VARTYPE const PROP8_TYPE = (VT_VECTOR|VT_I4);
  190. VARTYPE const PROP9_TYPE = VT_I4;
  191. VARTYPE const PROP10_TYPE = VT_LPWSTR;
  192. VARTYPE const PROP11_TYPE = VT_BSTR;
  193. VARTYPE const PROP12_TYPE = (VT_VECTOR|VT_BSTR);
  194. // for coercion test
  195. VARTYPE const PROP13_TYPE = VT_UI1;
  196. VARTYPE const PROP14_TYPE = VT_I2;
  197. VARTYPE const PROP15_TYPE = VT_UI2;
  198. VARTYPE const PROP16_TYPE = VT_I4;
  199. VARTYPE const PROP17_TYPE = VT_R4;
  200. VARTYPE const PROP18_TYPE = VT_R8;
  201. VARTYPE const PROP19_TYPE = VT_BOOL;
  202. VARTYPE const PROP20_TYPE = VT_LPSTR;
  203. VARTYPE const PROP21_TYPE = VT_CF;
  204. VARTYPE const PROP22_TYPE = VT_CF | VT_VECTOR;
  205. const long PROP1_VAL = 1234;
  206. #define PROP1_cb ( sizeof ULONG )
  207. const long PROP1_VAL_Alternate = 123;
  208. const WCHAR * PROP2_VAL = L"Wow! In a property.";
  209. #define PROP2_cb ( ( sizeof WCHAR ) * ( wcslen(PROP2_VAL) ) )
  210. const WCHAR * PROP3_VAL = L"AlanW";
  211. #define PROP3_cb ( ( sizeof WCHAR ) * ( wcslen(PROP3_VAL) ) )
  212. const WCHAR * alpwstrProp4[] = { L"This",
  213. L"is",
  214. L"a",
  215. L"Vector",
  216. L"Property",
  217. };
  218. const int clpwstrProp4 = (sizeof alpwstrProp4 / sizeof (WCHAR *));
  219. const CALPWSTR PROP4_VAL = { clpwstrProp4, (WCHAR * *) alpwstrProp4 };
  220. #define PROP4_cb 0
  221. const LONG SecondRelevantWord = 0x23;
  222. LONG alProp5[] = { 0x12, SecondRelevantWord, 0x35, 0x47, 0x59 };
  223. const int clProp5 = (sizeof alProp5 / sizeof (LONG));
  224. CAL PROP5_VAL = { clProp5, &alProp5[0] };
  225. LONG alProp5Less[] = { alProp5[0]-1, alProp5[1]-1, alProp5[2]-1, alProp5[3]-1, alProp5[4]-1 };
  226. const int clProp5Less = (sizeof alProp5Less / sizeof (LONG));
  227. CAL PROP5_VAL_LESS = { clProp5Less, &alProp5Less[0] };
  228. LONG alProp5More[] = { alProp5[0]+1, alProp5[1]+1, alProp5[2]+1, alProp5[3]+1, alProp5[4]+1 };
  229. const int clProp5More = (sizeof alProp5More / sizeof (LONG));
  230. CAL PROP5_VAL_MORE = { clProp5More, &alProp5More[0] };
  231. LONG alProp5AllLess[] = { 1, 2, 3, 4, 5 };
  232. const int clProp5AllLess = (sizeof alProp5AllLess / sizeof (LONG));
  233. CAL PROP5_VAL_ALLLESS = { clProp5AllLess, &alProp5AllLess[0] };
  234. LONG alProp5AllMore[] = { 0xffff, 0xfffe, 0xfffd, 0xfffc, 0xfffb };
  235. const int clProp5AllMore = (sizeof alProp5AllMore / sizeof (LONG));
  236. CAL PROP5_VAL_ALLMORE = { clProp5AllMore, &alProp5AllMore[0] };
  237. LONG alProp5Jumble[] = { alProp5[4], alProp5[3], alProp5[1], alProp5[2], alProp5[0] };
  238. const int clProp5Jumble = (sizeof alProp5Jumble / sizeof (LONG));
  239. CAL PROP5_VAL_JUMBLE = { clProp5Jumble, &alProp5Jumble[0] };
  240. LONG alProp5Like[] = { 0x1, 0x1, 0x2, 0x3, SecondRelevantWord };
  241. const int clProp5Like = (sizeof alProp5Like / sizeof (LONG));
  242. CAL PROP5_VAL_LIKE = { clProp5Like, &alProp5Like[0] };
  243. LONG alProp5None[] = { 0x1, 0x1, 0x2, 0x3, 0x4 };
  244. const int clProp5None = (sizeof alProp5None / sizeof (LONG));
  245. CAL PROP5_VAL_NONE = { clProp5None, &alProp5None[0] };
  246. #define PROP5_cb 0
  247. BLOB PROP6_VAL = { sizeof alProp5, (BYTE*) &alProp5[0] };
  248. #define PROP6_cb ( sizeof PROPVARIANT )
  249. GUID PROP7_VAL = guidMyPropSet;
  250. #define PROP7_cb ( sizeof GUID )
  251. #define PROP7_STR_VAL "{49691CF4-7E17-101A-A91C-08002B2ECDA9}"
  252. // note: loading the value of prop8 will be deferred
  253. LONG alProp8[5000];
  254. const int clProp8 = (sizeof alProp8 / sizeof (LONG));
  255. CAL PROP8_VAL = { clProp8, &alProp8[0] };
  256. #define PROP8_cb 0
  257. const long PROP9_VAL = 4321;
  258. #define PROP9_cb ( sizeof ULONG )
  259. const WCHAR * PROP10_VAL = L""; // an empty string
  260. #define PROP10_cb ( ( sizeof WCHAR ) * (wcslen(PROP10_VAL) ) )
  261. const WCHAR * PROP11_VAL = L"This is a BSTR"; // string for a BSTR prop
  262. WCHAR PROP11_LONGVAL[5000] = L"This is a large BSTR "; // string for a BSTR prop
  263. const char PROP13_VAL = 65;
  264. #define PROP13_cb ( sizeof char )
  265. #define PROP13_STR_VAL "65"
  266. const short PROP14_VAL = -1234;
  267. #define PROP14_cb ( sizeof short )
  268. #define PROP14_STR_VAL "-1234"
  269. const unsigned short PROP15_VAL = 1234;
  270. #define PROP15_cb ( sizeof (unsigned short) )
  271. #define PROP15_STR_VAL "1234"
  272. const int PROP16_VAL = -1234;
  273. #define PROP16_cb ( sizeof int )
  274. #define PROP16_STR_VAL "-1234"
  275. const float PROP17_VAL = 1234.5678F;
  276. #define PROP17_cb ( sizeof (float) )
  277. // This would get truncated in result as we supply a smaller buffer
  278. #define PROP17_STR_VAL "123"
  279. const double PROP18_VAL = 1234.12345678;
  280. #define PROP18_cb ( sizeof double )
  281. #define PROP18_STR_VAL "1234.12345678"
  282. const WORD PROP19_VAL = 0;
  283. #define PROP19_cb ( sizeof WORD )
  284. #define PROP19_STR_VAL "False"
  285. const LPSTR PROP20_VAL = "1245.5678";
  286. #define PROP20_cb ( strlen( PROP20_VAL ) )
  287. #define PROP20_DBL_VAL 1245.5678
  288. // note: not all the data in the CF is used, just the # of bytes specified
  289. CLIPDATA aClipData[3] =
  290. {
  291. { 20, 3, (BYTE *) "abcdefghijklmnopqrstuvwxyz" },
  292. { 16, 5, (BYTE *) "zyxwvutsrqponmlkjihgfedcba" },
  293. { 24, 7, (BYTE *) "01234567abcdefghijklmnopqrstuvwxyz" },
  294. };
  295. #define PROP21_cb (sizeof( void *) )
  296. #define PROP21_VAL &aClipData[0]
  297. #define PROP22_cb 0
  298. #define PROP22_VAL aClipData
  299. #define PROP22_CVALS ( sizeof aClipData / sizeof aClipData[0] )
  300. // safearray propvariants:
  301. PROPVARIANT vaI4;
  302. PROPSPEC psSA_I4 = { PRSPEC_PROPID, 2 };
  303. CDbColId const colSA_I4 = CDbColId( guidArray, 2 );
  304. PROPVARIANT vaBSTR;
  305. PROPSPEC psSA_BSTR = { PRSPEC_PROPID, 3 };
  306. CDbColId const colSA_BSTR = CDbColId( guidArray, 3 );
  307. PROPVARIANT vaVARIANT;
  308. PROPSPEC psSA_VARIANT = { PRSPEC_PROPID, 4 };
  309. CDbColId const colSA_VARIANT = CDbColId( guidArray, 4 );
  310. PROPVARIANT vaR8;
  311. PROPSPEC psSA_R8 = { PRSPEC_PROPID, 5 };
  312. CDbColId const colSA_R8 = CDbColId( guidArray, 5 );
  313. PROPVARIANT vaDATE;
  314. PROPSPEC psSA_DATE = { PRSPEC_PROPID, 6 };
  315. CDbColId const colSA_DATE = CDbColId( guidArray, 6 );
  316. PROPVARIANT vaBOOL;
  317. PROPSPEC psSA_BOOL = { PRSPEC_PROPID, 7 };
  318. CDbColId const colSA_BOOL = CDbColId( guidArray, 7 );
  319. PROPVARIANT vaDECIMAL;
  320. PROPSPEC psSA_DECIMAL = { PRSPEC_PROPID, 8 };
  321. CDbColId const colSA_DECIMAL = CDbColId( guidArray, 8 );
  322. PROPVARIANT vaI1;
  323. PROPSPEC psSA_I1 = { PRSPEC_PROPID, 9 };
  324. CDbColId const colSA_I1 = CDbColId( guidArray, 9 );
  325. PROPVARIANT vaR4;
  326. PROPSPEC psSA_R4 = { PRSPEC_PROPID, 10 };
  327. CDbColId const colSA_R4 = CDbColId( guidArray, 10 );
  328. PROPVARIANT vaCY;
  329. PROPSPEC psSA_CY = { PRSPEC_PROPID, 11 };
  330. CDbColId const colSA_CY = CDbColId( guidArray, 11 );
  331. PROPVARIANT vaUINT;
  332. PROPSPEC psSA_UINT = { PRSPEC_PROPID, 12 };
  333. CDbColId const colSA_UINT = CDbColId( guidArray, 12 );
  334. PROPVARIANT vaINT;
  335. PROPSPEC psSA_INT = { PRSPEC_PROPID, 13 };
  336. CDbColId const colSA_INT = CDbColId( guidArray, 13 );
  337. PROPVARIANT vaERROR;
  338. PROPSPEC psSA_ERROR = { PRSPEC_PROPID, 14 };
  339. CDbColId const colSA_ERROR = CDbColId( guidArray, 14 );
  340. //
  341. // Desired output columns (as both CDbColId and DBCOMUNID)
  342. //
  343. static GUID guidSystem = PSGUID_STORAGE;
  344. static GUID guidQuery = PSGUID_QUERY;
  345. static GUID guidBmk = DBBMKGUID;
  346. static GUID guidSelf = DBCOL_SELFCOLUMNS;
  347. static CDbColId psName( guidSystem, PID_STG_NAME );
  348. static CDbColId psPath( guidSystem, PID_STG_PATH );
  349. static CDbColId psAttr( guidSystem, PID_STG_ATTRIBUTES );
  350. static CDbColId psSize( guidSystem, PID_STG_SIZE );
  351. static CDbColId psWriteTime( guidSystem, PID_STG_WRITETIME );
  352. static CDbColId psClassid( guidSystem, PID_STG_CLASSID );
  353. static CDbColId psContents( guidSystem, PID_STG_CONTENTS );
  354. static CDbColId psRank( guidQuery, DISPID_QUERY_RANK );
  355. static CDbColId psWorkid( guidQuery, DISPID_QUERY_WORKID );
  356. static CDbColId psBookmark( guidBmk, PROPID_DBBMK_BOOKMARK );
  357. static CDbColId psSelf( guidSelf, PROPID_DBSELF_SELF );
  358. static CDbColId psChapt( guidBmk, PROPID_DBBMK_CHAPTER );
  359. static CDbSortKey sortSize( psSize, QUERY_SORTDESCEND );
  360. static CDbSortKey sortClassid( psClassid, QUERY_SORTDESCEND );
  361. static CDbSortKey sortWriteTime( psWriteTime, QUERY_SORTASCEND );
  362. static CDbSortKey sortName( psName, QUERY_SORTDESCEND );
  363. static CDbSortKey sortAttr( psName, QUERY_SORTASCEND );
  364. CDbSortKey aSortCols[] = {
  365. sortSize, sortClassid, sortWriteTime, sortName,
  366. };
  367. CDbSortKey aCatSortCols[] = {
  368. sortSize, sortWriteTime,
  369. };
  370. CDbSortKey aMultiCatSortCols[] = {
  371. sortAttr, sortSize,
  372. };
  373. static CDbSortKey sortKeywords( psKeywords, QUERY_SORTASCEND );
  374. static CDbSortKey sortRelevantWords( psRelevantWords, QUERY_SORTASCEND );
  375. static CDbSortKey sortTestProperty1( psTestProperty1, QUERY_SORTASCEND );
  376. CDbSortKey aPropSortCols[] = {
  377. sortKeywords, sortRelevantWords, sortTestProperty1
  378. };
  379. const int cSortColumns = (sizeof aSortCols) / (sizeof aSortCols[0]);
  380. const int cCatSortColumns = (sizeof aCatSortCols) / (sizeof aCatSortCols[0]);
  381. const int cMultiCatSortColumns = (sizeof aMultiCatSortCols) / (sizeof aMultiCatSortCols[0]);
  382. const int cPropSortColumns = (sizeof aPropSortCols) / (sizeof aPropSortCols[0]);
  383. const BYTE bmkFirst = (BYTE) DBBMK_FIRST;
  384. const BYTE bmkLast = (BYTE) DBBMK_LAST;
  385. //
  386. // Text in content index files
  387. //
  388. char const szCIFileData1[] =
  389. " The content index was created by Kyle Peltonen and Bartosz Milewski\n"
  390. "with help from Amy Arlin, Wade Richards, Mike Hewitt and a host of others.\n"
  391. " \"To be or not to be\" is most likely a noise phrase. \"To be or\n"
  392. "not to be, that is the question\" contains at least one non-noise\n"
  393. "word.\n"
  394. "Now is the time for all good men to come to the aid of their country.\n"
  395. "The content index is a superb piece of engineering. ;-)\n";
  396. char const szCIFileData2[] =
  397. "\"Anybody can be good in the country. "
  398. "There are no temptations there.\"\n"
  399. "\n"
  400. "Oscar Wilde (1854-1900), Anglo-Irish playwright, author.\n"
  401. "Lord Henry, in The Picture of Dorian Gray, ch. 19 (1891).\n";
  402. char const szOFSFileData[] = "PLEASE DELETE ME!\n";
  403. WCHAR wcsTestPath[MAX_PATH];
  404. WCHAR wcsTestCatalog[MAX_PATH];
  405. struct SBasicTest
  406. {
  407. // field lengths
  408. DBLENGTH cbClsid;
  409. DBLENGTH cbSize;
  410. DBLENGTH cbWriteTime;
  411. DBLENGTH cbAttr;
  412. DBLENGTH cbName;
  413. DBLENGTH cbPath;
  414. // field status
  415. ULONG sClsid;
  416. ULONG sSize;
  417. ULONG sWriteTime;
  418. ULONG sIPSStorage;
  419. ULONG sAttr;
  420. ULONG sName;
  421. ULONG sPath;
  422. // field data
  423. CLSID clsid;
  424. _int64 size;
  425. _int64 writeTime;
  426. unsigned attr;
  427. WCHAR awcName[MAX_PATH + 1];
  428. WCHAR *pwcPath;
  429. IUnknown *pIPSStorage;
  430. };
  431. struct SBasicAltTest
  432. {
  433. // field lengths
  434. DBLENGTH cbSize;
  435. DBLENGTH cbWriteTime1;
  436. DBLENGTH cbWriteTime2;
  437. DBLENGTH cbWriteTime3;
  438. // field status
  439. ULONG sSize;
  440. ULONG sWriteTime1;
  441. ULONG sWriteTime2;
  442. ULONG sWriteTime3;
  443. // field data
  444. LONG Size;
  445. DBDATE writeTime1;
  446. DBTIME writeTime2;
  447. DBTIMESTAMP writeTime3;
  448. };
  449. const ULONG cbRowName = sizeof WCHAR * (MAX_PATH + 1);
  450. #define ALLPARTS ( DBPART_VALUE|DBPART_LENGTH|DBPART_STATUS )
  451. DBBINDING aBasicTestCols[] =
  452. {
  453. // the iOrdinal field is filled in after the cursor is created
  454. { 0,
  455. offsetof(SBasicTest,clsid),
  456. offsetof(SBasicTest,cbClsid),
  457. offsetof(SBasicTest,sClsid),
  458. 0,0,0,
  459. ALLPARTS,
  460. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  461. sizeof CLSID,
  462. 0, DBTYPE_GUID,
  463. 0, 0 },
  464. { 0,
  465. offsetof(SBasicTest,size),
  466. offsetof(SBasicTest,cbSize),
  467. offsetof(SBasicTest,sSize),
  468. 0,0,0,
  469. ALLPARTS,
  470. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  471. sizeof LONGLONG,
  472. 0, DBTYPE_UI8,
  473. 0, 0 },
  474. { 0,
  475. offsetof(SBasicTest,writeTime),
  476. offsetof(SBasicTest,cbWriteTime),
  477. offsetof(SBasicTest,sWriteTime),
  478. 0,0,0,
  479. ALLPARTS,
  480. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  481. sizeof LONGLONG,
  482. 0, VT_FILETIME,
  483. 0, 0 },
  484. { 0,
  485. offsetof(SBasicTest,attr),
  486. offsetof(SBasicTest,cbAttr),
  487. offsetof(SBasicTest,sAttr),
  488. 0,0,0,
  489. ALLPARTS,
  490. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  491. 3, // 3 for cb is ok: fixed len field so ignored
  492. 0, DBTYPE_I4,
  493. 0, 0 },
  494. { 0,
  495. offsetof(SBasicTest,awcName),
  496. offsetof(SBasicTest,cbName),
  497. offsetof(SBasicTest,sName),
  498. 0,0,0,
  499. ALLPARTS,
  500. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  501. cbRowName,
  502. 0, DBTYPE_WSTR,
  503. 0, 0 },
  504. { 0,
  505. offsetof(SBasicTest,pwcPath),
  506. offsetof(SBasicTest,cbPath),
  507. offsetof(SBasicTest,sPath),
  508. 0,0,0,
  509. ALLPARTS,
  510. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  511. 0,
  512. 0, DBTYPE_WSTR|DBTYPE_BYREF,
  513. 0, 0 },
  514. { 0,
  515. offsetof(SBasicTest,pIPSStorage),
  516. 0,
  517. offsetof(SBasicTest,sIPSStorage),
  518. 0, // pTypeInfo
  519. &dbPersistObject, // pObject
  520. 0, // pBindExt
  521. DBPART_VALUE|DBPART_STATUS, // dwPart
  522. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, // dwMemOwner
  523. 0, // cbMaxLen
  524. 0, // dwFlags
  525. DBTYPE_IUNKNOWN, // wType
  526. 0, 0 }, // bPrecision, bScale
  527. };
  528. const ULONG cBasicTestCols = sizeof aBasicTestCols / sizeof aBasicTestCols[0];
  529. DBBINDING aBasicAltCols[] =
  530. {
  531. // the iOrdinal field is filled in after the cursor is created
  532. { 0,
  533. offsetof(SBasicAltTest,Size),
  534. offsetof(SBasicAltTest,cbSize),
  535. offsetof(SBasicAltTest,sSize),
  536. 0,0,0,
  537. ALLPARTS,
  538. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  539. 3, // 3 for cb is ok: fixed len field so ignored
  540. 0, DBTYPE_I4,
  541. 0, 0 },
  542. { 0,
  543. offsetof(SBasicAltTest,writeTime1),
  544. offsetof(SBasicAltTest,cbWriteTime1),
  545. offsetof(SBasicAltTest,sWriteTime1),
  546. 0,0,0,
  547. ALLPARTS,
  548. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  549. sizeof DBDATE,
  550. 0, DBTYPE_DBDATE,
  551. 0, 0 },
  552. { 0,
  553. offsetof(SBasicAltTest,writeTime2),
  554. offsetof(SBasicAltTest,cbWriteTime2),
  555. offsetof(SBasicAltTest,sWriteTime2),
  556. 0,0,0,
  557. ALLPARTS,
  558. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  559. sizeof DBTIME,
  560. 0, DBTYPE_DBTIME,
  561. 0, 0 },
  562. { 0,
  563. offsetof(SBasicAltTest,writeTime3),
  564. offsetof(SBasicAltTest,cbWriteTime3),
  565. offsetof(SBasicAltTest,sWriteTime3),
  566. 0,0,0,
  567. ALLPARTS,
  568. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  569. sizeof DBTIMESTAMP,
  570. 0, DBTYPE_DBTIMESTAMP,
  571. 0, 0 },
  572. };
  573. const ULONG cBasicAltCols = sizeof aBasicAltCols / sizeof aBasicAltCols[0];
  574. int fTimeout = 1; // non-zero if query times out
  575. int fVerbose = 0; // non-zero if verbose mode
  576. int cFailures = 0; // count of failures in test (unit test only)
  577. // Class to be used as an outer unknown. All QIs are simply
  578. // passed on to inner unknown.
  579. class COuterUnk: public IUnknown
  580. {
  581. public:
  582. //
  583. // IUnknown methods.
  584. //
  585. STDMETHOD(QueryInterface) ( THIS_ REFIID riid,
  586. LPVOID *ppiuk )
  587. {
  588. // do blindly delegate for purpose of test
  589. // don't AddRef as the inner unk will do it
  590. return _pInnerUnk->QueryInterface(riid,ppiuk);
  591. }
  592. STDMETHOD_(ULONG, AddRef) (THIS)
  593. {
  594. InterlockedIncrement( (long *)&_ref );
  595. return( _ref );
  596. }
  597. STDMETHOD_(ULONG, Release) (THIS)
  598. {
  599. if ( InterlockedDecrement( (long *)&_ref ) <= 0 )
  600. {
  601. InterlockedIncrement( (long *)&_ref ); // artificial ref count for aggr
  602. delete this;
  603. return 0;
  604. }
  605. return ( _ref );
  606. }
  607. void Set(IUnknown *pInnerUnk) {_pInnerUnk = pInnerUnk;
  608. _pInnerUnk->AddRef();}
  609. COuterUnk() : _ref(1), _pInnerUnk(NULL)
  610. {};
  611. ~COuterUnk() {
  612. if (_pInnerUnk)
  613. {
  614. _pInnerUnk->Release();
  615. _pInnerUnk = 0;
  616. }
  617. };
  618. private:
  619. long _ref; // OLE reference count
  620. IUnknown * _pInnerUnk;
  621. };
  622. void DownlevelTest(BOOL fSequential);
  623. void SingleLevelCategTest();
  624. void MultiLevelCategTest();
  625. void CategTest( HCHAPTER hUpperChapt,
  626. IRowset *pRowsetCateg, IRowset *pRowset, unsigned cCols );
  627. void RunPropTest( );
  628. void RunSafeArrayTest( );
  629. void RunDistribQueryTest( BOOL fDoContentTest );
  630. void DeleteTest(BOOL fSequential);
  631. void ContentTest(void);
  632. void ConflictingPropsTest( LPWSTR pwszScope,
  633. CDbCmdTreeNode * pTree,
  634. COuterUnk * pobjOuterUnk,
  635. ICommandTree **ppCmdTree );
  636. void CheckColumns( IUnknown* pRowset, CDbColumns& rColumns, BOOL fQuiet = FALSE );
  637. void CheckPropertiesInError( ICommand* pCmd, BOOL fQuiet = FALSE );
  638. void CheckPropertiesOnCommand( ICommand* pCmd, BOOL fQuiet = FALSE );
  639. void BasicTest( IRowset* pRowset,
  640. BOOL fSequential, HCHAPTER hChapt, unsigned cCols,
  641. BOOL fByRef, ICommandTree * pCmdTree = 0 );
  642. void BackwardsFetchTest( IRowset* pRowset );
  643. void FetchTest(IRowset* pRowset);
  644. void BindingTest(IUnknown* pRowset, BOOL fICommand = FALSE, BOOL fSequential = FALSE );
  645. void MoveTest(IRowset* pRowset, HCHAPTER hChapt = DB_NULL_HCHAPTER);
  646. int CheckHrowIdentity( IRowsetIdentity * pRowsetIdentity,
  647. DBROWCOUNT lOffset,
  648. DBCOUNTITEM cRows1,
  649. HROW * phRows1,
  650. DBCOUNTITEM cRows2,
  651. HROW * phRows2 );
  652. void TestIAccessorOnCommand( ICommandTree * pCmdTree );
  653. void CheckPropertyValue( PROPVARIANT const & varntPropRet,
  654. PROPVARIANT const & varntPropExp);
  655. BOOL GetBooleanProperty ( IRowset * pRowset, DBPROPID dbprop );
  656. BOOL SetBooleanProperty ( ICommand * pCmd, DBPROPID dbprop, VARIANT_BOOL f );
  657. CDbCmdTreeNode * FormQueryTree( CDbCmdTreeNode * pRst,
  658. CDbColumns & Cols,
  659. CDbSortSet * pSort,
  660. LPWSTR * aColNames = 0 );
  661. void GetCommandTreeErrors(ICommandTree* pCmdTree);
  662. IRowsetScroll * InstantiateRowset(
  663. ICommand *pQueryIn,
  664. DWORD dwDepth,
  665. LPWSTR pwszScope,
  666. CDbCmdTreeNode * pTree,
  667. REFIID riid,
  668. COuterUnk *pobjOuterUnk = 0,
  669. ICommandTree ** ppCmdTree = 0,
  670. BOOL fExtendedTypes = TRUE
  671. );
  672. void InstantiateMultipleRowsets(
  673. DWORD dwDepth,
  674. LPWSTR pwszScope,
  675. CDbCmdTreeNode * pTree,
  676. REFIID riid,
  677. unsigned cRowsets,
  678. IUnknown ** aRowsets,
  679. ICommandTree ** ppCmdTree = 0
  680. );
  681. void ReleaseStaticHrows( IRowset * pRowset, DBCOUNTITEM cRows, HROW * phRows );
  682. void FreeHrowsArray( IRowset * pRowset, DBCOUNTITEM cRows, HROW ** pphRows );
  683. HACCESSOR MapColumns(
  684. IUnknown * pUnknown,
  685. DBORDINAL cCols,
  686. DBBINDING * pBindings,
  687. const DBID * pColIds,
  688. BOOL fByRef = FALSE );
  689. void ReleaseAccessor( IUnknown * pUnknown, HACCESSOR hAcc );
  690. int WaitForCompletion( IRowset *pRowset, BOOL fQuiet = FALSE );
  691. void Setup(void);
  692. void Cleanup(void);
  693. ULONG Delnode( WCHAR const * wcsDir );
  694. void BuildFile( WCHAR const * wcsFile, char const * data, ULONG cb );
  695. void CantRun(void);
  696. void Fail(void);
  697. void Usage(void);
  698. void LogProgress( char const * pszFormat, ... );
  699. void LogError( char const * pszFormat, ... );
  700. void LogFail( char const * pszFormat, ... );
  701. WCHAR * FormatGuid( GUID const & guid );
  702. void DBSortTest(void);
  703. SCODE SetScopeProperties( ICommand * pCmd,
  704. unsigned cDirs,
  705. WCHAR const * const * apDirs,
  706. ULONG const * aulFlags,
  707. WCHAR const * const * apCats = 0,
  708. WCHAR const * const * apMachines = 0 );
  709. BOOL DoContentQuery(
  710. ICommand * pQuery,
  711. CDbRestriction & CiRst,
  712. unsigned cExpectedHits );
  713. char *ProgName = PROG_NAME;
  714. void Usage(void)
  715. {
  716. #ifdef UNIT_TEST
  717. printf("Usage: %s [ -d[:InfoLevel] ] [-v] [-V] [-t] [-c]\n",
  718. ProgName);
  719. #else // !UNIT_TEST
  720. printf("Usage: %s [-v] [-V] [-t] [-c]\n", ProgName);
  721. #endif // UNIT_TEST
  722. printf("\t-v\tverbose\n"
  723. "\t-V\tvery verbose - dumps tables, column and rowset info\n"
  724. "\t-t\tdon't timeout queries\n"
  725. "\t-c\tdon't do content query test\n");
  726. // "\t-dl\tdon't do tests on downlevel file system\n"
  727. // "\t-ofs\tdon't do tests on OFS file system\n");
  728. // "\t-n{d,o}\tdon't do tests on downlevel (-nd) or OFS (-no)\n");
  729. #ifdef UNIT_TEST
  730. printf("\t-d[:InfoLevel]\tset debug infolevel to InfoLevel\n");
  731. #endif // UNIT_TEST
  732. exit(2);
  733. }
  734. //+-------------------------------------------------------------------------
  735. //
  736. // Function: IsContentFilteringEnabled, public
  737. //
  738. // Synopsis: Read the registry for the key FilterContent at the
  739. // location
  740. //
  741. //--------------------------------------------------------------------------
  742. BOOL IsContentFilteringEnabled()
  743. {
  744. WCHAR wcsFilterContents[] = L"FilterContents";
  745. WCHAR wcsRegAdmin[] = L"ContentIndex";
  746. BOOL fFilteringEnabled = FALSE;
  747. RTL_QUERY_REGISTRY_TABLE regtab[2];
  748. regtab[0].DefaultType = REG_NONE;
  749. regtab[0].DefaultData = 0;
  750. regtab[0].DefaultLength = 0;
  751. regtab[0].QueryRoutine = 0;
  752. regtab[0].Name = wcsFilterContents;
  753. regtab[0].EntryContext = &fFilteringEnabled;
  754. regtab[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
  755. regtab[1].QueryRoutine = 0;
  756. regtab[1].Flags = 0;
  757. NTSTATUS Status = RtlQueryRegistryValues( RTL_REGISTRY_CONTROL,
  758. wcsRegAdmin,
  759. &regtab[0],
  760. 0,
  761. 0 );
  762. if ( NT_ERROR(Status) || !fFilteringEnabled )
  763. return FALSE;
  764. ISimpleCommandCreator * pCmdCreator = 0;
  765. CLSID clsidSCC = CLSID_CISimpleCommandCreator;
  766. SCODE sc = CoCreateInstance( clsidSCC,
  767. NULL,
  768. CLSCTX_INPROC_SERVER,
  769. IID_ISimpleCommandCreator,
  770. (void **)&pCmdCreator );
  771. if ( S_OK != sc )
  772. {
  773. LogError( "CoCreateInstance for cmd creator returned %08x\n", sc );
  774. return FALSE;
  775. }
  776. WCHAR awchCatalog[80];
  777. ULONG cchCat = 0;
  778. sc = pCmdCreator->GetDefaultCatalog( awchCatalog,
  779. sizeof awchCatalog/sizeof(awchCatalog[0]),
  780. &cchCat );
  781. if ( S_OK != sc )
  782. {
  783. LogError( "GetDefaultCatalog returned %08x\n", sc );
  784. pCmdCreator->Release();
  785. return FALSE;
  786. }
  787. sc = pCmdCreator->VerifyCatalog( TEST_MACHINE, CONTENT_CATALOG );
  788. pCmdCreator->Release();
  789. return sc == S_OK;
  790. }
  791. //+-------------------------------------------------------------------------
  792. //
  793. // Function: main, public
  794. //
  795. // Synopsis: Test the file system implementation of the IRowset
  796. // family of interfaces.
  797. //
  798. // Notes:
  799. //
  800. // History: 25 Mar 1994 Alanw Created
  801. //
  802. //--------------------------------------------------------------------------
  803. int __cdecl main(int argc, char **argv)
  804. {
  805. #ifdef UNIT_TEST
  806. DBSortTest();
  807. #endif
  808. unsigned i;
  809. BOOL fDoContentTest = TRUE;
  810. //
  811. // Parse arguments.
  812. //
  813. ProgName = argv[0];
  814. for ( i = 1; i < (unsigned)argc ; i++ )
  815. {
  816. char *pszArg = argv[i];
  817. if ( *pszArg == '-' ) {
  818. switch ( *++pszArg )
  819. {
  820. case 'd':
  821. // if (pszArg[1] == 'l') // -dl - no downlevel tests
  822. // {
  823. // fNoDownlevel = TRUE;
  824. // break;
  825. // }
  826. #if defined (UNIT_TEST) && (DBG == 1)
  827. if (*++pszArg == ':') // -d:xx - debug output mode
  828. pszArg++;
  829. {
  830. unsigned fInfoLevel = atoi(pszArg);
  831. tbInfoLevel = fInfoLevel ? fInfoLevel : 0xFFFFF;
  832. }
  833. break;
  834. #else // !UNIT_TEST
  835. Usage();
  836. exit(2);
  837. #endif // UNIT_TEST
  838. case 't': // don't timeout
  839. fTimeout = 0;
  840. break;
  841. case 'c':
  842. fDoContentTest = FALSE;
  843. break;
  844. case 'V': // very verbose, dumps table
  845. fVerbose++;
  846. case 'v': // verbose
  847. fVerbose++;
  848. break;
  849. default:
  850. Usage();
  851. exit (2);
  852. }
  853. } else {
  854. // Exit the argument loop
  855. argc -= i;
  856. argv += i;
  857. break;
  858. }
  859. }
  860. printf( "%s: OLE-DB cursor unit test.\n"
  861. #if defined (UNIT_TEST)
  862. " No expected failures\n"
  863. #if !(defined(DO_CATEG_TESTS) && \
  864. defined(DO_NOTIFICATION) && \
  865. defined(DO_CONTENT_TESTS) && \
  866. defined(MULTI_LEVEL_CATEG_TEST) )
  867. " Not all tests are turned on\n"
  868. #endif // conditional tests
  869. #endif // defined(UNIT_TEST)
  870. , ProgName );
  871. for (i = 0; i < clProp8; i++)
  872. alProp8[i] = i;
  873. CoInitialize( 0 );
  874. Setup();
  875. // Patch in this iid, which can't be done in the initializer
  876. dbPersistObject.dwFlags = STGM_PRIORITY | STGM_READ;
  877. dbPersistObject.iid = IID_IPropertySetStorage;
  878. //
  879. // Base functionality test
  880. //
  881. RunPropTest( );
  882. RunSafeArrayTest();
  883. RunDistribQueryTest( fDoContentTest );
  884. DownlevelTest(TRUE);
  885. DownlevelTest(FALSE);
  886. #ifdef DO_CATEG_TESTS
  887. SingleLevelCategTest();
  888. #ifdef DO_MULTI_LEVEL_CATEG_TEST
  889. MultiLevelCategTest();
  890. #endif
  891. #endif // DO_CATEG_TESTS
  892. #ifdef DO_CONTENT_TESTS
  893. if ( fDoContentTest && IsContentFilteringEnabled() )
  894. {
  895. ContentTest();
  896. }
  897. else
  898. #endif
  899. LogProgress("WARNING: Content Query test disabled\n");
  900. DeleteTest(TRUE);
  901. DeleteTest(FALSE);
  902. CIShutdown();
  903. //#if defined (UNIT_TEST)
  904. if (cFailures)
  905. {
  906. printf("%d failures occurred\n", cFailures);
  907. Fail();
  908. }
  909. //#endif // defined(UNIT_TEST)
  910. Cleanup();
  911. CoUninitialize();
  912. printf( "%s: PASSED\n", ProgName );
  913. if (! _isatty(_fileno(stdout)) )
  914. fprintf( stderr, "%s: PASSED\n", ProgName );
  915. return( 0 );
  916. } //main
  917. //+-------------------------------------------------------------------------
  918. //
  919. // Function: DownlevelTest, public
  920. //
  921. // Synopsis: Basic query feature test.
  922. //
  923. // History: 30 Jun 94 AlanW Created
  924. //
  925. // Notes: Just looks for files in the system directory.
  926. //
  927. //--------------------------------------------------------------------------
  928. void DownlevelTest(BOOL fSequential)
  929. {
  930. LogProgress( "Non-content %s query\n",
  931. fSequential? "sequential" : "scrollable");
  932. SCODE sc;
  933. //
  934. // Find system directory
  935. WCHAR wcsSysDir[MAX_PATH];
  936. #if 0
  937. wcscpy(wcsSysDir, L"F:\\winnt\\system32");
  938. #else
  939. if( !GetSystemDirectory( wcsSysDir, sizeof(wcsSysDir) / sizeof(WCHAR) ) )
  940. {
  941. LogFail( "Unable to determine system directory.\n" );
  942. }
  943. #endif
  944. //
  945. // Get name, size and class id for *.exe, *.dll, *.doc and *.sys
  946. //
  947. int cCol = 7;
  948. if ( !fSequential )
  949. cCol++;
  950. CDbColumns cols(cCol);
  951. cols.Add( psClassid, 0 );
  952. cols.Add( psSize, 1 );
  953. cols.Add( psWriteTime, 2 );
  954. cols.Add( psAttr, 3 );
  955. cols.Add( psName, 4 );
  956. cols.Add( psPath, 5 );
  957. cols.Add( psSelf, 6 );
  958. if ( !fSequential )
  959. {
  960. cols.Add( psWorkid, 7);
  961. }
  962. CDbPropertyRestriction rst;
  963. rst.SetRelation( DBOP_like );
  964. rst.SetProperty( psName );
  965. rst.SetValue( L"*.|(exe|,dll|,doc|,sys|,zzz|)" );
  966. CDbSortSet ss(cSortColumns);
  967. for (unsigned i = 0; i<cSortColumns; i++)
  968. ss.Add(aSortCols[i], i);
  969. CDbCmdTreeNode * pDbCmdTree = FormQueryTree(&rst, cols, &ss);
  970. if (! fSequential)
  971. {
  972. ConflictingPropsTest(wcsSysDir, pDbCmdTree, 0, 0);
  973. }
  974. ICommandTree * pCmdTree=0;
  975. COuterUnk *pOuterUnk = new COuterUnk();
  976. IRowset * pRowset = InstantiateRowset(
  977. 0,
  978. QUERY_SHALLOW, // Depth
  979. wcsSysDir, // Scope
  980. pDbCmdTree, // DBCOMMANDTREE
  981. fSequential ? IID_IRowset :
  982. IID_IRowsetScroll, // IID of i/f to return
  983. pOuterUnk,
  984. &pCmdTree );
  985. //
  986. // Verify columns
  987. //
  988. CheckColumns( pRowset, cols );
  989. if ( !WaitForCompletion( pRowset, TRUE ) )
  990. {
  991. pCmdTree->Release();
  992. pRowset->Release();
  993. LogFail( "Downlevel query unsuccessful.\n" );
  994. }
  995. //
  996. // Do basic function tests.
  997. //
  998. BasicTest(pRowset, fSequential, 0, cBasicTestCols, TRUE);
  999. BasicTest(pRowset, fSequential, 0, cBasicTestCols, TRUE, pCmdTree);
  1000. //
  1001. // Do backward fetch tests
  1002. //
  1003. if ( !fSequential )
  1004. {
  1005. BackwardsFetchTest( pRowset );
  1006. }
  1007. FetchTest(pRowset);
  1008. //
  1009. // Test SetBindings, GetBindings, Move and Scroll
  1010. //
  1011. BindingTest(pRowset, FALSE, fSequential );
  1012. BindingTest(pCmdTree, TRUE, fSequential );
  1013. if ( ! fSequential )
  1014. {
  1015. MoveTest(pRowset);
  1016. }
  1017. pCmdTree->Release();
  1018. pRowset->Release();
  1019. pOuterUnk->Release(); // truly release it
  1020. } //DownlevelTest
  1021. //+---------------------------------------------------------------------------
  1022. //
  1023. // Function: ConflictingPropsTest
  1024. //
  1025. // Synopsis: Tests handling of conflicting settings of rowset properties.
  1026. //
  1027. // Arguments: [pswzScope] - Query scope
  1028. // [pTree] - pointer to DBCOMMANDTREE for the query
  1029. // [pUnkOuter] - pointer to outer unknown object
  1030. // [ppCmdTree] - if non-zero, ICommandTree will be returned here.
  1031. //
  1032. // Returns: NOTHING
  1033. //
  1034. // History: 26 May 1998 AlanW Created
  1035. //
  1036. // Notes:
  1037. //
  1038. //----------------------------------------------------------------------------
  1039. void ConflictingPropsTest(
  1040. LPWSTR pwszScope,
  1041. CDbCmdTreeNode * pTree,
  1042. COuterUnk * pobjOuterUnk,
  1043. ICommandTree **ppCmdTree
  1044. ) {
  1045. DWORD dwDepth = QUERY_SHALLOW;
  1046. // run the query
  1047. ICommand * pQuery = 0;
  1048. IUnknown * pIUnknown;
  1049. SCODE sc = CICreateCommand( &pIUnknown,
  1050. (IUnknown *)pobjOuterUnk,
  1051. IID_IUnknown,
  1052. TEST_CATALOG,
  1053. TEST_MACHINE );
  1054. if ( FAILED( sc ) )
  1055. LogFail( "ConflictingPropsTest - error 0x%x Unable to create command\n",
  1056. sc );
  1057. if (pobjOuterUnk)
  1058. {
  1059. pobjOuterUnk->Set(pIUnknown);
  1060. }
  1061. if (pobjOuterUnk)
  1062. sc = pobjOuterUnk->QueryInterface(IID_ICommand, (void **) &pQuery );
  1063. else
  1064. sc = pIUnknown->QueryInterface(IID_ICommand, (void **) &pQuery );
  1065. pIUnknown->Release();
  1066. if ( FAILED( sc ) )
  1067. LogFail( "ConflictingPropsTest - error 0x%x Unable to QI ICommand\n",
  1068. sc );
  1069. sc = SetScopeProperties( pQuery,
  1070. 1,
  1071. &pwszScope,
  1072. &dwDepth );
  1073. if ( FAILED( sc ) )
  1074. LogFail( "ConflictingPropsTest - error 0x%x Unable to set scope '%ws'\n",
  1075. sc, pwszScope );
  1076. CheckPropertiesOnCommand( pQuery );
  1077. ICommandTree *pCmdTree = 0;
  1078. if (pobjOuterUnk)
  1079. sc = pobjOuterUnk->QueryInterface(IID_ICommandTree, (void **)&pCmdTree);
  1080. else
  1081. sc = pQuery->QueryInterface(IID_ICommandTree, (void **)&pCmdTree);
  1082. if (FAILED (sc) )
  1083. {
  1084. if ( 0 != pQuery )
  1085. pQuery->Release();
  1086. LogFail("QI for ICommandTree failed\n");
  1087. }
  1088. DBCOMMANDTREE * pRoot = pTree->CastToStruct();
  1089. sc = pCmdTree->SetCommandTree( &pRoot, 0, TRUE);
  1090. if (FAILED (sc) )
  1091. {
  1092. if ( 0 != pQuery )
  1093. pQuery->Release();
  1094. pCmdTree->Release();
  1095. LogFail("SetCommandTree failed, %08x\n", sc);
  1096. }
  1097. ICommandProperties *pCmdProp = 0;
  1098. if (pobjOuterUnk)
  1099. sc = pobjOuterUnk->QueryInterface(IID_ICommandProperties, (void **)&pCmdProp);
  1100. else
  1101. sc = pQuery->QueryInterface(IID_ICommandProperties, (void **)&pCmdProp);
  1102. if (FAILED (sc) )
  1103. {
  1104. if ( 0 != pQuery )
  1105. pQuery->Release();
  1106. LogFail("QI for ICommandProperties failed\n");
  1107. }
  1108. //
  1109. // Set conflicting properties
  1110. //
  1111. const unsigned MAX_PROPS = 6;
  1112. DBPROPSET aPropSet[MAX_PROPS];
  1113. DBPROP aProp[MAX_PROPS];
  1114. ULONG cProp = 0;
  1115. aProp[cProp].dwPropertyID = DBPROP_IRowsetScroll;
  1116. aProp[cProp].dwOptions = DBPROPOPTIONS_REQUIRED;
  1117. aProp[cProp].dwStatus = 0; // Ignored
  1118. aProp[cProp].colid = dbcolNull;
  1119. aProp[cProp].vValue.vt = VT_BOOL;
  1120. aProp[cProp].vValue.boolVal = VARIANT_TRUE;
  1121. aPropSet[cProp].rgProperties = &aProp[cProp];
  1122. aPropSet[cProp].cProperties = 1;
  1123. aPropSet[cProp].guidPropertySet = DBPROPSET_ROWSET;
  1124. cProp++;
  1125. aProp[cProp].dwPropertyID = DBPROP_BOOKMARKS;
  1126. aProp[cProp].dwOptions = DBPROPOPTIONS_REQUIRED;
  1127. aProp[cProp].dwStatus = 0; // Ignored
  1128. aProp[cProp].colid = dbcolNull;
  1129. aProp[cProp].vValue.vt = VT_BOOL;
  1130. aProp[cProp].vValue.boolVal = VARIANT_FALSE;
  1131. aPropSet[cProp].rgProperties = &aProp[cProp];
  1132. aPropSet[cProp].cProperties = 1;
  1133. aPropSet[cProp].guidPropertySet = DBPROPSET_ROWSET;
  1134. cProp++;
  1135. sc = pCmdProp->SetProperties( cProp, aPropSet );
  1136. //pCmdProp->Release();
  1137. if ( FAILED(sc) || DB_S_ERRORSOCCURRED == sc )
  1138. {
  1139. if ( 0 != pQuery )
  1140. pQuery->Release();
  1141. LogError("ICommandProperties::SetProperties failed\n");
  1142. cFailures++;
  1143. }
  1144. IRowset * pRowset = 0;
  1145. sc = pQuery->Execute( 0, // no aggr. IUnknown
  1146. IID_IRowset, // IID for i/f to return
  1147. 0, // disp. params
  1148. 0, // count of rows affected
  1149. (IUnknown **)&pRowset); // Returned interface
  1150. if (SUCCEEDED (sc))
  1151. {
  1152. if ( 0 == pRowset )
  1153. LogError("ICommand::Execute returned success(%x), but pRowset is null\n", sc);
  1154. else
  1155. LogError("ICommand::Execute returned success(%x) with conflicting props\n", sc);
  1156. if (DB_S_ERRORSOCCURRED == sc)
  1157. {
  1158. CheckPropertiesInError(pQuery);
  1159. }
  1160. pRowset->Release();
  1161. pCmdProp->Release();
  1162. pCmdTree->Release();
  1163. pQuery->Release();
  1164. Fail();
  1165. }
  1166. else // FAILED (sc)
  1167. {
  1168. if (DB_E_ERRORSOCCURRED != sc)
  1169. {
  1170. LogError("ICommand::Execute with conflicing props failed, %x\n", sc);
  1171. if (DB_E_ERRORSINCOMMAND == sc)
  1172. GetCommandTreeErrors(pCmdTree);
  1173. pCmdProp->Release();
  1174. pCmdTree->Release();
  1175. pQuery->Release();
  1176. Fail();
  1177. }
  1178. CheckPropertiesInError(pQuery, TRUE);
  1179. }
  1180. // TODO: check other combinations of conflicting properties
  1181. // check that execute succeeds on same ICommand after reset
  1182. // Set properties back to their default state
  1183. cProp = 0;
  1184. aProp[cProp].dwPropertyID = DBPROP_IRowsetLocate;
  1185. aProp[cProp].dwOptions = DBPROPOPTIONS_OPTIONAL;
  1186. aProp[cProp].dwStatus = 0; // Ignored
  1187. aProp[cProp].colid = dbcolNull;
  1188. aProp[cProp].vValue.vt = VT_BOOL;
  1189. aProp[cProp].vValue.boolVal = VARIANT_FALSE;
  1190. aPropSet[cProp].rgProperties = &aProp[cProp];
  1191. aPropSet[cProp].cProperties = 1;
  1192. aPropSet[cProp].guidPropertySet = DBPROPSET_ROWSET;
  1193. cProp++;
  1194. aProp[cProp].dwPropertyID = DBPROP_BOOKMARKS;
  1195. aProp[cProp].dwOptions = DBPROPOPTIONS_OPTIONAL;
  1196. aProp[cProp].dwStatus = 0; // Ignored
  1197. aProp[cProp].colid = dbcolNull;
  1198. aProp[cProp].vValue.vt = VT_BOOL;
  1199. aProp[cProp].vValue.boolVal = VARIANT_FALSE;
  1200. aPropSet[cProp].rgProperties = &aProp[cProp];
  1201. aPropSet[cProp].cProperties = 1;
  1202. aPropSet[cProp].guidPropertySet = DBPROPSET_ROWSET;
  1203. cProp++;
  1204. aProp[cProp].dwPropertyID = DBPROP_IRowsetScroll;
  1205. aProp[cProp].dwOptions = DBPROPOPTIONS_OPTIONAL;
  1206. aProp[cProp].dwStatus = 0; // Ignored
  1207. aProp[cProp].colid = dbcolNull;
  1208. aProp[cProp].vValue.vt = VT_BOOL;
  1209. aProp[cProp].vValue.boolVal = VARIANT_FALSE;
  1210. aPropSet[cProp].rgProperties = &aProp[cProp];
  1211. aPropSet[cProp].cProperties = 1;
  1212. aPropSet[cProp].guidPropertySet = DBPROPSET_ROWSET;
  1213. cProp++;
  1214. sc = pCmdProp->SetProperties( cProp, aPropSet );
  1215. pCmdProp->Release();
  1216. if (FAILED (sc) )
  1217. {
  1218. LogError("ICommandProperties::SetProperties failed, %08x\n", sc);
  1219. if (DB_E_ERRORSINCOMMAND == sc)
  1220. {
  1221. GetCommandTreeErrors(pCmdTree);
  1222. }
  1223. if (DB_E_ERRORSOCCURRED == sc)
  1224. {
  1225. CheckPropertiesInError(pQuery);
  1226. }
  1227. pQuery->Release();
  1228. pCmdTree->Release();
  1229. Fail();
  1230. }
  1231. pQuery->Release();
  1232. if ( 0 == ppCmdTree )
  1233. {
  1234. pCmdTree->Release();
  1235. }
  1236. else
  1237. {
  1238. *ppCmdTree = pCmdTree;
  1239. }
  1240. return;
  1241. }
  1242. #ifdef DO_CATEG_TESTS
  1243. //+-------------------------------------------------------------------------
  1244. //
  1245. // Function: SingleLevelCategTest, public
  1246. //
  1247. // Synopsis: Basic query categorization feature test.
  1248. //
  1249. // History: 30 Mar 95 dlee Created
  1250. //
  1251. // Notes: Just looks for files in the system directory.
  1252. //
  1253. //--------------------------------------------------------------------------
  1254. void SingleLevelCategTest()
  1255. {
  1256. LogProgress( "Non-content categorization query\n" );
  1257. SCODE sc;
  1258. //
  1259. // Find system directory
  1260. //
  1261. WCHAR wcsSysDir[MAX_PATH];
  1262. #if 0
  1263. wcscpy(wcsSysDir,L"g:\\winnt\\system32");
  1264. #else
  1265. if( !GetSystemDirectory( wcsSysDir, sizeof(wcsSysDir) / sizeof(WCHAR) ) )
  1266. LogFail( "Unable to determine system directory.\n" );
  1267. #endif
  1268. //
  1269. // Get name, size and class id for *.exe, *.dll, *.doc, and *.sys
  1270. //
  1271. CDbColumns cols(8);
  1272. cols.Add( psClassid, 0 );
  1273. cols.Add( psSize, 1 );
  1274. cols.Add( psWriteTime, 2 );
  1275. cols.Add( psAttr, 3 );
  1276. cols.Add( psName, 4 );
  1277. cols.Add( psPath, 5 );
  1278. cols.Add( psSelf, 6 );
  1279. cols.Add( psBookmark, 7);
  1280. CDbNestingNode nest;
  1281. nest.AddGroupingColumn( psSize );
  1282. nest.AddParentColumn( psBookmark );
  1283. nest.AddParentColumn( psSize );
  1284. nest.AddChildColumn( psClassid );
  1285. nest.AddChildColumn( psSize );
  1286. nest.AddChildColumn( psWriteTime );
  1287. nest.AddChildColumn( psAttr );
  1288. nest.AddChildColumn( psName );
  1289. nest.AddChildColumn( psPath );
  1290. nest.AddChildColumn( psSelf );
  1291. nest.AddChildColumn( psBookmark);
  1292. CDbPropertyRestriction rst;
  1293. rst.SetRelation( DBOP_like );
  1294. rst.SetProperty( psName );
  1295. rst.SetValue( L"*.|(exe|,dll|,doc|,sys|,zzz|)" );
  1296. CDbSelectNode * pSelect = new CDbSelectNode();
  1297. pSelect->AddRestriction( rst.Clone() );
  1298. nest.AddTable( pSelect );
  1299. pSelect = 0;
  1300. IRowset * pRowsets[2];
  1301. ICommandTree * pCmdTree = 0;
  1302. InstantiateMultipleRowsets(
  1303. QUERY_SHALLOW, // Depth
  1304. wcsSysDir, // Scope
  1305. nest.Clone(), // DBCOMMANDTREE
  1306. IID_IRowsetScroll, // IID for i/f to return
  1307. 2,
  1308. (IUnknown **)pRowsets,
  1309. &pCmdTree );
  1310. IRowset *pRowsetCateg = pRowsets[0];
  1311. IRowset *pRowset = pRowsets[1];
  1312. //
  1313. // Verify columns
  1314. //
  1315. CDbColumns chapCols(3);
  1316. chapCols.Add( psBookmark, 0 );
  1317. chapCols.Add( psSize, 1 );
  1318. chapCols.Add( psChapt, 2 ); // chapt must be last since it is added to
  1319. // the end automatically above.
  1320. CheckColumns( pRowsetCateg, chapCols );
  1321. CheckColumns( pRowset, cols );
  1322. if ( !WaitForCompletion( pRowset, FALSE ) )
  1323. {
  1324. pCmdTree->Release();
  1325. pRowset->Release();
  1326. pRowsetCateg->Release();
  1327. LogFail( "Downlevel query unsuccessful.\n" );
  1328. }
  1329. //
  1330. // Do basic function tests.
  1331. //
  1332. FetchTest(pRowset);
  1333. //
  1334. // Test SetBindings, GetBindings, Move and Scroll
  1335. //
  1336. BindingTest(pRowset);
  1337. BindingTest(pCmdTree, TRUE);
  1338. CategTest(0, pRowsetCateg, pRowset, cBasicTestCols);
  1339. pCmdTree->Release();
  1340. pRowset->Release();
  1341. pRowsetCateg->Release();
  1342. } //SingleLevelCategTest
  1343. #define MAX_CHAPT_LENGTH 32
  1344. static DBBINDING aCategCols[] =
  1345. {
  1346. {
  1347. 0, sizeof DBLENGTH,
  1348. 0, 0,
  1349. 0,0,0,
  1350. DBPART_VALUE|DBPART_LENGTH,
  1351. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  1352. MAX_CHAPT_LENGTH,
  1353. 0, DBTYPE_BYTES,
  1354. 0,0 },
  1355. };
  1356. const ULONG cCategCols = sizeof aCategCols / sizeof aCategCols[0];
  1357. static DBBINDING aSizeCol[] =
  1358. {
  1359. {
  1360. 0, 0,
  1361. 0, 0,
  1362. 0,0,0,
  1363. DBPART_VALUE,
  1364. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  1365. sizeof LONGLONG,
  1366. 0, DBTYPE_UI8,
  1367. 0, 0 },
  1368. };
  1369. static DBBINDING aAttrCol[] =
  1370. {
  1371. {
  1372. 0, 0,
  1373. 0, 0,
  1374. 0,0,0,
  1375. DBPART_VALUE,
  1376. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  1377. sizeof LONG,
  1378. 0, DBTYPE_I4,
  1379. 0, 0 },
  1380. };
  1381. struct ChaptBinding
  1382. {
  1383. DBLENGTH len;
  1384. ULONG chapt; // because I know the first 4 bytes are the chapt
  1385. char abChapt[MAX_CHAPT_LENGTH - sizeof ULONG];
  1386. };
  1387. void CategTest(
  1388. HCHAPTER hUpperChapt,
  1389. IRowset * pRowsetCateg,
  1390. IRowset * pRowset,
  1391. unsigned cCols )
  1392. {
  1393. LogProgress( " Categorization test\n" );
  1394. BOOL fBackwardFetch = GetBooleanProperty( pRowset, DBPROP_CANFETCHBACKWARDS );
  1395. BOOL fCanHoldRows = GetBooleanProperty( pRowset, DBPROP_CANHOLDROWS );
  1396. if ( !fBackwardFetch || !fCanHoldRows )
  1397. LogProgress("WARNING: Categorized backward fetch test disabled\n");
  1398. IUnknown * pAccessor = pRowsetCateg;
  1399. HACCESSOR hAccCateg = MapColumns( pAccessor,
  1400. cCategCols, aCategCols, &psChapt);
  1401. HACCESSOR hAccSize = MapColumns( pRowsetCateg,
  1402. 1, aSizeCol, &psSize);
  1403. IRowsetLocate * pRLC = 0;
  1404. SCODE sc = pRowsetCateg->QueryInterface( IID_IRowsetLocate,
  1405. (void **)&pRLC);
  1406. if (FAILED(sc) || pRLC == 0)
  1407. LogFail("QueryInterface to IRowsetLocate failed\n");
  1408. IRowsetIdentity * pRowsetIdentity = 0;
  1409. sc = pRowsetCateg->QueryInterface( IID_IRowsetIdentity,
  1410. (void **)&pRowsetIdentity);
  1411. if (FAILED(sc) && (sc != E_NOINTERFACE || pRowsetIdentity != 0)) {
  1412. LogError("QueryInterface to IRowsetIdentity failed (%x)\n", sc);
  1413. pRowsetIdentity = 0;
  1414. cFailures++;
  1415. }
  1416. IChapteredRowset * pChapteredRowset = 0;
  1417. sc = pRowset->QueryInterface( IID_IChapteredRowset,
  1418. (void **)&pChapteredRowset);
  1419. if (FAILED(sc)) {
  1420. LogError("QueryInterface to IChapteredRowset failed (%x)\n", sc);
  1421. pChapteredRowset = 0;
  1422. cFailures++;
  1423. }
  1424. IRowsetScroll * pRS = 0;
  1425. sc = pRowset->QueryInterface( IID_IRowsetScroll,
  1426. (void **)&pRS);
  1427. if (FAILED(sc) || pRS == 0)
  1428. LogFail("QueryInterface to IRowsetScroll failed\n");
  1429. SCODE scHier = S_OK;
  1430. HROW ahRows[10];
  1431. HROW* phRows = ahRows;
  1432. DBCOUNTITEM cCategories = 0;
  1433. DBCOUNTITEM cRowsTotal = 0;
  1434. DBCOUNTITEM cRowsReturned = 0;
  1435. LONGLONG llSizePrev = -1;
  1436. while (scHier != DB_S_ENDOFROWSET)
  1437. {
  1438. scHier = pRLC->GetNextRows( hUpperChapt, 0, 10, &cRowsReturned, &phRows);
  1439. if (FAILED(scHier))
  1440. LogFail("pRLC->GetNextRows failed: 0x%lx\n", scHier);
  1441. if ( 0 == cRowsReturned )
  1442. {
  1443. if ( DB_S_ENDOFROWSET != scHier )
  1444. LogFail("pRLC->GetNextRows bad return at end of rowset: 0x%lx\n", scHier);
  1445. continue;
  1446. }
  1447. cCategories += cRowsReturned;
  1448. HCHAPTER hLastChapter = DB_NULL_HCHAPTER;
  1449. for (ULONG row = 0; row < cRowsReturned; row++)
  1450. {
  1451. ChaptBinding data;
  1452. SCODE sc = pRLC->GetData(phRows[row], hAccCateg, &data);
  1453. if ( FAILED( sc ) )
  1454. LogFail("Can't get category data in CategTest()\n");
  1455. LONGLONG llSize;
  1456. sc = pRLC->GetData(phRows[row], hAccSize, &llSize);
  1457. if ( FAILED( sc ) )
  1458. LogFail("Can't get size data in CategTest()\n");
  1459. if (fVerbose > 1)
  1460. printf( " category, file size: %lx, %d\n",
  1461. data.chapt,
  1462. (int) llSize );
  1463. if ( llSize == llSizePrev )
  1464. LogFail("Duplicate size categories\n");
  1465. if ( llSizePrev > llSize )
  1466. LogFail("categories unsorted by size\n");
  1467. llSizePrev = llSize;
  1468. DBCOUNTITEM cRows;
  1469. sc = pRS->GetApproximatePosition( data.chapt, 0, 0, 0, &cRows );
  1470. if ( FAILED( sc ) )
  1471. LogFail("GetApproximatePosition with chapter failed %x\n", sc);
  1472. cRowsTotal += cRows;
  1473. // then test fetching rows in the category
  1474. BasicTest(pRowset, FALSE, data.chapt, cCols, FALSE);
  1475. MoveTest(pRowset, data.chapt);
  1476. if (cCategories == cRowsReturned && 0 == row &&
  1477. DB_NULL_HCHAPTER == hUpperChapt)
  1478. {
  1479. // Do testing on entire base rowset
  1480. BasicTest(pRowset, FALSE, DB_NULL_HCHAPTER, cCols, FALSE);
  1481. MoveTest(pRowset, DB_NULL_HCHAPTER);
  1482. }
  1483. if (pChapteredRowset && row != (cRowsReturned - 1))
  1484. {
  1485. ULONG ulRefCnt = 10;
  1486. sc = pChapteredRowset->ReleaseChapter( data.chapt, &ulRefCnt );
  1487. if ( FAILED( sc ) )
  1488. {
  1489. LogError("ReleaseChapter failed, sc = %x\n", sc);
  1490. cFailures++;
  1491. }
  1492. else if ( ulRefCnt != 0 )
  1493. {
  1494. LogError("ReleaseChapter returned bad refcount: got %d, exp 0\n", ulRefCnt);
  1495. cFailures++;
  1496. }
  1497. }
  1498. else
  1499. hLastChapter = data.chapt;
  1500. }
  1501. if (pChapteredRowset)
  1502. {
  1503. ULONG ulRefCnt = 10;
  1504. sc = pChapteredRowset->AddRefChapter( hLastChapter, &ulRefCnt );
  1505. if ( FAILED( sc ) )
  1506. {
  1507. LogError("AddRefChapter failed, sc = %x\n", sc);
  1508. cFailures++;
  1509. }
  1510. else if ( ulRefCnt != 2 )
  1511. {
  1512. LogError("AddRefChapter returned bad refcount: %d\n", ulRefCnt);
  1513. cFailures++;
  1514. }
  1515. }
  1516. if ( fBackwardFetch && fCanHoldRows )
  1517. {
  1518. HROW ahRows2[10];
  1519. HROW* phRows2 = ahRows2;
  1520. DBCOUNTITEM cRowsRet2 = 0;
  1521. DBROWOFFSET oRows = - (DBROWOFFSET)cRowsReturned;
  1522. // fetch the categories BACKWARD to test GetNextRows behavior
  1523. // over chapters.
  1524. sc = pRLC->GetNextRows( hUpperChapt, 0, oRows,
  1525. &cRowsRet2, &phRows2);
  1526. if (FAILED(sc))
  1527. LogFail("pRLC->GetNextRows backward fetch failed: 0x%lx\n", sc);
  1528. if ( cRowsRet2 != cRowsReturned )
  1529. {
  1530. LogFail("pRLC->GetNextRows different row count on fwd/bkwd fetch: %d %d\n",
  1531. cRowsReturned, cRowsRet2);
  1532. }
  1533. // The first row retrieved in ahRows2 is the last retrieved in
  1534. // ahRows. Fetch the chapter again and check its refcount to see
  1535. // if it was collapsed properly.
  1536. if (pChapteredRowset)
  1537. {
  1538. ChaptBinding data;
  1539. sc = pRLC->GetData(phRows2[0], hAccCateg, &data);
  1540. if ( FAILED( sc ) )
  1541. LogFail("Can't re-fetch category data in CategTest()\n");
  1542. ULONG ulRefCnt = 10;
  1543. sc = pChapteredRowset->ReleaseChapter( data.chapt, &ulRefCnt );
  1544. if ( FAILED( sc ) )
  1545. {
  1546. LogError("ReleaseChapter failed on chapt refetch, sc = %x\n", sc);
  1547. cFailures++;
  1548. }
  1549. else if ( ulRefCnt != 2 )
  1550. {
  1551. LogError("ReleaseChapter returned bad refcount: got %d, exp 2\n", ulRefCnt);
  1552. cFailures++;
  1553. }
  1554. else
  1555. {
  1556. pChapteredRowset->ReleaseChapter( data.chapt, &ulRefCnt );
  1557. pChapteredRowset->ReleaseChapter( data.chapt, &ulRefCnt );
  1558. }
  1559. }
  1560. // Reverse the order of the rows for HROW identity check
  1561. unsigned i, j;
  1562. for (i=0, j=(unsigned)(cRowsRet2-1); i < j; i++, j--)
  1563. {
  1564. HROW hrTmp = ahRows2[i];
  1565. ahRows2[i] = ahRows2[j];
  1566. ahRows2[j] = hrTmp;
  1567. }
  1568. int cFailed = CheckHrowIdentity( pRowsetIdentity, 0,
  1569. cRowsReturned, ahRows,
  1570. cRowsRet2, ahRows2 );
  1571. if ( cFailed > 0 )
  1572. {
  1573. LogFail( "Backwards category fetch CheckHrowIdentity returned %d\n", cFailed );
  1574. }
  1575. // Release first row in handle array, use that position to refetch
  1576. // last row in array.
  1577. sc = pRLC->ReleaseRows( 1, phRows2, 0, 0, 0 );
  1578. DBCOUNTITEM cRowsRet3 = 0;
  1579. sc = pRLC->GetNextRows( hUpperChapt, cRowsRet2-1, 1,
  1580. &cRowsRet3, &phRows2);
  1581. if (FAILED(sc))
  1582. LogFail("pRLC->GetNextRows re-fetch failed: 0x%lx\n", sc);
  1583. if ( cRowsRet3 != 1 )
  1584. {
  1585. LogFail("pRLC->GetNextRows unexpected row count on re-fetch: %d\n",
  1586. cRowsRet3);
  1587. }
  1588. cFailed = CheckHrowIdentity( pRowsetIdentity, cRowsRet2-1,
  1589. 1, ahRows2,
  1590. 1, ahRows2 );
  1591. if ( cFailed > 0 )
  1592. {
  1593. LogFail( "Category re-fetch CheckHrowIdentity returned %d\n", cFailed );
  1594. }
  1595. sc = pRLC->ReleaseRows( cRowsRet2, phRows2, 0, 0, 0 );
  1596. }
  1597. sc = pRLC->ReleaseRows( cRowsReturned, phRows, 0, 0, 0 );
  1598. }
  1599. if (cCategories == 0)
  1600. LogFail("No categories found\n");
  1601. DBCOUNTITEM cRows;
  1602. sc = pRS->GetApproximatePosition( DB_NULL_HCHAPTER, 0, 0, 0, &cRows );
  1603. if ( FAILED( sc ) )
  1604. LogFail("GetApproximatePosition with NULL chapter failed %x\n", sc);
  1605. if (DB_NULL_HCHAPTER == hUpperChapt && cRowsTotal != cRows)
  1606. LogFail("Sum of rows in chapters(%d) is not same as total rows(%d)\n",
  1607. cRowsTotal, cRows);
  1608. if (DB_NULL_HCHAPTER != hUpperChapt && cRowsTotal > cRows)
  1609. LogFail("Sum of rows in chapters(%d) is greater than total rows(%d)\n",
  1610. cRowsTotal, cRows);
  1611. ReleaseAccessor( pAccessor, hAccCateg );
  1612. ReleaseAccessor( pRowsetCateg, hAccSize );
  1613. pRLC->Release();
  1614. pRS->Release();
  1615. if (pRowsetIdentity)
  1616. pRowsetIdentity->Release();
  1617. if (pChapteredRowset)
  1618. pChapteredRowset->Release();
  1619. } //CategTest
  1620. #endif // DO_CATEG_TESTS
  1621. #ifdef DO_MULTI_LEVEL_CATEG_TEST
  1622. void UpperLevelCategTest(
  1623. IRowset *pRowsetUpperCateg,
  1624. IRowset *pRowsetLowerCateg,
  1625. IRowset *pRowset,
  1626. unsigned cCols)
  1627. {
  1628. LogProgress( " Upper Level Categorization test\n" );
  1629. HACCESSOR hAccCateg = MapColumns( pRowsetUpperCateg,
  1630. cCategCols, aCategCols, &psChapt);
  1631. HACCESSOR hAccAttr = MapColumns( pRowsetUpperCateg,
  1632. 1, aAttrCol, &psAttr);
  1633. IRowsetLocate * pRLUC = 0;
  1634. SCODE sc = pRowsetUpperCateg->QueryInterface( IID_IRowsetLocate,
  1635. (void **)&pRLUC);
  1636. if (FAILED(sc) || pRLUC == 0)
  1637. LogFail("QueryInterface to IRowsetLocate failed\n");
  1638. IRowsetScroll * pRSLC = 0;
  1639. sc = pRowsetLowerCateg->QueryInterface( IID_IRowsetScroll,
  1640. (void **)&pRSLC);
  1641. if (FAILED(sc) || pRSLC == 0)
  1642. LogFail("QueryInterface to IRowsetScroll failed\n");
  1643. SCODE scHier = S_OK;
  1644. HROW ahRows[10];
  1645. HROW* phRows = ahRows;
  1646. ULONG cCategories = 0;
  1647. DBCOUNTITEM cRowsTotal = 0;
  1648. DBCOUNTITEM cRowsReturned = 0;
  1649. LONG lAttrPrev = 0xffffffff;
  1650. while (scHier != DB_S_ENDOFROWSET)
  1651. {
  1652. scHier = pRLUC->GetNextRows(0, 0, 10, &cRowsReturned, &phRows);
  1653. if (FAILED(scHier))
  1654. LogFail("pRLUC->GetNextRows failed: 0x%lx\n", scHier);
  1655. cCategories += (ULONG) cRowsReturned;
  1656. for (ULONG row = 0; row < cRowsReturned; row++)
  1657. {
  1658. ChaptBinding data;
  1659. SCODE sc = pRLUC->GetData(phRows[row],hAccCateg,&data);
  1660. if ( FAILED( sc ) )
  1661. LogFail("GetData in UpperLevelCategTest failed: 0x%lx\n",sc);
  1662. LONG lAttr;
  1663. sc = pRLUC->GetData(phRows[row],hAccAttr,&lAttr);
  1664. if ( FAILED( sc ) )
  1665. LogFail("GetData in UpperLevelCategTest failed: 0x%lx\n",sc);
  1666. if (fVerbose > 1)
  1667. printf( "upper level category, attr:: %lx, %lx\n",
  1668. data.chapt,
  1669. lAttr );
  1670. if ( lAttrPrev == lAttr )
  1671. LogFail("duplicate attrib categories\n");
  1672. if ( lAttrPrev > lAttr )
  1673. LogFail("categories unsorted by attrib\n");
  1674. lAttrPrev = lAttr;
  1675. DBCOUNTITEM cRows;
  1676. sc = pRSLC->GetApproximatePosition( data.chapt, 0, 0, 0, &cRows );
  1677. if ( FAILED( sc ) )
  1678. LogFail("GetApproximatePosition with chapter failed %x\n", sc);
  1679. cRowsTotal += cRows;
  1680. // then test fetching rows in the category
  1681. MoveTest( pRowsetLowerCateg,
  1682. data.chapt );
  1683. CategTest( data.chapt,
  1684. pRowsetLowerCateg,
  1685. pRowset,
  1686. cCols );
  1687. }
  1688. sc = pRLUC->ReleaseRows( cRowsReturned, phRows, 0, 0, 0 );
  1689. }
  1690. if (cCategories == 0)
  1691. LogFail("No categories found\n");
  1692. DBCOUNTITEM cRows;
  1693. sc = pRSLC->GetApproximatePosition( DB_NULL_HCHAPTER, 0, 0, 0, &cRows );
  1694. if ( FAILED( sc ) )
  1695. LogFail("GetApproximatePosition with NULL chapter failed %x\n", sc);
  1696. if (cRowsTotal != cRows)
  1697. LogFail("Sum of rows in chapters(%d) is not same as total rows(%d)\n",
  1698. cRowsTotal, cRows);
  1699. ReleaseAccessor( pRLUC, hAccCateg );
  1700. ReleaseAccessor( pRLUC, hAccAttr );
  1701. pRSLC->Release();
  1702. pRLUC->Release();
  1703. } //UpperLevelCategTest
  1704. //+-------------------------------------------------------------------------
  1705. //
  1706. // Function: MultiLevelCategTest, public
  1707. //
  1708. // Synopsis: Basic query categorization feature test.
  1709. //
  1710. // History: 30 Mar 95 dlee Created
  1711. //
  1712. // Notes: Just looks for files in the system directory.
  1713. //
  1714. //--------------------------------------------------------------------------
  1715. void MultiLevelCategTest()
  1716. {
  1717. LogProgress( "Non-content multi-level categorization query\n" );
  1718. SCODE sc;
  1719. WCHAR wcsSysDir[MAX_PATH];
  1720. #if 0
  1721. wcscpy(wcsSysDir,L"g:\\winnt\\system32");
  1722. #else
  1723. if( !GetSystemDirectory( wcsSysDir, sizeof(wcsSysDir) / sizeof(WCHAR) ) )
  1724. LogFail( "Unable to determine system directory.\n" );
  1725. #endif
  1726. //
  1727. // Get name, size and class id for *.exe, *.dll, *.doc, and *.sys
  1728. // Group on attribute, then size.
  1729. //
  1730. CDbColumns cols(8);
  1731. cols.Add( psClassid, 0 );
  1732. cols.Add( psSize, 1 );
  1733. cols.Add( psWriteTime, 2 );
  1734. cols.Add( psAttr, 3 );
  1735. cols.Add( psName, 4 );
  1736. cols.Add( psPath, 5 );
  1737. cols.Add( psSelf, 6 );
  1738. cols.Add( psBookmark, 7);
  1739. CDbNestingNode nest1;
  1740. nest1.AddGroupingColumn( psAttr );
  1741. nest1.AddParentColumn( psBookmark );
  1742. nest1.AddParentColumn( psAttr );
  1743. CDbNestingNode nest2;
  1744. nest2.AddGroupingColumn( psSize );
  1745. nest2.AddParentColumn( psBookmark );
  1746. nest2.AddParentColumn( psSize );
  1747. nest2.AddChildColumn( psClassid );
  1748. nest2.AddChildColumn( psSize );
  1749. nest2.AddChildColumn( psWriteTime );
  1750. nest2.AddChildColumn( psAttr );
  1751. nest2.AddChildColumn( psName );
  1752. nest2.AddChildColumn( psPath );
  1753. nest2.AddChildColumn( psSelf );
  1754. nest2.AddChildColumn( psBookmark);
  1755. CDbPropertyRestriction rst;
  1756. rst.SetRelation( DBOP_like );
  1757. rst.SetProperty( psName );
  1758. rst.SetValue( L"*.|(exe|,dll|,doc|,sys|,zzz|)" );
  1759. CDbSelectNode * pSelect = new CDbSelectNode();
  1760. pSelect->AddRestriction( rst.Clone() );
  1761. nest2.AddTable( pSelect );
  1762. pSelect = 0;
  1763. nest1.AddTable( nest2.Clone() );
  1764. IRowset * pRowsets[3];
  1765. ICommandTree * pCmdTree;
  1766. InstantiateMultipleRowsets(
  1767. QUERY_SHALLOW, // Depth
  1768. wcsSysDir, // Scope
  1769. nest1.Clone(), // DBCOMMANDTREE
  1770. IID_IRowsetScroll, // IID for i/f to return
  1771. 3,
  1772. (IUnknown **)pRowsets,
  1773. &pCmdTree );
  1774. IRowset *pRowsetUpperCateg = pRowsets[0];
  1775. IRowset *pRowsetLowerCateg = pRowsets[1];
  1776. IRowset *pRowset = pRowsets[2];
  1777. //
  1778. // Verify columns
  1779. //
  1780. CDbColumns chapCols(4);
  1781. chapCols.Add( psBookmark, 0 );
  1782. chapCols.Add( psAttr, 1 );
  1783. chapCols.Add( psChapt, 2 );
  1784. CheckColumns( pRowsetUpperCateg, chapCols );
  1785. chapCols.Add( psSize, 1 );
  1786. chapCols.Add( psChapt, 2 );
  1787. CheckColumns( pRowsetLowerCateg, chapCols );
  1788. CheckColumns( pRowset, cols );
  1789. if ( !WaitForCompletion( pRowset, FALSE ) )
  1790. {
  1791. pRowset->Release();
  1792. LogFail( "Downlevel query unsuccessful.\n" );
  1793. }
  1794. //
  1795. // Do basic function tests.
  1796. //
  1797. FetchTest(pRowset);
  1798. //
  1799. // Test SetBindings, GetBindings, Move and Scroll
  1800. //
  1801. BindingTest(pRowset);
  1802. BindingTest(pCmdTree, TRUE);
  1803. MoveTest( pRowsetUpperCateg );
  1804. UpperLevelCategTest( pRowsetUpperCateg,
  1805. pRowsetLowerCateg,
  1806. pRowset,
  1807. cBasicTestCols );
  1808. pCmdTree->Release();
  1809. pRowset->Release();
  1810. pRowsetUpperCateg->Release();
  1811. pRowsetLowerCateg->Release();
  1812. } //MultiLevelCategTest
  1813. #endif // DO_MULTI_LEVEL_CATEG_TEST
  1814. //+-------------------------------------------------------------------------
  1815. //
  1816. // Function: RunPropQuery, public
  1817. //
  1818. // Synopsis: Execute a retricted query and check results
  1819. //
  1820. // History:
  1821. //
  1822. //--------------------------------------------------------------------------
  1823. static DBBINDING aPropTestColsByRef[] =
  1824. {
  1825. { 0, 0 * (sizeof( PROPVARIANT * )), 0, 0,
  1826. 0, 0, 0,
  1827. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  1828. sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  1829. { 1, 1 * (sizeof( PROPVARIANT * )), 0, 0,
  1830. 0, 0, 0,
  1831. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  1832. sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  1833. { 2, 2 * (sizeof( PROPVARIANT * )), 0, 0,
  1834. 0, 0, 0,
  1835. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  1836. sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  1837. { 3, 3 * (sizeof( PROPVARIANT * )), 0, 0,
  1838. 0, 0, 0,
  1839. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  1840. sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  1841. { sizeof( PROPVARIANT * ), 4 * (sizeof( PROPVARIANT * )), 0, 0,
  1842. 0, 0, 0,
  1843. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  1844. sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  1845. { 5, 5 * (sizeof( PROPVARIANT * )), 0, 0,
  1846. 0, 0, 0,
  1847. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  1848. sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  1849. { 6, 6 * (sizeof( PROPVARIANT * )), 0, 0,
  1850. 0, 0, 0,
  1851. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  1852. sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  1853. { 7, 7 * (sizeof( PROPVARIANT * )), 0, 0,
  1854. 0, 0, 0,
  1855. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  1856. sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  1857. { 8, 8 * (sizeof( PROPVARIANT * )), 0, 0,
  1858. 0, 0, 0,
  1859. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  1860. sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  1861. { 9, 9 * (sizeof( PROPVARIANT * )), 0, 0,
  1862. 0, 0, 0,
  1863. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  1864. sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  1865. { 10,10* (sizeof( PROPVARIANT * )), 0, 0,
  1866. 0, 0, 0,
  1867. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  1868. sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  1869. { 11,11* (sizeof( PROPVARIANT * )), 0, 0,
  1870. 0, 0, 0,
  1871. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  1872. sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  1873. { 12,12* (sizeof( PROPVARIANT * )), 0, 0,
  1874. 0, 0, 0,
  1875. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  1876. sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  1877. { 13,13* (sizeof( PROPVARIANT * )), 0, 0,
  1878. 0, 0, 0,
  1879. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  1880. sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  1881. };
  1882. const ULONG cPropTestColsByRef = sizeof aPropTestColsByRef /
  1883. sizeof aPropTestColsByRef[0];
  1884. LPWSTR aPropTestColNames[] = {
  1885. L"TestProp1",
  1886. L"TestProp2",
  1887. L"Author",
  1888. L"Keywords",
  1889. L"RelevantWords",
  1890. L"MyBlob",
  1891. L"MyGuid",
  1892. L"ManyRW",
  1893. L"SecurityTest",
  1894. L"TestProp10",
  1895. L"TestProp11",
  1896. L"TestProp12",
  1897. L"TestProp21",
  1898. L"TestProp22",
  1899. L"Path",
  1900. };
  1901. void RunPropQueryByRefBindings(
  1902. ICommand * pQuery,
  1903. CDbRestriction & PropRst,
  1904. unsigned cExpectedHits,
  1905. unsigned numTest )
  1906. {
  1907. //
  1908. // Get twelve properties back
  1909. //
  1910. CDbColumns cols(cPropTestColsByRef);
  1911. cols.Add( psTestProperty1, 0 );
  1912. cols.Add( psTestProperty2, 1 );
  1913. cols.Add( psAuthor, 2 );
  1914. cols.Add( psKeywords, 3 );
  1915. cols.Add( psRelevantWords, 4 );
  1916. cols.Add( psBlobTest, 5 );
  1917. cols.Add( psGuidTest, 6 );
  1918. cols.Add( psManyRW, 7 );
  1919. cols.Add( psSecurityTest, 8 );
  1920. cols.Add( psTestProperty10, 9 );
  1921. cols.Add( psTestProperty11, 10 );
  1922. cols.Add( psTestProperty12, 11 );
  1923. cols.Add( psTestProperty21, 12 );
  1924. cols.Add( psTestProperty22, 13 );
  1925. if (isEven( numTest/2 ))
  1926. cols.Add( psPath, cols.Count() );
  1927. BOOL fSeq = isEven( numTest );
  1928. CDbSortSet ss(cPropSortColumns);
  1929. for (unsigned i = 0; i < cPropSortColumns; i++)
  1930. ss.Add (aPropSortCols[i], i);
  1931. //
  1932. // Do it!
  1933. //
  1934. CDbCmdTreeNode * pDbCmdTree = FormQueryTree( &PropRst,
  1935. cols,
  1936. fSeq ? 0 : &ss,
  1937. aPropTestColNames );
  1938. ICommandTree * pCmdTree = 0;
  1939. IRowsetScroll * pRowset = InstantiateRowset(
  1940. pQuery,
  1941. QUERY_SHALLOW, // Depth
  1942. 0, // Scope
  1943. pDbCmdTree, // DBCOMMANDTREE
  1944. fSeq ? IID_IRowset : IID_IRowsetScroll, // IID for i/f to return
  1945. 0,
  1946. &pCmdTree );
  1947. //
  1948. // Verify columns
  1949. //
  1950. CheckColumns( pRowset, cols, TRUE );
  1951. if ( !WaitForCompletion( pRowset, TRUE ) )
  1952. {
  1953. LogError( "property query unsuccessful.\n" );
  1954. pCmdTree->Release();
  1955. pRowset->Release();
  1956. Fail();
  1957. }
  1958. //
  1959. // Get data
  1960. //
  1961. DBCOUNTITEM cRowsReturned = 0;
  1962. HROW* pgrhRows = 0;
  1963. SCODE sc = pRowset->GetNextRows(0, 0, 10, &cRowsReturned, &pgrhRows);
  1964. if ( FAILED( sc ) )
  1965. {
  1966. LogError( "IRowset->GetRowsAt A returned 0x%x\n", sc );
  1967. pCmdTree->Release();
  1968. pRowset->Release();
  1969. Fail();
  1970. }
  1971. if ( 0 == cExpectedHits )
  1972. {
  1973. pCmdTree->Release();
  1974. pRowset->Release();
  1975. if ( cRowsReturned > 0 )
  1976. LogFail("RunPropQueryByRefBindings, %d returned rows, expected 0\n",
  1977. cRowsReturned);
  1978. else
  1979. return;
  1980. }
  1981. if (sc != DB_S_ENDOFROWSET &&
  1982. cRowsReturned != 10)
  1983. {
  1984. LogError( "IRowset->GetRowsAt B returned %d of %d rows,"
  1985. " status (%x) != DB_S_ENDOFROWSET\n",
  1986. cRowsReturned, 10,
  1987. sc);
  1988. pCmdTree->Release();
  1989. pRowset->Release();
  1990. #if defined(UNIT_TEST)
  1991. cFailures++;
  1992. return;
  1993. #else
  1994. Fail();
  1995. #endif
  1996. }
  1997. //
  1998. // Expect 1 or 2 hits
  1999. //
  2000. if (sc != DB_S_ENDOFROWSET || cRowsReturned != cExpectedHits)
  2001. {
  2002. LogError( "IRowset->GetRowsAt C returned %d rows (expected %d),"
  2003. " status (%x)\n",
  2004. cRowsReturned, cExpectedHits, sc );
  2005. pCmdTree->Release();
  2006. pRowset->Release();
  2007. #if defined(UNIT_TEST)
  2008. cFailures++;
  2009. return;
  2010. #else
  2011. Fail();
  2012. #endif
  2013. }
  2014. //
  2015. // Patch the column index numbers with true column ids
  2016. //
  2017. DBID aDbCols[cPropTestColsByRef];
  2018. aDbCols[0] = psTestProperty1;
  2019. aDbCols[1] = psTestProperty2;
  2020. aDbCols[2] = psAuthor;
  2021. aDbCols[3] = psKeywords;
  2022. aDbCols[4] = psRelevantWords;
  2023. aDbCols[5] = psBlobTest;
  2024. aDbCols[6] = psGuidTest;
  2025. aDbCols[7] = psManyRW;
  2026. aDbCols[8] = psSecurityTest;
  2027. aDbCols[9] = psTestProperty10;
  2028. aDbCols[10] = psTestProperty11;
  2029. aDbCols[11] = psTestProperty12;
  2030. aDbCols[12] = psTestProperty21;
  2031. aDbCols[13] = psTestProperty22;
  2032. IUnknown * pAccessor = (IUnknown *) pRowset; // hAccessor must be created on rowset
  2033. // to be used with rowset->GetData below
  2034. HACCESSOR hAccessor = MapColumns( pAccessor, cPropTestColsByRef,
  2035. aPropTestColsByRef, aDbCols, TRUE);
  2036. //
  2037. // Fetch the data
  2038. //
  2039. PROPVARIANT * aVarnt[cPropTestColsByRef];
  2040. for (unsigned row = 0; row < cRowsReturned; row++)
  2041. {
  2042. sc = pRowset->GetData(pgrhRows[row], hAccessor, aVarnt);
  2043. if (S_OK != sc)
  2044. {
  2045. LogError("IRowset->GetData returned 0x%x (expected 0)\n",sc);
  2046. pCmdTree->Release();
  2047. pRowset->Release();
  2048. Fail();
  2049. }
  2050. //
  2051. // Verify the data.
  2052. //
  2053. // Ascending sort, prop1 > prop1Alternate.
  2054. // If one hit, it's PROP1_VAL, not the alternate.
  2055. // prop1=1234, alternate=123
  2056. BOOL fAlternate = FALSE;
  2057. if ( fSeq )
  2058. {
  2059. if ( 1 == cRowsReturned )
  2060. {
  2061. varProp1.lVal = PROP1_VAL;
  2062. CheckPropertyValue( *aVarnt[0], varProp1 );
  2063. }
  2064. else
  2065. {
  2066. // no sort order -- it's either prop1 or alternate
  2067. if ( PROP1_TYPE != aVarnt[0]->vt )
  2068. LogFail( "bad datatype for prop1: 0x%x\n", aVarnt[0]->vt );
  2069. if ( PROP1_VAL != aVarnt[0]->lVal &&
  2070. PROP1_VAL_Alternate != aVarnt[0]->lVal )
  2071. LogFail( "bad value for prop1: 0x%x\n", aVarnt[0]->lVal );
  2072. fAlternate = aVarnt[0]->lVal == PROP1_VAL_Alternate;
  2073. }
  2074. }
  2075. else
  2076. {
  2077. fAlternate = (0 == row) && (1 != cRowsReturned);
  2078. varProp1.lVal = fAlternate ?
  2079. PROP1_VAL_Alternate :
  2080. PROP1_VAL;
  2081. CheckPropertyValue( *aVarnt[0], varProp1 );
  2082. }
  2083. CheckPropertyValue( *aVarnt[1], varProp2 );
  2084. CheckPropertyValue( *aVarnt[2], varProp3 );
  2085. CheckPropertyValue( *aVarnt[3], varProp4 );
  2086. CheckPropertyValue( *aVarnt[4], varProp5 );
  2087. CheckPropertyValue( *aVarnt[5], varProp6 );
  2088. CheckPropertyValue( *aVarnt[6], varProp7 );
  2089. CheckPropertyValue( *aVarnt[7], fAlternate ? varProp8A : varProp8 );
  2090. CheckPropertyValue( *aVarnt[8], varProp9 );
  2091. CheckPropertyValue( *aVarnt[9], varProp10 );
  2092. if ( aVarnt[10]->vt == VT_BSTR &&
  2093. SysStringLen( aVarnt[10]->bstrVal) < 1000 )
  2094. {
  2095. CheckPropertyValue( *aVarnt[10], varProp11 );
  2096. }
  2097. else
  2098. {
  2099. CheckPropertyValue( *aVarnt[10], varProp11A );
  2100. }
  2101. CheckPropertyValue( *aVarnt[11], varProp12 );
  2102. CheckPropertyValue( *aVarnt[12], varProp21 );
  2103. CheckPropertyValue( *aVarnt[13], varProp22 );
  2104. }
  2105. sc = pRowset->ReleaseRows( cRowsReturned, pgrhRows, 0, 0, 0);
  2106. if (S_OK != sc)
  2107. {
  2108. LogError("IRowset->ReleaseRows returned 0x%x (expected 0)\n",sc);
  2109. pCmdTree->Release();
  2110. pRowset->Release();
  2111. Fail();
  2112. }
  2113. CoTaskMemFree(pgrhRows);
  2114. pgrhRows = 0;
  2115. //
  2116. // Clean up.
  2117. //
  2118. ReleaseAccessor( pAccessor, hAccessor);
  2119. pCmdTree->Release();
  2120. pRowset->Release();
  2121. } //RunPropQueryByRefBindings
  2122. struct SPropTestColsTight
  2123. {
  2124. int p1_i4;
  2125. WCHAR * p2_pwc;
  2126. WCHAR * p3_pwc;
  2127. int dummy1; // vectors need 8 byte alignment
  2128. DBVECTOR p4_vpwc;
  2129. DBVECTOR p5_vi;
  2130. PROPVARIANT* p6_pvar;
  2131. GUID * p7_pguid;
  2132. DBVECTOR p8_vi;
  2133. SAFEARRAY * p8a_ai;
  2134. int p9_i4;
  2135. WCHAR * p10_pwc;
  2136. BSTR p11_pwc;
  2137. DBVECTOR p12_vpwc;
  2138. CLIPDATA * p21_pclipdata;
  2139. int dummy3; // vectors need 8 byte alignment
  2140. CACLIPDATA p22_caclipdata;
  2141. WCHAR * p2a_pwc;
  2142. DBLENGTH p1_cb;
  2143. DBLENGTH p2_cb;
  2144. DBLENGTH p3_cb;
  2145. DBLENGTH p4_cb;
  2146. DBLENGTH p5_cb;
  2147. DBLENGTH p6_cb;
  2148. DBLENGTH p7_cb;
  2149. DBLENGTH p8_cb;
  2150. DBLENGTH p8a_cb;
  2151. DBLENGTH p9_cb;
  2152. DBLENGTH p10_cb;
  2153. DBLENGTH p11_cb;
  2154. DBLENGTH p12_cb;
  2155. DBLENGTH p21_cb;
  2156. DBLENGTH p22_cb;
  2157. DBLENGTH p2a_cb;
  2158. ULONG p1_status;
  2159. ULONG p2_status;
  2160. ULONG p3_status;
  2161. ULONG p4_status;
  2162. ULONG p5_status;
  2163. ULONG p6_status;
  2164. ULONG p7_status;
  2165. ULONG p8_status;
  2166. ULONG p8a_status;
  2167. ULONG p9_status;
  2168. ULONG p10_status;
  2169. ULONG p11_status;
  2170. ULONG p12_status;
  2171. ULONG p21_status;
  2172. ULONG p22_status;
  2173. ULONG p2a_status;
  2174. };
  2175. #define DBTYPE_BRWSTR ( DBTYPE_BYREF | DBTYPE_WSTR )
  2176. static DBBINDING aPropTestColsTight[] =
  2177. {
  2178. { 0,
  2179. offsetof(SPropTestColsTight,p1_i4),
  2180. offsetof(SPropTestColsTight,p1_cb),
  2181. offsetof(SPropTestColsTight,p1_status),
  2182. 0,0,0,
  2183. ALLPARTS,
  2184. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  2185. sizeof ULONG, 0,
  2186. DBTYPE_I4,
  2187. 0, 0 },
  2188. { 1,
  2189. offsetof(SPropTestColsTight,p2_pwc),
  2190. offsetof(SPropTestColsTight,p2_cb),
  2191. offsetof(SPropTestColsTight,p2_status),
  2192. 0,0,0,
  2193. ALLPARTS,
  2194. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  2195. sizeof (WCHAR *), 0,
  2196. DBTYPE_BRWSTR,
  2197. 0, 0 },
  2198. { 2,
  2199. offsetof(SPropTestColsTight,p3_pwc),
  2200. offsetof(SPropTestColsTight,p3_cb),
  2201. offsetof(SPropTestColsTight,p3_status),
  2202. 0,0,0,
  2203. ALLPARTS,
  2204. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  2205. sizeof (WCHAR *), 0,
  2206. DBTYPE_BRWSTR,
  2207. 0, 0 },
  2208. { 3,
  2209. offsetof(SPropTestColsTight,p4_vpwc),
  2210. offsetof(SPropTestColsTight,p4_cb),
  2211. offsetof(SPropTestColsTight,p4_status),
  2212. 0,0,0,
  2213. ALLPARTS,
  2214. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  2215. sizeof DBVECTOR, 0,
  2216. DBTYPE_VECTOR|VT_LPWSTR,
  2217. 0, 0 },
  2218. { 4,
  2219. offsetof(SPropTestColsTight,p5_vi),
  2220. offsetof(SPropTestColsTight,p5_cb),
  2221. offsetof(SPropTestColsTight,p5_status),
  2222. 0,0,0,
  2223. ALLPARTS,
  2224. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  2225. sizeof DBVECTOR, 0,
  2226. DBTYPE_VECTOR|DBTYPE_I4,
  2227. 0, 0 },
  2228. { 5,
  2229. offsetof(SPropTestColsTight,p6_pvar),
  2230. offsetof(SPropTestColsTight,p6_cb),
  2231. offsetof(SPropTestColsTight,p6_status),
  2232. 0,0,0,
  2233. ALLPARTS,
  2234. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  2235. sizeof (PROPVARIANT *), 0,
  2236. DBTYPE_VARIANT|DBTYPE_BYREF,
  2237. 0, 0 },
  2238. { 6,
  2239. offsetof(SPropTestColsTight,p7_pguid),
  2240. offsetof(SPropTestColsTight,p7_cb),
  2241. offsetof(SPropTestColsTight,p7_status),
  2242. 0,0,0,
  2243. ALLPARTS,
  2244. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  2245. sizeof (GUID *), 0,
  2246. DBTYPE_GUID|DBTYPE_BYREF,
  2247. 0, 0 },
  2248. { 7,
  2249. offsetof(SPropTestColsTight,p8_vi),
  2250. offsetof(SPropTestColsTight,p8_cb),
  2251. offsetof(SPropTestColsTight,p8_status),
  2252. 0,0,0,
  2253. ALLPARTS,
  2254. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  2255. sizeof DBVECTOR, 0,
  2256. DBTYPE_VECTOR|DBTYPE_I4,
  2257. 0, 0 },
  2258. { 8,
  2259. offsetof(SPropTestColsTight,p9_i4),
  2260. offsetof(SPropTestColsTight,p9_cb),
  2261. offsetof(SPropTestColsTight,p9_status),
  2262. 0,0,0,
  2263. ALLPARTS,
  2264. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  2265. sizeof ULONG, 0,
  2266. DBTYPE_I4,
  2267. 0, 0 },
  2268. { 9,
  2269. offsetof(SPropTestColsTight,p10_pwc),
  2270. offsetof(SPropTestColsTight,p10_cb),
  2271. offsetof(SPropTestColsTight,p10_status),
  2272. 0,0,0,
  2273. ALLPARTS,
  2274. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  2275. sizeof (WCHAR *), 0,
  2276. DBTYPE_BRWSTR,
  2277. 0, 0 },
  2278. { 10,
  2279. offsetof(SPropTestColsTight,p11_pwc),
  2280. offsetof(SPropTestColsTight,p11_cb),
  2281. offsetof(SPropTestColsTight,p11_status),
  2282. 0,0,0,
  2283. ALLPARTS,
  2284. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  2285. sizeof (BSTR), 0,
  2286. DBTYPE_BSTR,
  2287. 0, 0 },
  2288. { 11,
  2289. offsetof(SPropTestColsTight,p12_vpwc),
  2290. offsetof(SPropTestColsTight,p12_cb),
  2291. offsetof(SPropTestColsTight,p12_status),
  2292. 0,0,0,
  2293. ALLPARTS,
  2294. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  2295. sizeof DBVECTOR, 0,
  2296. DBTYPE_VECTOR|DBTYPE_BSTR,
  2297. 0, 0 },
  2298. { 12,
  2299. offsetof(SPropTestColsTight,p21_pclipdata),
  2300. offsetof(SPropTestColsTight,p21_cb),
  2301. offsetof(SPropTestColsTight,p21_status),
  2302. 0,0,0,
  2303. ALLPARTS,
  2304. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  2305. sizeof( CLIPDATA * ), 0,
  2306. VT_CF | DBTYPE_BYREF,
  2307. 0, 0 },
  2308. { 13,
  2309. offsetof(SPropTestColsTight,p22_caclipdata),
  2310. offsetof(SPropTestColsTight,p22_cb),
  2311. offsetof(SPropTestColsTight,p22_status),
  2312. 0,0,0,
  2313. ALLPARTS,
  2314. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  2315. sizeof CACLIPDATA, 0,
  2316. DBTYPE_VECTOR | VT_CF,
  2317. 0, 0 },
  2318. { 14, // Prop 2 again, as a different type
  2319. offsetof(SPropTestColsTight,p2a_pwc),
  2320. offsetof(SPropTestColsTight,p2a_cb),
  2321. offsetof(SPropTestColsTight,p2a_status),
  2322. 0,0,0,
  2323. ALLPARTS,
  2324. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  2325. 30, 0,
  2326. DBTYPE_WSTR | DBTYPE_BYREF,
  2327. 0, 0 },
  2328. { 15, // Prop 8 again, as a different type
  2329. offsetof(SPropTestColsTight,p8a_ai),
  2330. offsetof(SPropTestColsTight,p8a_cb),
  2331. offsetof(SPropTestColsTight,p8a_status),
  2332. 0,0,0,
  2333. ALLPARTS,
  2334. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  2335. sizeof (SAFEARRAY *), 0,
  2336. DBTYPE_ARRAY|DBTYPE_I4,
  2337. 0, 0 },
  2338. };
  2339. const ULONG cPropTestColsTight = sizeof aPropTestColsTight /
  2340. sizeof aPropTestColsTight[0];
  2341. void RunPropQueryTightBindings(
  2342. ICommand * pQuery,
  2343. CDbRestriction & PropRst,
  2344. unsigned cExpectedHits,
  2345. unsigned numTest )
  2346. {
  2347. //
  2348. // Get twelve properties back
  2349. //
  2350. CDbColumns cols(cPropTestColsTight);
  2351. cols.Add( psTestProperty1, 0 );
  2352. cols.Add( psTestProperty2, 1 );
  2353. cols.Add( psAuthor, 2 );
  2354. cols.Add( psKeywords, 3 );
  2355. cols.Add( psRelevantWords, 4 );
  2356. cols.Add( psBlobTest, 5 );
  2357. cols.Add( psGuidTest, 6 );
  2358. cols.Add( psManyRW, 7 );
  2359. cols.Add( psSecurityTest, 8 );
  2360. cols.Add( psTestProperty10, 9 );
  2361. cols.Add( psTestProperty11, 10 );
  2362. cols.Add( psTestProperty12, 11 );
  2363. cols.Add( psTestProperty21, 12 );
  2364. cols.Add( psTestProperty22, 13 );
  2365. CDbSortSet ss(cPropSortColumns);
  2366. for (unsigned i = 0; i < cPropSortColumns; i++)
  2367. ss.Add (aPropSortCols[i], i);
  2368. //
  2369. // Do it!
  2370. //
  2371. CDbCmdTreeNode * pDbCmdTree = FormQueryTree(&PropRst, cols, &ss);
  2372. ICommandTree * pCmdTree = 0;
  2373. IRowsetScroll * pRowset = InstantiateRowset(
  2374. pQuery,
  2375. QUERY_SHALLOW, // Depth
  2376. 0, // Scope
  2377. pDbCmdTree, // DBCOMMANDTREE
  2378. IID_IRowsetScroll, // IID for i/f to return
  2379. 0,
  2380. &pCmdTree,
  2381. TRUE );
  2382. //
  2383. // Verify columns
  2384. //
  2385. CheckColumns( pRowset, cols, TRUE );
  2386. if ( !WaitForCompletion( pRowset, TRUE ) )
  2387. {
  2388. LogError( "property query unsuccessful.\n" );
  2389. pCmdTree->Release();
  2390. pRowset->Release();
  2391. Fail();
  2392. }
  2393. //
  2394. // Get data
  2395. //
  2396. DBCOUNTITEM cRowsReturned = 0;
  2397. HROW* pgrhRows = 0;
  2398. SCODE sc = pRowset->GetRowsAt(0,0, 1, &bmkFirst, 0, 10, &cRowsReturned,
  2399. &pgrhRows);
  2400. if ( FAILED( sc ) )
  2401. {
  2402. LogError( "IRowset->GetRowsAt D returned 0x%x\n", sc );
  2403. pCmdTree->Release();
  2404. pRowset->Release();
  2405. Fail();
  2406. }
  2407. if ( 0 == cExpectedHits )
  2408. {
  2409. pCmdTree->Release();
  2410. pRowset->Release();
  2411. if ( cRowsReturned > 0 )
  2412. {
  2413. LogError("RunPropQueryTightBindings, %d returned rows, expected 0\n",
  2414. cRowsReturned);
  2415. #if defined(UNIT_TEST)
  2416. cFailures++;
  2417. return;
  2418. #else
  2419. Fail();
  2420. #endif
  2421. }
  2422. else
  2423. return;
  2424. }
  2425. if (sc != DB_S_ENDOFROWSET &&
  2426. cRowsReturned != 10)
  2427. {
  2428. LogError( "IRowset->GetRowsAt E returned %d of %d rows,"
  2429. " status (%x) != DB_S_ENDOFROWSET\n",
  2430. cRowsReturned, 10,
  2431. sc);
  2432. pCmdTree->Release();
  2433. pRowset->Release();
  2434. #if defined(UNIT_TEST)
  2435. cFailures++;
  2436. return;
  2437. #else
  2438. Fail();
  2439. #endif
  2440. }
  2441. //
  2442. // Expect 1 or 2 hits
  2443. //
  2444. if (sc != DB_S_ENDOFROWSET || cRowsReturned != cExpectedHits)
  2445. {
  2446. LogError( "IRowset->GetRowsAt F returned %d rows (expected %d),"
  2447. " status (%x)\n",
  2448. cRowsReturned, cExpectedHits, sc );
  2449. pCmdTree->Release();
  2450. pRowset->Release();
  2451. #if defined(UNIT_TEST)
  2452. cFailures++;
  2453. return;
  2454. #else
  2455. Fail();
  2456. #endif
  2457. }
  2458. //
  2459. // Patch the column index numbers with true column ids
  2460. //
  2461. DBID aDbCols[cPropTestColsTight];
  2462. aDbCols[0] = psTestProperty1;
  2463. aDbCols[1] = psTestProperty2;
  2464. aDbCols[2] = psAuthor;
  2465. aDbCols[3] = psKeywords;
  2466. aDbCols[4] = psRelevantWords;
  2467. aDbCols[5] = psBlobTest;
  2468. aDbCols[6] = psGuidTest;
  2469. aDbCols[7] = psManyRW;
  2470. aDbCols[8] = psSecurityTest;
  2471. aDbCols[9] = psTestProperty10;
  2472. aDbCols[10] = psTestProperty11;
  2473. aDbCols[11] = psTestProperty12;
  2474. aDbCols[12] = psTestProperty21;
  2475. aDbCols[13] = psTestProperty22;
  2476. aDbCols[14] = psTestProperty2; // repeated
  2477. aDbCols[15] = psManyRW; // repeated
  2478. IUnknown * pAccessor = (IUnknown *) pRowset; // hAccessor must be created on rowset
  2479. // to be used with rowset->GetData below
  2480. HACCESSOR hAccessor = MapColumns( pAccessor, cPropTestColsTight,
  2481. aPropTestColsTight, aDbCols, TRUE);
  2482. //
  2483. // Fetch the data
  2484. //
  2485. for (unsigned row = 0; row < cRowsReturned; row++)
  2486. {
  2487. SPropTestColsTight sRow;
  2488. // Ascending sort, prop1 > prop1Alternate.
  2489. // If one hit, it's not the alternate.
  2490. BOOL fAlternate = (0 == row) && (1 != cRowsReturned);
  2491. sc = pRowset->GetData( pgrhRows[row], hAccessor, & sRow );
  2492. // Either the conversion of varProp8 to array will fail, or the
  2493. // conversion of varProp8A to vector will fail.
  2494. if (DB_S_ERRORSOCCURRED != sc && !fAlternate)
  2495. {
  2496. LogError("IRowset->GetData returned 0x%x (expected 0)\n",sc);
  2497. LogError("IRowset->GetData returned 0x%x (expected 0x40eda)\n",sc);
  2498. if (S_OK != sc &&
  2499. DB_E_ERRORSOCCURRED != sc)
  2500. {
  2501. pCmdTree->Release();
  2502. pRowset->Release();
  2503. Fail();
  2504. }
  2505. }
  2506. if (DB_S_ERRORSOCCURRED != sc && fAlternate)
  2507. {
  2508. // Prop 8 should fail to convert for alternate row.
  2509. LogError("IRowset->GetData returned 0x%x (expected 0x40eda)\n",sc);
  2510. if (S_OK != sc && DB_E_ERRORSOCCURRED != sc)
  2511. {
  2512. pCmdTree->Release();
  2513. pRowset->Release();
  2514. Fail();
  2515. }
  2516. }
  2517. //
  2518. // Verify the data. Put output data into variants for comparison
  2519. //
  2520. PROPVARIANT vTest;
  2521. if ( DBSTATUS_S_OK != sRow.p1_status )
  2522. LogFail( "status of property 1 is bad: %x\n", sRow.p1_status );
  2523. varProp1.lVal = fAlternate ? PROP1_VAL_Alternate : PROP1_VAL;
  2524. vTest.vt = DBTYPE_I4;
  2525. vTest.iVal = (SHORT) sRow.p1_i4;
  2526. CheckPropertyValue( vTest, varProp1 );
  2527. if ( sRow.p1_cb != PROP1_cb )
  2528. LogFail( "cb of property 1 is %ld, should be %ld\n",
  2529. sRow.p1_cb, PROP1_cb );
  2530. if ( DBSTATUS_S_OK != sRow.p2_status )
  2531. LogFail( "status of property 2 is bad: %x\n", sRow.p2_status );
  2532. vTest.vt = VT_LPWSTR;
  2533. vTest.pwszVal = sRow.p2_pwc;
  2534. CheckPropertyValue( vTest, varProp2 );
  2535. if ( sRow.p2_cb != PROP2_cb )
  2536. LogFail( "cb of property 2 is %ld, should be %ld\n",
  2537. sRow.p2_cb, PROP2_cb );
  2538. if ( DBSTATUS_S_OK != sRow.p3_status )
  2539. LogFail( "status of property 3 is bad: %x\n", sRow.p3_status );
  2540. vTest.vt = VT_LPWSTR;
  2541. vTest.pwszVal = sRow.p3_pwc;
  2542. CheckPropertyValue( vTest, varProp3 );
  2543. if ( sRow.p3_cb != PROP3_cb )
  2544. LogFail( "cb of property 3 is %ld, should be %ld\n",
  2545. sRow.p3_cb, PROP3_cb );
  2546. if ( DBSTATUS_S_OK != sRow.p4_status )
  2547. LogFail( "status of property 4 is bad: %x\n", sRow.p4_status );
  2548. vTest.vt = VT_VECTOR | VT_LPWSTR;
  2549. memcpy( & vTest.cal, & sRow.p4_vpwc, sizeof DBVECTOR );
  2550. CheckPropertyValue( vTest, varProp4 );
  2551. if ( sRow.p4_cb != PROP4_cb )
  2552. LogFail( "cb of property 4 is %ld, should be %ld\n",
  2553. sRow.p4_cb, PROP4_cb );
  2554. if ( DBSTATUS_S_OK != sRow.p5_status )
  2555. LogFail( "status of property 5 is bad: %x\n", sRow.p5_status );
  2556. vTest.vt = VT_VECTOR | VT_I4;
  2557. memcpy( & vTest.cal, & sRow.p5_vi, sizeof DBVECTOR );
  2558. CheckPropertyValue( vTest, varProp5 );
  2559. if ( sRow.p5_cb != PROP5_cb )
  2560. LogFail( "cb of property 5 is %ld, should be %ld\n",
  2561. sRow.p5_cb, PROP5_cb );
  2562. if ( DBSTATUS_S_OK != sRow.p6_status )
  2563. LogFail( "status of property 6 is bad: %x\n", sRow.p6_status );
  2564. CheckPropertyValue( *sRow.p6_pvar, varProp6 );
  2565. // is cb of 20 right, or is 0 right? blobs aren't in OLEDB!
  2566. if ( sRow.p6_cb != PROP6_cb )
  2567. LogFail( "cb of property 6 is %ld, should be %ld\n",
  2568. sRow.p6_cb, PROP6_cb );
  2569. if ( DBSTATUS_S_OK != sRow.p7_status )
  2570. LogFail( "status of property 7 is bad: %x\n", sRow.p7_status );
  2571. vTest.vt = VT_CLSID;
  2572. vTest.puuid = sRow.p7_pguid;
  2573. CheckPropertyValue( vTest, varProp7 );
  2574. if ( sRow.p7_cb != PROP7_cb )
  2575. LogFail( "cb of property 7 is %ld, should be %ld\n",
  2576. sRow.p7_cb, PROP7_cb );
  2577. if (! fAlternate)
  2578. {
  2579. if ( DBSTATUS_S_OK != sRow.p8_status )
  2580. LogFail( "status of property 8 is bad: %x\n", sRow.p8_status );
  2581. if ( DBSTATUS_E_CANTCONVERTVALUE != sRow.p8a_status )
  2582. LogFail( "alt. status of property 8 is OK for prim: %x\n", sRow.p8a_status );
  2583. vTest.vt = VT_VECTOR | VT_I4;
  2584. memcpy( & vTest.cal, & sRow.p8_vi, sizeof DBVECTOR );
  2585. CheckPropertyValue( vTest, varProp8 );
  2586. if ( sRow.p8_cb != PROP8_cb )
  2587. LogFail( "cb of property 8 is %ld, should be %ld\n",
  2588. sRow.p8_cb, PROP8_cb );
  2589. }
  2590. else
  2591. {
  2592. if ( DBSTATUS_E_CANTCONVERTVALUE != sRow.p8_status )
  2593. LogFail( "status of property 8 is OK for alt: %x\n", sRow.p8_status );
  2594. if ( DBSTATUS_S_OK != sRow.p8a_status )
  2595. LogFail( "alt status of property 8 is bad: %x\n", sRow.p8a_status );
  2596. vTest.vt = VT_ARRAY | VT_I4;
  2597. memcpy( &vTest.parray, &sRow.p8a_ai, sizeof (SAFEARRAY *) );
  2598. CheckPropertyValue( vTest, varProp8A );
  2599. }
  2600. // can't see prop9 due to its no-read security
  2601. if ( DBSTATUS_S_ISNULL != sRow.p9_status )
  2602. LogFail( "status of property 9 is bad: %x\n", sRow.p9_status );
  2603. if ( 0 != sRow.p9_cb )
  2604. LogFail( "cb of property 9 is bad: %x\n", sRow.p9_cb );
  2605. if ( DBSTATUS_S_OK != sRow.p10_status )
  2606. LogFail( "status of property 10 is bad: %x\n", sRow.p10_status );
  2607. vTest.vt = VT_LPWSTR;
  2608. vTest.pwszVal = sRow.p10_pwc;
  2609. CheckPropertyValue( vTest, varProp10 );
  2610. if ( sRow.p10_cb != PROP10_cb )
  2611. LogFail( "cb of property 10 is %ld, should be %ld\n",
  2612. sRow.p10_cb, PROP10_cb );
  2613. if ( DBSTATUS_S_OK != sRow.p11_status )
  2614. LogFail( "status of property 11 is bad: %x\n", sRow.p11_status );
  2615. vTest.vt = VT_BSTR;
  2616. vTest.pwszVal = sRow.p11_pwc;
  2617. // Note: prop 11 conditional on size...
  2618. if ( SysStringLen(sRow.p11_pwc) > 1000)
  2619. {
  2620. CheckPropertyValue( vTest, varProp11A );
  2621. }
  2622. else
  2623. {
  2624. CheckPropertyValue( vTest, varProp11 );
  2625. }
  2626. // NOTE: the length of a BSTR is sizeof BSTR
  2627. //unsigned PROP11_cb = SysStringLen(varProp11.bstrVal) * sizeof (OLECHAR)
  2628. // + sizeof (DWORD) + sizeof (OLECHAR);
  2629. unsigned PROP11_cb = sizeof BSTR;
  2630. if ( sRow.p11_cb != PROP11_cb )
  2631. LogFail( "cb of property 11 is %ld, should be %ld\n",
  2632. sRow.p11_cb, PROP11_cb );
  2633. if ( DBSTATUS_S_OK != sRow.p12_status )
  2634. LogFail( "status of property 12 is bad: %x\n", sRow.p12_status );
  2635. vTest.vt = VT_VECTOR | VT_BSTR;
  2636. memcpy( & vTest.cal, & sRow.p12_vpwc, sizeof DBVECTOR );
  2637. CheckPropertyValue( vTest, varProp12 );
  2638. if ( sRow.p12_cb != PROP4_cb )
  2639. LogFail( "cb of property 12 is %ld, should be %ld\n",
  2640. sRow.p12_cb, PROP4_cb );
  2641. if ( DBSTATUS_S_OK != sRow.p21_status )
  2642. LogFail( "status of property 21 is bad: %x\n", sRow.p21_status );
  2643. vTest.vt = VT_CF;
  2644. vTest.pclipdata = sRow.p21_pclipdata;
  2645. CheckPropertyValue( vTest, varProp21 );
  2646. if ( sRow.p21_cb != PROP21_cb )
  2647. LogFail( "cb of property 21 is %ld, should be %ld\n",
  2648. sRow.p21_cb, PROP21_cb );
  2649. if ( DBSTATUS_S_OK != sRow.p22_status )
  2650. LogFail( "status of property 22 is bad: %x\n", sRow.p22_status );
  2651. vTest.vt = VT_VECTOR | VT_CF;
  2652. vTest.caclipdata = sRow.p22_caclipdata;
  2653. CheckPropertyValue( vTest, varProp22 );
  2654. if ( sRow.p22_cb != PROP22_cb )
  2655. LogFail( "cb of property 22 is %ld, should be %ld\n",
  2656. sRow.p22_cb, PROP22_cb );
  2657. if ( DBSTATUS_S_OK != sRow.p2a_status )
  2658. LogFail( "status of property 2 as WSTR is bad: %x\n", sRow.p2a_status );
  2659. vTest.vt = VT_LPWSTR;
  2660. vTest.pwszVal = sRow.p2a_pwc;
  2661. CheckPropertyValue( vTest, varProp2 );
  2662. if ( sRow.p2a_cb != PROP2_cb )
  2663. LogFail( "cb of property 2 as WSTR is %ld, should be %ld\n",
  2664. sRow.p2a_cb, PROP2_cb );
  2665. // Don't free anything -- this is byref
  2666. }
  2667. sc = pRowset->ReleaseRows( cRowsReturned, pgrhRows, 0, 0, 0);
  2668. if (S_OK != sc)
  2669. {
  2670. LogError("IRowset->ReleaseRows returned 0x%x (expected 0)\n",sc);
  2671. pRowset->Release();
  2672. Fail();
  2673. }
  2674. CoTaskMemFree(pgrhRows);
  2675. pgrhRows = 0;
  2676. //
  2677. // Clean up.
  2678. //
  2679. ReleaseAccessor( pAccessor, hAccessor);
  2680. pCmdTree->Release();
  2681. pRowset->Release();
  2682. } //RunPropQueryTightBindings
  2683. //+-------------------------------------------------------------------------
  2684. //
  2685. // Function: RunPropQuery, public
  2686. //
  2687. // Synopsis: Execute a retricted query and check results
  2688. //
  2689. // History:
  2690. //
  2691. //--------------------------------------------------------------------------
  2692. static DBBINDING aPropTestCols[] =
  2693. {
  2694. { 0, 0 * cbPV, 0, 0,
  2695. 0, 0, 0,
  2696. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  2697. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  2698. { 1, 1 * cbPV, 0, 0,
  2699. 0, 0, 0,
  2700. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  2701. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  2702. { 2, 2 * cbPV, 0, 0,
  2703. 0, 0, 0,
  2704. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  2705. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  2706. { 3, 3 * cbPV, 0, 0,
  2707. 0, 0, 0,
  2708. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  2709. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  2710. { 4, 4 * cbPV, 0, 0,
  2711. 0, 0, 0,
  2712. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  2713. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  2714. { 5, 5 * cbPV, 0, 0,
  2715. 0, 0, 0,
  2716. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  2717. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  2718. { 6, 6 * cbPV, 0, 0,
  2719. 0, 0, 0,
  2720. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  2721. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  2722. { 7, 7 * cbPV, 0, 0,
  2723. 0, 0, 0,
  2724. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  2725. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  2726. { 8, 8 * cbPV, 0, 0,
  2727. 0, 0, 0,
  2728. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  2729. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  2730. { 9, 9 * cbPV, 0, 0,
  2731. 0, 0, 0,
  2732. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  2733. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  2734. { 10,10* cbPV, 0, 0,
  2735. 0, 0, 0,
  2736. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  2737. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  2738. { 11,11* cbPV, 0, 0,
  2739. 0, 0, 0,
  2740. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  2741. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  2742. { 12,12* cbPV, 0, 0,
  2743. 0, 0, 0,
  2744. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  2745. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  2746. { 13,13* cbPV, 0, 0,
  2747. 0, 0, 0,
  2748. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  2749. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  2750. };
  2751. const ULONG cPropTestCols = sizeof aPropTestCols / sizeof aPropTestCols[0];
  2752. void RunPropQuery(
  2753. ICommand * pQuery,
  2754. CDbRestriction & PropRst,
  2755. unsigned cExpectedHits,
  2756. unsigned numTest )
  2757. {
  2758. RunPropQueryTightBindings( pQuery, PropRst, cExpectedHits, numTest );
  2759. RunPropQueryByRefBindings( pQuery, PropRst, cExpectedHits, numTest );
  2760. //
  2761. // Get twelve properties back
  2762. //
  2763. CDbColumns cols(cPropTestCols);
  2764. cols.Add( psTestProperty1, 0 );
  2765. cols.Add( psTestProperty2, 1 );
  2766. cols.Add( psAuthor, 2 );
  2767. cols.Add( psKeywords, 3 );
  2768. cols.Add( psRelevantWords, 4 );
  2769. cols.Add( psBlobTest, 5 );
  2770. cols.Add( psGuidTest, 6 );
  2771. cols.Add( psManyRW, 7 );
  2772. cols.Add( psSecurityTest, 8 );
  2773. cols.Add( psTestProperty10, 9 );
  2774. cols.Add( psTestProperty11, 10 );
  2775. cols.Add( psTestProperty12, 11 );
  2776. cols.Add( psTestProperty21, 12 );
  2777. cols.Add( psTestProperty22, 13 );
  2778. BOOL fSeq = isEven( numTest );
  2779. CDbSortSet ss(cPropSortColumns);
  2780. for (unsigned i = 0; i < cPropSortColumns; i++)
  2781. ss.Add (aPropSortCols[i], i);
  2782. //
  2783. // Do it!
  2784. //
  2785. CDbCmdTreeNode * pDbCmdTree = FormQueryTree( &PropRst,
  2786. cols,
  2787. fSeq ? 0 : &ss );
  2788. ICommandTree * pCmdTree = 0;
  2789. IRowsetScroll * pRowset = InstantiateRowset(
  2790. pQuery,
  2791. QUERY_SHALLOW, // Depth
  2792. 0,
  2793. pDbCmdTree, // DBCOMMANDTREE
  2794. fSeq ? IID_IRowset : IID_IRowsetScroll, // IID for i/f to return
  2795. 0,
  2796. &pCmdTree );
  2797. //
  2798. // Verify columns
  2799. //
  2800. CheckColumns( pRowset, cols, TRUE );
  2801. if ( !WaitForCompletion( pRowset, TRUE ) )
  2802. {
  2803. pCmdTree->Release();
  2804. pRowset->Release();
  2805. LogFail( "property query unsuccessful.\n" );
  2806. }
  2807. //
  2808. // Get data
  2809. //
  2810. DBCOUNTITEM cRowsReturned = 0;
  2811. HROW* pgrhRows = 0;
  2812. SCODE sc = pRowset->GetNextRows(0, 0, 10, &cRowsReturned, &pgrhRows);
  2813. if ( FAILED( sc ) )
  2814. {
  2815. pCmdTree->Release();
  2816. pRowset->Release();
  2817. LogFail( "IRowset->GetRowsAt G returned 0x%x\n", sc );
  2818. }
  2819. if ( 0 == cExpectedHits )
  2820. {
  2821. pCmdTree->Release();
  2822. pRowset->Release();
  2823. if ( cRowsReturned > 0 )
  2824. LogFail("RunPropQuery, %d returned rows, expected none\n",
  2825. cRowsReturned);
  2826. else
  2827. return;
  2828. }
  2829. if (sc != DB_S_ENDOFROWSET &&
  2830. cRowsReturned != 10)
  2831. {
  2832. LogError( "IRowset->GetRowsAt H returned %d of %d rows,"
  2833. " status (%x) != DB_S_ENDOFROWSET\n",
  2834. cRowsReturned, 10,
  2835. sc);
  2836. pCmdTree->Release();
  2837. pRowset->Release();
  2838. #if defined(UNIT_TEST)
  2839. cFailures++;
  2840. return;
  2841. #else
  2842. Fail();
  2843. #endif
  2844. }
  2845. //
  2846. // Expect 1 or 2 hits
  2847. //
  2848. if (sc != DB_S_ENDOFROWSET || cRowsReturned != cExpectedHits)
  2849. {
  2850. LogError( "IRowset->GetRowsAt I returned %d rows (expected %d),"
  2851. " status (%x)\n",
  2852. cRowsReturned, cExpectedHits, sc );
  2853. pCmdTree->Release();
  2854. pRowset->Release();
  2855. #if defined(UNIT_TEST)
  2856. cFailures++;
  2857. return;
  2858. #else
  2859. Fail();
  2860. #endif
  2861. }
  2862. //
  2863. // Patch the column index numbers with true column ids
  2864. //
  2865. DBID aDbCols[cPropTestCols];
  2866. aDbCols[0] = psTestProperty1;
  2867. aDbCols[1] = psTestProperty2;
  2868. aDbCols[2] = psAuthor;
  2869. aDbCols[3] = psKeywords;
  2870. aDbCols[4] = psRelevantWords;
  2871. aDbCols[5] = psBlobTest;
  2872. aDbCols[6] = psGuidTest;
  2873. aDbCols[7] = psManyRW;
  2874. aDbCols[8] = psSecurityTest;
  2875. aDbCols[9] = psTestProperty10;
  2876. aDbCols[10] = psTestProperty11;
  2877. aDbCols[11] = psTestProperty12;
  2878. aDbCols[12] = psTestProperty21;
  2879. aDbCols[13] = psTestProperty22;
  2880. IUnknown * pAccessor = (IUnknown *) pRowset; // hAccessor must be created on rowset
  2881. // to be used with rowset->GetData below
  2882. HACCESSOR hAccessor = MapColumns(pAccessor, cPropTestCols, aPropTestCols, aDbCols);
  2883. //
  2884. // Fetch the data
  2885. //
  2886. PROPVARIANT aVarnt[cPropTestCols];
  2887. for (unsigned row = 0; row < cRowsReturned; row++)
  2888. {
  2889. sc = pRowset->GetData(pgrhRows[row], hAccessor, aVarnt);
  2890. if (S_OK != sc)
  2891. {
  2892. LogError("IRowset->GetData returned 0x%x (expected 0)\n",sc);
  2893. pCmdTree->Release();
  2894. pRowset->Release();
  2895. Fail();
  2896. }
  2897. //
  2898. // Verify the data.
  2899. //
  2900. // Ascending sort, prop1 > prop1Alternate.
  2901. // If one hit, it's PROP1_VAL, not the alternate.
  2902. // prop1=1234, alternate=123
  2903. BOOL fAlternate = FALSE;
  2904. if ( fSeq )
  2905. {
  2906. if ( 1 == cRowsReturned )
  2907. {
  2908. varProp1.lVal = PROP1_VAL;
  2909. CheckPropertyValue( aVarnt[0], varProp1 );
  2910. }
  2911. else
  2912. {
  2913. // no sort order -- it's either prop1 or alternate
  2914. if ( PROP1_TYPE != aVarnt[0].vt )
  2915. LogFail( "bad datatype for prop1: 0x%x\n", aVarnt[0].vt );
  2916. if ( PROP1_VAL != aVarnt[0].lVal &&
  2917. PROP1_VAL_Alternate != aVarnt[0].lVal )
  2918. LogFail( "bad value for prop1: 0x%x\n", aVarnt[0].lVal );
  2919. fAlternate = aVarnt[0].lVal == PROP1_VAL_Alternate;
  2920. }
  2921. }
  2922. else
  2923. {
  2924. fAlternate = (0 == row) && (1 != cRowsReturned);
  2925. varProp1.lVal = fAlternate ?
  2926. PROP1_VAL_Alternate :
  2927. PROP1_VAL;
  2928. CheckPropertyValue( aVarnt[0], varProp1 );
  2929. }
  2930. CheckPropertyValue( aVarnt[1], varProp2 );
  2931. CheckPropertyValue( aVarnt[2], varProp3 );
  2932. CheckPropertyValue( aVarnt[3], varProp4 );
  2933. CheckPropertyValue( aVarnt[4], varProp5 );
  2934. CheckPropertyValue( aVarnt[5], varProp6 );
  2935. CheckPropertyValue( aVarnt[6], varProp7 );
  2936. CheckPropertyValue( aVarnt[7], fAlternate ? varProp8A : varProp8 );
  2937. CheckPropertyValue( aVarnt[8], varProp9 );
  2938. CheckPropertyValue( aVarnt[9], varProp10 );
  2939. if ( aVarnt[10].vt == VT_BSTR &&
  2940. SysStringLen( aVarnt[10].bstrVal) < 1000 )
  2941. {
  2942. CheckPropertyValue( aVarnt[10], varProp11 );
  2943. }
  2944. else
  2945. {
  2946. CheckPropertyValue( aVarnt[10], varProp11A );
  2947. }
  2948. CheckPropertyValue( aVarnt[11], varProp12 );
  2949. CheckPropertyValue( aVarnt[12], varProp21 );
  2950. CheckPropertyValue( aVarnt[13], varProp22 );
  2951. //
  2952. // Free extra data allocated byref in the variants above
  2953. //
  2954. CoTaskMemFree(aVarnt[1].pwszVal);
  2955. CoTaskMemFree(aVarnt[2].pwszVal);
  2956. for (unsigned x = 0; x < aVarnt[3].calpwstr.cElems; x++ )
  2957. CoTaskMemFree( aVarnt[3].calpwstr.pElems[ x ] );
  2958. CoTaskMemFree(aVarnt[3].calpwstr.pElems);
  2959. CoTaskMemFree(aVarnt[4].cal.pElems);
  2960. CoTaskMemFree(aVarnt[5].blob.pBlobData);
  2961. CoTaskMemFree(aVarnt[6].puuid);
  2962. // sometimes a VT_VECTOR, sometimes a VT_ARRAY
  2963. HRESULT hrPVC = PropVariantClear( &aVarnt[7] );
  2964. if ( S_OK != hrPVC )
  2965. LogError( "bad propvariant clear: %#x\n", hrPVC );
  2966. // nothing to free for [8] -- insufficient security to load value
  2967. CoTaskMemFree(aVarnt[9].pwszVal);
  2968. PropVariantClear(&aVarnt[10]);
  2969. PropVariantClear(&aVarnt[11]);
  2970. PropVariantClear(&aVarnt[12]);
  2971. PropVariantClear(&aVarnt[13]);
  2972. }
  2973. sc = pRowset->ReleaseRows( cRowsReturned, pgrhRows, 0, 0, 0);
  2974. if (S_OK != sc)
  2975. {
  2976. LogError("IRowset->ReleaseRows returned 0x%x (expected 0)\n",sc);
  2977. pCmdTree->Release();
  2978. pRowset->Release();
  2979. Fail();
  2980. }
  2981. CoTaskMemFree(pgrhRows);
  2982. pgrhRows = 0;
  2983. //
  2984. // Clean up.
  2985. //
  2986. ReleaseAccessor( pAccessor, hAccessor);
  2987. pCmdTree->Release();
  2988. pRowset->Release();
  2989. } //RunPropQuery
  2990. const int COERCE_PROP_BUF_SIZE = 129;
  2991. struct CoercePropStruct
  2992. {
  2993. char szProp13[COERCE_PROP_BUF_SIZE];
  2994. char szProp14[COERCE_PROP_BUF_SIZE];
  2995. char szProp15[COERCE_PROP_BUF_SIZE];
  2996. char szProp16[COERCE_PROP_BUF_SIZE];
  2997. char szProp17[COERCE_PROP_BUF_SIZE];
  2998. char szProp18[COERCE_PROP_BUF_SIZE];
  2999. char szProp19[COERCE_PROP_BUF_SIZE];
  3000. char szProp7[COERCE_PROP_BUF_SIZE];
  3001. double szProp20;
  3002. } ;
  3003. static DBBINDING aPropTestCoerceCols[] =
  3004. {
  3005. { 0, COERCE_PROP_BUF_SIZE * 0, 0, 0,
  3006. 0, 0, 0,
  3007. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  3008. COERCE_PROP_BUF_SIZE, 0, DBTYPE_STR, 0, 0}, // prop13
  3009. { 1, COERCE_PROP_BUF_SIZE * 1, 0, 0,
  3010. 0, 0, 0,
  3011. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  3012. COERCE_PROP_BUF_SIZE, 0, DBTYPE_STR, 0, 0}, // prop14
  3013. { 2, COERCE_PROP_BUF_SIZE * 2, 0, 0,
  3014. 0, 0, 0,
  3015. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  3016. COERCE_PROP_BUF_SIZE, 0, DBTYPE_STR, 0, 0}, // prop15
  3017. { 3, COERCE_PROP_BUF_SIZE * 3, 0, 0,
  3018. 0, 0, 0,
  3019. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  3020. COERCE_PROP_BUF_SIZE, 0, DBTYPE_STR, 0, 0}, // prop16
  3021. { 4, COERCE_PROP_BUF_SIZE * 4, 0, 0,
  3022. 0, 0, 0,
  3023. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  3024. 4, 0, DBTYPE_STR, 0, 0}, // prop17 // give smaller size to test if truncation works
  3025. { 5, COERCE_PROP_BUF_SIZE * 5, 0, 0,
  3026. 0, 0, 0,
  3027. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  3028. COERCE_PROP_BUF_SIZE, 0, DBTYPE_STR, 0, 0}, //prop18
  3029. { 6, COERCE_PROP_BUF_SIZE * 6, 0, 0,
  3030. 0, 0, 0,
  3031. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  3032. COERCE_PROP_BUF_SIZE, 0, DBTYPE_STR, 0, 0}, // prop19
  3033. { 7, COERCE_PROP_BUF_SIZE * 7, 0, 0,
  3034. 0, 0, 0,
  3035. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  3036. COERCE_PROP_BUF_SIZE, 0, DBTYPE_STR, 0, 0}, // prop7
  3037. { 8, COERCE_PROP_BUF_SIZE * 8, 0, 0,
  3038. 0, 0, 0,
  3039. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  3040. sizeof( double ), 0, DBTYPE_R8, 0, 0} // prop20
  3041. };
  3042. const ULONG cPropTestCoerceCols = sizeof aPropTestCoerceCols / sizeof aPropTestCoerceCols[0];
  3043. void RunPropQueryAndCoerce(
  3044. ICommand * pQuery,
  3045. CDbRestriction & PropRst,
  3046. unsigned cExpectedHits,
  3047. unsigned numTest )
  3048. {
  3049. CoercePropStruct CoerceResultTestData;
  3050. // set up the expected result data
  3051. memset( &CoerceResultTestData, 0, sizeof CoercePropStruct );
  3052. strcpy( CoerceResultTestData.szProp13, PROP13_STR_VAL );
  3053. strcpy( CoerceResultTestData.szProp14, PROP14_STR_VAL );
  3054. strcpy( CoerceResultTestData.szProp15, PROP15_STR_VAL );
  3055. strcpy( CoerceResultTestData.szProp16, PROP16_STR_VAL );
  3056. strcpy( CoerceResultTestData.szProp17, PROP17_STR_VAL );
  3057. strcpy( CoerceResultTestData.szProp18, PROP18_STR_VAL );
  3058. strcpy( CoerceResultTestData.szProp19, PROP19_STR_VAL );
  3059. strcpy( CoerceResultTestData.szProp7, PROP7_STR_VAL );
  3060. CoerceResultTestData.szProp20 = PROP20_DBL_VAL;
  3061. CDbColumns cols(cPropTestCoerceCols);
  3062. cols.Add( psTestProperty13, 0 );
  3063. cols.Add( psTestProperty14, 1 );
  3064. cols.Add( psTestProperty15, 2 );
  3065. cols.Add( psTestProperty16, 3 );
  3066. cols.Add( psTestProperty17, 4 );
  3067. cols.Add( psTestProperty18, 5 );
  3068. cols.Add( psTestProperty19, 6 );
  3069. cols.Add( psGuidTest, 7 );
  3070. cols.Add( psTestProperty20, 8 );
  3071. //
  3072. // Do it!
  3073. //
  3074. CDbCmdTreeNode * pDbCmdTree = FormQueryTree( &PropRst,
  3075. cols,
  3076. 0);
  3077. ICommandTree * pCmdTree = 0;
  3078. IRowsetScroll * pRowset = InstantiateRowset(
  3079. pQuery,
  3080. QUERY_SHALLOW, // Depth
  3081. 0,
  3082. pDbCmdTree, // DBCOMMANDTREE
  3083. IID_IRowset, // IID for i/f to return
  3084. 0,
  3085. &pCmdTree );
  3086. //
  3087. // Verify columns
  3088. //
  3089. CheckColumns( pRowset, cols, TRUE );
  3090. if ( !WaitForCompletion( pRowset, TRUE ) )
  3091. {
  3092. pCmdTree->Release();
  3093. pRowset->Release();
  3094. LogFail( "property query unsuccessful.\n" );
  3095. }
  3096. //
  3097. // Get data
  3098. //
  3099. DBCOUNTITEM cRowsReturned = 0;
  3100. HROW* pgrhRows = 0;
  3101. SCODE sc = pRowset->GetNextRows(0, 0, 10, &cRowsReturned, &pgrhRows);
  3102. if ( FAILED( sc ) )
  3103. {
  3104. pCmdTree->Release();
  3105. pRowset->Release();
  3106. LogFail( "RunPropQueryAndCoerce IRowset->GetNextRows A returned 0x%x\n", sc );
  3107. }
  3108. if ( 0 == cExpectedHits )
  3109. {
  3110. pCmdTree->Release();
  3111. pRowset->Release();
  3112. if ( cRowsReturned > 0 )
  3113. LogFail("RunPropQueryAndCoerce, %d returned rows, expected none\n",
  3114. cRowsReturned);
  3115. else
  3116. return;
  3117. }
  3118. if (sc != DB_S_ENDOFROWSET &&
  3119. cRowsReturned != 10)
  3120. {
  3121. LogError( "RunPropQueryAndCoerce IRowset->GetNextRows C returned %d of %d rows,"
  3122. " status (%x) != DB_S_ENDOFROWSET\n",
  3123. cRowsReturned, 10,
  3124. sc);
  3125. pCmdTree->Release();
  3126. pRowset->Release();
  3127. #if defined(UNIT_TEST)
  3128. cFailures++;
  3129. return;
  3130. #else
  3131. Fail();
  3132. #endif
  3133. }
  3134. //
  3135. // Expect 1 or 2 hits
  3136. //
  3137. if (sc != DB_S_ENDOFROWSET || cRowsReturned != cExpectedHits)
  3138. {
  3139. LogError( "RunPropQueryAndCoerce IRowset->GetNextRows D returned %d rows (expected %d),"
  3140. " status (%x)\n",
  3141. cRowsReturned, cExpectedHits, sc );
  3142. pCmdTree->Release();
  3143. pRowset->Release();
  3144. #if defined(UNIT_TEST)
  3145. cFailures++;
  3146. return;
  3147. #else
  3148. Fail();
  3149. #endif
  3150. }
  3151. //
  3152. // Patch the column index numbers with true column ids
  3153. //
  3154. DBID aDbCols[cPropTestCoerceCols];
  3155. aDbCols[0] = psTestProperty13;
  3156. aDbCols[1] = psTestProperty14;
  3157. aDbCols[2] = psTestProperty15;
  3158. aDbCols[3] = psTestProperty16;
  3159. aDbCols[4] = psTestProperty17;
  3160. aDbCols[5] = psTestProperty18;
  3161. aDbCols[6] = psTestProperty19;
  3162. aDbCols[7] = psGuidTest;
  3163. aDbCols[8] = psTestProperty20;
  3164. IUnknown * pAccessor = (IUnknown *) pRowset; // hAccessor must be created on rowset
  3165. // to be used with rowset->GetData below
  3166. HACCESSOR hAccessor = MapColumns(pAccessor, cPropTestCoerceCols, aPropTestCoerceCols, aDbCols);
  3167. //
  3168. // Fetch the data
  3169. //
  3170. //PROPVARIANT aVarnt[cPropTestCols];
  3171. CoercePropStruct rowData;
  3172. memset( &rowData, 0, sizeof CoercePropStruct );
  3173. for (unsigned row = 0; row < cRowsReturned; row++)
  3174. {
  3175. sc = pRowset->GetData(pgrhRows[row], hAccessor, &rowData);
  3176. if (S_OK != sc)
  3177. {
  3178. LogError("RunPropQueryAndCoerce IRowset->GetData returned 0x%x (expected 0)\n",sc);
  3179. pCmdTree->Release();
  3180. pRowset->Release();
  3181. Fail();
  3182. }
  3183. // verify
  3184. if ( memcmp( &rowData, &CoerceResultTestData, sizeof CoercePropStruct ) )
  3185. {
  3186. LogFail( "RunPropQueryAndCoerce failed." );
  3187. }
  3188. }
  3189. sc = pRowset->ReleaseRows( cRowsReturned, pgrhRows, 0, 0, 0);
  3190. if (S_OK != sc)
  3191. {
  3192. LogError("IRowset->ReleaseRows returned 0x%x (expected 0)\n",sc);
  3193. pCmdTree->Release();
  3194. pRowset->Release();
  3195. Fail();
  3196. }
  3197. CoTaskMemFree(pgrhRows);
  3198. pgrhRows = 0;
  3199. //
  3200. // Clean up.
  3201. //
  3202. ReleaseAccessor( pAccessor, hAccessor);
  3203. pCmdTree->Release();
  3204. pRowset->Release();
  3205. } //RunPropQueryAndCoerce
  3206. //+-------------------------------------------------------------------------
  3207. //
  3208. // Function: RunDistribQueryTest, public
  3209. //
  3210. // Synopsis: Minimal test for the distributed rowset
  3211. //
  3212. // History: 07 Oct 98 vikasman created
  3213. //
  3214. // Notes: This is a pretty minimal test; should try sorted and
  3215. // scrollable (all combinations), larger result sets
  3216. //
  3217. //--------------------------------------------------------------------------
  3218. void RunDistribQueryTest( BOOL fDoContentTest )
  3219. {
  3220. LogProgress( "Distributed Query Test\n" );
  3221. IUnknown * pIUnknown;
  3222. ICommand * pQuery = 0;
  3223. SCODE scIC = CICreateCommand( &pIUnknown,
  3224. 0,
  3225. IID_IUnknown,
  3226. TEST_CATALOG,
  3227. TEST_MACHINE );
  3228. if ( FAILED( scIC ) )
  3229. LogFail( "RunDistribQueryTest - error 0x%x Unable to create ICommand\n",
  3230. scIC );
  3231. scIC = pIUnknown->QueryInterface(IID_ICommand, (void **) &pQuery );
  3232. pIUnknown->Release();
  3233. if ( FAILED( scIC ) )
  3234. LogFail( "RunDistribQueryTest - error 0x%x Unable to QI ICommand\n",
  3235. scIC );
  3236. if ( 0 == pQuery )
  3237. LogFail( "RunDistribQueryTest - CICreateCommand succeeded, but returned null pQuery\n" );
  3238. WCHAR * awcMachines[2];
  3239. WCHAR * awcCatalogs[2];
  3240. WCHAR * awcScopes[2];
  3241. WCHAR aComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  3242. DWORD aDepths[2];
  3243. ULONG cComputerName = MAX_COMPUTERNAME_LENGTH + 1;
  3244. GetComputerName( aComputerName, &cComputerName );
  3245. awcMachines[0] = TEST_MACHINE;
  3246. awcCatalogs[0] = TEST_CATALOG;
  3247. awcScopes[0] = wcsTestPath;
  3248. aDepths[0] = QUERY_SHALLOW;
  3249. awcMachines[1] = aComputerName;
  3250. awcCatalogs[1] = TEST_CATALOG;
  3251. awcScopes[1] = wcsTestPath;
  3252. aDepths[1] = QUERY_SHALLOW;
  3253. scIC = SetScopeProperties( pQuery,
  3254. 2,
  3255. awcScopes,
  3256. aDepths,
  3257. awcCatalogs,
  3258. awcMachines );
  3259. if ( FAILED( scIC ) )
  3260. LogFail( "RunDistribQueryTest - error 0x%x Unable to set scope '%ws'\n",
  3261. scIC, wcsTestPath );
  3262. CheckPropertiesOnCommand( pQuery );
  3263. unsigned numTest = 1;
  3264. // singleton DBOP_equal singleton - Coersion test
  3265. {
  3266. LogProgress( " DistributedRowset - Property coercion to String test\n" );
  3267. CDbPropertyRestriction PropRst;
  3268. PropRst.SetProperty( psTestProperty1 );
  3269. PropRst.SetRelation( DBOP_equal );
  3270. PropRst.SetValue( PROP1_VAL );
  3271. RunPropQueryAndCoerce( pQuery, PropRst, 2, numTest++ );
  3272. }
  3273. pQuery->Release();
  3274. }
  3275. //+-------------------------------------------------------------------------
  3276. //
  3277. // Function: RunPropTest, public
  3278. //
  3279. // Synopsis: Very minimal test of property query
  3280. //
  3281. // History: 13-May-93 KyleP Created
  3282. // 15 Oct 94 Alanw Converted to OLE-DB query
  3283. //
  3284. //--------------------------------------------------------------------------
  3285. void RunPropTest( void )
  3286. {
  3287. LogProgress( "Property Retrieval Test\n" );
  3288. PROPVARIANT pvProp5;
  3289. pvProp5.vt = VT_I4|VT_VECTOR;
  3290. pvProp5.cal.cElems = clProp5;
  3291. pvProp5.cal.pElems = (LONG *) alProp5;
  3292. PROPVARIANT pvProp5Jumble;
  3293. pvProp5Jumble.vt = VT_I4|VT_VECTOR;
  3294. pvProp5Jumble.cal.cElems = clProp5Jumble;
  3295. pvProp5Jumble.cal.pElems = (LONG *) alProp5Jumble;
  3296. PROPVARIANT pvProp5Like;
  3297. pvProp5Like.vt = VT_I4|VT_VECTOR;
  3298. pvProp5Like.cal.cElems = clProp5Like;
  3299. pvProp5Like.cal.pElems = (LONG *) alProp5Like;
  3300. PROPVARIANT pvProp5None;
  3301. pvProp5None.vt = VT_I4|VT_VECTOR;
  3302. pvProp5None.cal.cElems = clProp5None;
  3303. pvProp5None.cal.pElems = (LONG *) alProp5None;
  3304. PROPVARIANT pvProp5Less;
  3305. pvProp5Less.vt = VT_I4|VT_VECTOR;
  3306. pvProp5Less.cal.cElems = clProp5Less;
  3307. pvProp5Less.cal.pElems = (LONG *) alProp5Less;
  3308. PROPVARIANT pvProp5AllLess;
  3309. pvProp5AllLess.vt = VT_I4|VT_VECTOR;
  3310. pvProp5AllLess.cal.cElems = clProp5AllLess;
  3311. pvProp5AllLess.cal.pElems = (LONG *) alProp5AllLess;
  3312. PROPVARIANT pvProp5More;
  3313. pvProp5More.vt = VT_I4|VT_VECTOR;
  3314. pvProp5More.cal.cElems = clProp5More;
  3315. pvProp5More.cal.pElems = (LONG *) alProp5More;
  3316. PROPVARIANT pvProp5AllMore;
  3317. SAFEARRAY saProp5AllMore = { 1, // Dimension
  3318. FADF_AUTO, // Flags: on stack
  3319. sizeof(LONG), // Size of an element
  3320. 1, // Lock count. 1 for safety.
  3321. (void *)alProp5AllMore, // The data
  3322. { clProp5AllMore, 0 } };// Bounds (element count, low bound)
  3323. pvProp5AllMore.vt = VT_I4|VT_ARRAY;
  3324. pvProp5AllMore.parray = &saProp5AllMore;
  3325. WCHAR *pwszScope = wcsTestPath;
  3326. DWORD dwDepth = QUERY_SHALLOW;
  3327. IUnknown * pIUnknown;
  3328. ICommand * pQuery = 0;
  3329. SCODE scIC = CICreateCommand( &pIUnknown,
  3330. 0,
  3331. IID_IUnknown,
  3332. TEST_CATALOG,
  3333. TEST_MACHINE );
  3334. if ( FAILED( scIC ) )
  3335. LogFail( "RunPropTest - error 0x%x Unable to create ICommand\n",
  3336. scIC );
  3337. scIC = pIUnknown->QueryInterface(IID_ICommand, (void **) &pQuery );
  3338. pIUnknown->Release();
  3339. if ( FAILED( scIC ) )
  3340. LogFail( "RunPropTest - error 0x%x Unable to QI ICommand\n",
  3341. scIC );
  3342. if ( 0 == pQuery )
  3343. LogFail( "RunPropTest - CICreateCommand succeeded, but returned null pQuery\n" );
  3344. scIC = SetScopeProperties( pQuery,
  3345. 1,
  3346. &pwszScope,
  3347. &dwDepth );
  3348. if ( FAILED( scIC ) )
  3349. LogFail( "RunPropTest - error 0x%x Unable to set scope '%ws'\n",
  3350. scIC, pwszScope );
  3351. CheckPropertiesOnCommand( pQuery );
  3352. unsigned numTest = 1;
  3353. // singleton DBOP_equal singleton - Coersion test
  3354. {
  3355. LogProgress( " Property coercion to String test 0\n" );
  3356. CDbPropertyRestriction PropRst;
  3357. PropRst.SetProperty( psTestProperty1 );
  3358. PropRst.SetRelation( DBOP_equal );
  3359. PropRst.SetValue( PROP1_VAL );
  3360. RunPropQueryAndCoerce( pQuery, PropRst, 1, numTest++ );
  3361. }
  3362. // singleton DBOP_equal singleton
  3363. {
  3364. LogProgress( " Property Retrieval test 0\n" );
  3365. CDbPropertyRestriction PropRst;
  3366. PropRst.SetProperty( psTestProperty1 );
  3367. PropRst.SetRelation( DBOP_equal );
  3368. PropRst.SetValue( PROP1_VAL );
  3369. RunPropQuery( pQuery, PropRst, 1, numTest++ );
  3370. }
  3371. // vector DBOP_equal vector
  3372. {
  3373. LogProgress( " Property Retrieval test 1\n" );
  3374. CDbPropertyRestriction PropRst;
  3375. PropRst.SetProperty( psRelevantWords );
  3376. PropRst.SetRelation( DBOP_equal );
  3377. PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5)) );
  3378. RunPropQueryAndCoerce( pQuery, PropRst, 2, numTest );
  3379. RunPropQuery( pQuery, PropRst, 2, numTest++ );
  3380. }
  3381. // vector DBOP_equal_all vector (FAIL getting any hits back)
  3382. {
  3383. LogProgress( " Property Retrieval test 2\n" );
  3384. CDbPropertyRestriction PropRst;
  3385. PropRst.SetProperty( psRelevantWords );
  3386. PropRst.SetRelation( DBOP_equal_all );
  3387. PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5)) );
  3388. RunPropQuery( pQuery, PropRst, 0, numTest++ );
  3389. }
  3390. // singleton DBOP_equal_any singleton
  3391. {
  3392. LogProgress( " Property Retrieval test 3\n" );
  3393. CDbPropertyRestriction PropRst;
  3394. PropRst.SetProperty( psTestProperty1 );
  3395. PropRst.SetRelation( DBOP_equal_any );
  3396. PropRst.SetValue( PROP1_VAL );
  3397. RunPropQuery( pQuery, PropRst, 1, numTest++ );
  3398. }
  3399. // singleton DBOP_equal vector (FAIL getting any hits back)
  3400. {
  3401. LogProgress( " Property Retrieval test 4\n" );
  3402. CDbPropertyRestriction PropRst;
  3403. PropRst.SetProperty( psRelevantWords );
  3404. PropRst.SetRelation( DBOP_equal );
  3405. PropRst.SetValue( SecondRelevantWord );
  3406. RunPropQuery( pQuery, PropRst, 0, numTest++ );
  3407. }
  3408. // singleton DBOP_equal_any vector (FAIL -- singleton not in vector)
  3409. {
  3410. LogProgress( " Property Retrieval test 5\n" );
  3411. CDbPropertyRestriction PropRst;
  3412. PropRst.SetProperty( psRelevantWords );
  3413. PropRst.SetRelation( DBOP_equal_any );
  3414. PropRst.SetValue( (LONG) 666 );
  3415. RunPropQuery( pQuery, PropRst, 0, numTest++ );
  3416. }
  3417. // singleton DBOP_equal_any vector
  3418. {
  3419. LogProgress( " Property Retrieval test 6\n" );
  3420. CDbPropertyRestriction PropRst;
  3421. PropRst.SetProperty( psRelevantWords );
  3422. PropRst.SetRelation( DBOP_equal_any );
  3423. PropRst.SetValue( SecondRelevantWord );
  3424. RunPropQuery( pQuery, PropRst, 2, numTest++ );
  3425. }
  3426. // reordered vector DBOP_equal_any vector
  3427. {
  3428. LogProgress( " Property Retrieval test 7\n" );
  3429. CDbPropertyRestriction PropRst;
  3430. PropRst.SetProperty( psRelevantWords );
  3431. PropRst.SetRelation( DBOP_equal_any );
  3432. PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5Jumble)) );
  3433. RunPropQuery( pQuery, PropRst, 2 , numTest++ );
  3434. }
  3435. // vector with one element match DBOP_equal_any vector
  3436. {
  3437. LogProgress( " Property Retrieval test 8\n" );
  3438. CDbPropertyRestriction PropRst;
  3439. PropRst.SetProperty( psRelevantWords );
  3440. PropRst.SetRelation( DBOP_equal_any );
  3441. PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5Like)) );
  3442. RunPropQuery( pQuery, PropRst, 2, numTest++ );
  3443. }
  3444. // vector with 0 element overlap DBOP_equal_any vector (FAIL getting any hits back)
  3445. {
  3446. LogProgress( " Property Retrieval test 9\n" );
  3447. CDbPropertyRestriction PropRst;
  3448. PropRst.SetProperty( psRelevantWords );
  3449. PropRst.SetRelation( DBOP_equal_any );
  3450. PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5None)) );
  3451. RunPropQuery( pQuery, PropRst, 0, numTest++ );
  3452. }
  3453. // reordered vector DBOP_equal_any vector
  3454. {
  3455. LogProgress( " Property Retrieval test 10\n" );
  3456. CDbPropertyRestriction PropRst;
  3457. PropRst.SetProperty( psRelevantWords );
  3458. PropRst.SetRelation( DBOP_equal_any );
  3459. PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5Jumble)) );
  3460. RunPropQuery( pQuery, PropRst, 2, numTest++ );
  3461. }
  3462. // vector with one element match DBOP_equal_all vector (FAIL getting hits back)
  3463. {
  3464. LogProgress( " Property Retrieval test 11\n" );
  3465. CDbPropertyRestriction PropRst;
  3466. PropRst.SetProperty( psRelevantWords );
  3467. PropRst.SetRelation( DBOP_equal_all );
  3468. PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5Like)) );
  3469. RunPropQuery( pQuery, PropRst, 0, numTest++ );
  3470. }
  3471. // less vector DBOP_less vector (FAIL getting hits back)
  3472. {
  3473. LogProgress( " Property Retrieval test 12\n" );
  3474. CDbPropertyRestriction PropRst;
  3475. PropRst.SetProperty( psRelevantWords );
  3476. PropRst.SetRelation( DBOP_less );
  3477. PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5Less)) );
  3478. RunPropQuery( pQuery, PropRst, 0, numTest++ );
  3479. }
  3480. // less vector DBOP_greater vector
  3481. {
  3482. LogProgress( " Property Retrieval test 13\n" );
  3483. CDbPropertyRestriction PropRst;
  3484. PropRst.SetProperty( psRelevantWords );
  3485. PropRst.SetRelation( DBOP_greater );
  3486. PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5Less)) );
  3487. RunPropQuery( pQuery, PropRst, 2, numTest++ );
  3488. }
  3489. // more vector DBOP_greater_equal vector (FAIL getting hits back)
  3490. {
  3491. LogProgress( " Property Retrieval test 14\n" );
  3492. CDbPropertyRestriction PropRst;
  3493. PropRst.SetProperty( psRelevantWords );
  3494. PropRst.SetRelation( DBOP_greater_equal );
  3495. PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5More)) );
  3496. RunPropQuery( pQuery, PropRst, 0, numTest++ );
  3497. }
  3498. // more vector DBOP_less_equal vector
  3499. {
  3500. LogProgress( " Property Retrieval test 15\n" );
  3501. CDbPropertyRestriction PropRst;
  3502. PropRst.SetProperty( psRelevantWords );
  3503. PropRst.SetRelation( DBOP_less_equal );
  3504. PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5More)) );
  3505. RunPropQuery( pQuery, PropRst, 2, numTest++ );
  3506. }
  3507. // less vector DBOP_less_all vector (FAIL getting hits back)
  3508. {
  3509. LogProgress( " Property Retrieval test 16\n" );
  3510. CDbPropertyRestriction PropRst;
  3511. PropRst.SetProperty( psRelevantWords );
  3512. PropRst.SetRelation( DBOP_less_all );
  3513. PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5AllLess)) );
  3514. RunPropQuery( pQuery, PropRst, 0, numTest++ );
  3515. }
  3516. // less vector DBOP_greater_all vector
  3517. {
  3518. LogProgress( " Property Retrieval test 17\n" );
  3519. CDbPropertyRestriction PropRst;
  3520. PropRst.SetProperty( psRelevantWords );
  3521. PropRst.SetRelation( DBOP_greater_all );
  3522. PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5AllLess)) );
  3523. RunPropQuery( pQuery, PropRst, 2, numTest++ );
  3524. }
  3525. // more vector DBOP_greater_equal_all vector (FAIL getting hits back)
  3526. {
  3527. LogProgress( " Property Retrieval test 18\n" );
  3528. CDbPropertyRestriction PropRst;
  3529. PropRst.SetProperty( psRelevantWords );
  3530. PropRst.SetRelation( DBOP_greater_equal_all );
  3531. PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5AllMore)) );
  3532. RunPropQuery( pQuery, PropRst, 0, numTest++ );
  3533. }
  3534. // more vector DBOP_less_equal_all vector
  3535. {
  3536. LogProgress( " Property Retrieval test 19\n" );
  3537. CDbPropertyRestriction PropRst;
  3538. PropRst.SetProperty( psRelevantWords );
  3539. PropRst.SetRelation( DBOP_less_equal_all );
  3540. PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5AllMore)) );
  3541. RunPropQuery( pQuery, PropRst, 2, numTest++ );
  3542. }
  3543. // less vector DBOP_less_any vector (FAIL getting hits back)
  3544. {
  3545. LogProgress( " Property Retrieval test 20\n" );
  3546. CDbPropertyRestriction PropRst;
  3547. PropRst.SetProperty( psRelevantWords );
  3548. PropRst.SetRelation( DBOP_less_any );
  3549. PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5AllLess)) );
  3550. RunPropQuery( pQuery, PropRst, 0, numTest++ );
  3551. }
  3552. // less vector DBOP_greater_any vector
  3553. {
  3554. LogProgress( " Property Retrieval test 21\n" );
  3555. CDbPropertyRestriction PropRst;
  3556. PropRst.SetProperty( psRelevantWords );
  3557. PropRst.SetRelation( DBOP_greater_any );
  3558. PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5AllLess)) );
  3559. RunPropQuery( pQuery, PropRst, 2, numTest++ );
  3560. }
  3561. // more vector DBOP_greater_equal_any vector (FAIL getting hits back)
  3562. {
  3563. LogProgress( " Property Retrieval test 22\n" );
  3564. CDbPropertyRestriction PropRst;
  3565. PropRst.SetProperty( psRelevantWords );
  3566. PropRst.SetRelation( DBOP_greater_equal_any );
  3567. PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5AllMore)) );
  3568. RunPropQuery( pQuery, PropRst, 0, numTest++ );
  3569. }
  3570. // more vector DBOP_less_equal_any vector
  3571. {
  3572. LogProgress( " Property Retrieval test 23\n" );
  3573. CDbPropertyRestriction PropRst;
  3574. PropRst.SetProperty( psRelevantWords );
  3575. PropRst.SetRelation( DBOP_less_equal_any );
  3576. PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5AllMore)) );
  3577. RunPropQuery( pQuery, PropRst, 2, numTest++ );
  3578. }
  3579. // singleton wstr DBOP_equal_any string vector
  3580. {
  3581. LogProgress( " Property Retrieval test 24\n" );
  3582. CDbPropertyRestriction PropRst;
  3583. PropRst.SetProperty( psKeywords );
  3584. PropRst.SetRelation( DBOP_equal_any );
  3585. PropRst.SetValue( L"is" );
  3586. RunPropQuery( pQuery, PropRst, 2, numTest++ );
  3587. }
  3588. // bogus singleton wstr DBOP_equal_any string vector (FAIL getting hits back)
  3589. {
  3590. LogProgress( " Property Retrieval test 25\n" );
  3591. CDbPropertyRestriction PropRst;
  3592. PropRst.SetProperty( psKeywords );
  3593. PropRst.SetRelation( DBOP_equal_any );
  3594. PropRst.SetValue( L"666" );
  3595. RunPropQuery( pQuery, PropRst, 0, numTest++ );
  3596. }
  3597. // bogus singleton DBOP_equal_any singleton
  3598. {
  3599. LogProgress( " Property Retrieval test 26\n" );
  3600. CDbPropertyRestriction PropRst;
  3601. PropRst.SetProperty( psTestProperty1 );
  3602. PropRst.SetRelation( DBOP_equal_any );
  3603. PropRst.SetValue( PROP1_VAL + 100 );
  3604. RunPropQuery( pQuery, PropRst, 0, numTest++ );
  3605. }
  3606. // singleton DBOP_equal singleton (empty string)
  3607. {
  3608. LogProgress( " Property Retrieval test 27\n" );
  3609. CDbPropertyRestriction PropRst;
  3610. PropRst.SetProperty( psTestProperty10 );
  3611. PropRst.SetRelation( DBOP_equal );
  3612. PropRst.SetValue( PROP10_VAL );
  3613. RunPropQuery( pQuery, PropRst, 2, numTest++ );
  3614. }
  3615. // singleton DBOP_equal singleton (BSTR string)
  3616. {
  3617. LogProgress( " Property Retrieval test 28\n" );
  3618. CDbPropertyRestriction PropRst;
  3619. PropRst.SetProperty( psTestProperty11 );
  3620. PropRst.SetRelation( DBOP_equal );
  3621. PropRst.SetValue( varProp11 );
  3622. RunPropQuery( pQuery, PropRst, 1, numTest++ );
  3623. }
  3624. // less vector DBOP_less_all large vector (FAIL getting hits back)
  3625. {
  3626. LogProgress( " Property Retrieval test 29\n" );
  3627. CDbPropertyRestriction PropRst;
  3628. PropRst.SetProperty( psManyRW );
  3629. PropRst.SetRelation( DBOP_less_all );
  3630. PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5AllLess)) );
  3631. RunPropQuery( pQuery, PropRst, 0, numTest++ );
  3632. }
  3633. // less vector DBOP_greater_all large vector (FAIL getting hits back)
  3634. {
  3635. LogProgress( " Property Retrieval test 30\n" );
  3636. CDbPropertyRestriction PropRst;
  3637. PropRst.SetProperty( psManyRW );
  3638. PropRst.SetRelation( DBOP_greater_all );
  3639. PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5AllLess)) );
  3640. RunPropQuery( pQuery, PropRst, 0, numTest++ );
  3641. }
  3642. // more vector DBOP_less_all large vector
  3643. {
  3644. LogProgress( " Property Retrieval test 31\n" );
  3645. CDbPropertyRestriction PropRst;
  3646. PropRst.SetProperty( psManyRW );
  3647. PropRst.SetRelation( DBOP_less_all );
  3648. PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5AllMore)) );
  3649. RunPropQuery( pQuery, PropRst, 2, numTest++ );
  3650. }
  3651. // singleton DBOP_less_equal_all large vector
  3652. {
  3653. LogProgress( " Property Retrieval test 32\n" );
  3654. CDbPropertyRestriction PropRst;
  3655. PropRst.SetProperty( psManyRW );
  3656. PropRst.SetRelation( DBOP_less_equal_all );
  3657. PropRst.SetValue( (LONG) (clProp8-1) );
  3658. RunPropQuery( pQuery, PropRst, 2, numTest++ );
  3659. }
  3660. pQuery->Release();
  3661. } //RunPropTest
  3662. struct SSafeArrayTestColsTight
  3663. {
  3664. SAFEARRAY * a_I4;
  3665. SAFEARRAY * a_BSTR;
  3666. SAFEARRAY * a_VARIANT;
  3667. SAFEARRAY * a_R8;
  3668. SAFEARRAY * a_DATE;
  3669. SAFEARRAY * a_BOOL;
  3670. SAFEARRAY * a_DECIMAL;
  3671. SAFEARRAY * a_I1;
  3672. SAFEARRAY * a_R4;
  3673. SAFEARRAY * a_CY;
  3674. SAFEARRAY * a_UINT;
  3675. SAFEARRAY * a_INT;
  3676. SAFEARRAY * a_ERROR;
  3677. DBLENGTH I4_cb;
  3678. DBLENGTH BSTR_cb;
  3679. DBLENGTH VARIANT_cb;
  3680. DBLENGTH R8_cb;
  3681. DBLENGTH DATE_cb;
  3682. DBLENGTH BOOL_cb;
  3683. DBLENGTH DECIMAL_cb;
  3684. DBLENGTH I1_cb;
  3685. DBLENGTH R4_cb;
  3686. DBLENGTH CY_cb;
  3687. DBLENGTH UINT_cb;
  3688. DBLENGTH INT_cb;
  3689. DBLENGTH ERROR_cb;
  3690. ULONG I4_status;
  3691. ULONG BSTR_status;
  3692. ULONG VARIANT_status;
  3693. ULONG R8_status;
  3694. ULONG DATE_status;
  3695. ULONG BOOL_status;
  3696. ULONG DECIMAL_status;
  3697. ULONG I1_status;
  3698. ULONG R4_status;
  3699. ULONG CY_status;
  3700. ULONG UINT_status;
  3701. ULONG INT_status;
  3702. ULONG ERROR_status;
  3703. };
  3704. static DBBINDING aSafeArrayTestColsTight[] =
  3705. {
  3706. { 0,
  3707. offsetof(SSafeArrayTestColsTight,a_I4),
  3708. offsetof(SSafeArrayTestColsTight,I4_cb),
  3709. offsetof(SSafeArrayTestColsTight,I4_status),
  3710. 0,0,0,
  3711. ALLPARTS,
  3712. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  3713. sizeof (SAFEARRAY *), 0,
  3714. DBTYPE_ARRAY|DBTYPE_I4,
  3715. 0, 0 },
  3716. { 1,
  3717. offsetof(SSafeArrayTestColsTight,a_BSTR),
  3718. offsetof(SSafeArrayTestColsTight,BSTR_cb),
  3719. offsetof(SSafeArrayTestColsTight,BSTR_status),
  3720. 0,0,0,
  3721. ALLPARTS,
  3722. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  3723. sizeof (SAFEARRAY *), 0,
  3724. DBTYPE_ARRAY|DBTYPE_BSTR,
  3725. 0, 0 },
  3726. { 2,
  3727. offsetof(SSafeArrayTestColsTight,a_VARIANT),
  3728. offsetof(SSafeArrayTestColsTight,VARIANT_cb),
  3729. offsetof(SSafeArrayTestColsTight,VARIANT_status),
  3730. 0,0,0,
  3731. ALLPARTS,
  3732. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  3733. sizeof (SAFEARRAY *), 0,
  3734. DBTYPE_ARRAY|DBTYPE_VARIANT,
  3735. 0, 0 },
  3736. { 3,
  3737. offsetof(SSafeArrayTestColsTight,a_R8),
  3738. offsetof(SSafeArrayTestColsTight,R8_cb),
  3739. offsetof(SSafeArrayTestColsTight,R8_status),
  3740. 0,0,0,
  3741. ALLPARTS,
  3742. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  3743. sizeof (SAFEARRAY *), 0,
  3744. DBTYPE_ARRAY|DBTYPE_R8,
  3745. 0, 0 },
  3746. { 4,
  3747. offsetof(SSafeArrayTestColsTight,a_DATE),
  3748. offsetof(SSafeArrayTestColsTight,DATE_cb),
  3749. offsetof(SSafeArrayTestColsTight,DATE_status),
  3750. 0,0,0,
  3751. ALLPARTS,
  3752. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  3753. sizeof (SAFEARRAY *), 0,
  3754. DBTYPE_ARRAY|DBTYPE_DATE,
  3755. 0, 0 },
  3756. { 5,
  3757. offsetof(SSafeArrayTestColsTight,a_BOOL),
  3758. offsetof(SSafeArrayTestColsTight,BOOL_cb),
  3759. offsetof(SSafeArrayTestColsTight,BOOL_status),
  3760. 0,0,0,
  3761. ALLPARTS,
  3762. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  3763. sizeof (SAFEARRAY *), 0,
  3764. DBTYPE_ARRAY|DBTYPE_BOOL,
  3765. 0, 0 },
  3766. { 6,
  3767. offsetof(SSafeArrayTestColsTight,a_DECIMAL),
  3768. offsetof(SSafeArrayTestColsTight,DECIMAL_cb),
  3769. offsetof(SSafeArrayTestColsTight,DECIMAL_status),
  3770. 0,0,0,
  3771. ALLPARTS,
  3772. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  3773. sizeof (SAFEARRAY *), 0,
  3774. DBTYPE_ARRAY|DBTYPE_DECIMAL,
  3775. 0, 0 },
  3776. { 7,
  3777. offsetof(SSafeArrayTestColsTight,a_I1),
  3778. offsetof(SSafeArrayTestColsTight,I1_cb),
  3779. offsetof(SSafeArrayTestColsTight,I1_status),
  3780. 0,0,0,
  3781. ALLPARTS,
  3782. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  3783. sizeof (SAFEARRAY *), 0,
  3784. DBTYPE_ARRAY|DBTYPE_I1,
  3785. 0, 0 },
  3786. { 8,
  3787. offsetof(SSafeArrayTestColsTight,a_R4),
  3788. offsetof(SSafeArrayTestColsTight,R4_cb),
  3789. offsetof(SSafeArrayTestColsTight,R4_status),
  3790. 0,0,0,
  3791. ALLPARTS,
  3792. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  3793. sizeof (SAFEARRAY *), 0,
  3794. DBTYPE_ARRAY|DBTYPE_R4,
  3795. 0, 0 },
  3796. { 9,
  3797. offsetof(SSafeArrayTestColsTight,a_CY),
  3798. offsetof(SSafeArrayTestColsTight,CY_cb),
  3799. offsetof(SSafeArrayTestColsTight,CY_status),
  3800. 0,0,0,
  3801. ALLPARTS,
  3802. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  3803. sizeof (SAFEARRAY *), 0,
  3804. DBTYPE_ARRAY|DBTYPE_CY,
  3805. 0, 0 },
  3806. { 10,
  3807. offsetof(SSafeArrayTestColsTight,a_UINT),
  3808. offsetof(SSafeArrayTestColsTight,UINT_cb),
  3809. offsetof(SSafeArrayTestColsTight,UINT_status),
  3810. 0,0,0,
  3811. ALLPARTS,
  3812. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  3813. sizeof (SAFEARRAY *), 0,
  3814. DBTYPE_ARRAY|VT_UINT,
  3815. 0, 0 },
  3816. { 11,
  3817. offsetof(SSafeArrayTestColsTight,a_INT),
  3818. offsetof(SSafeArrayTestColsTight,INT_cb),
  3819. offsetof(SSafeArrayTestColsTight,INT_status),
  3820. 0,0,0,
  3821. ALLPARTS,
  3822. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  3823. sizeof (SAFEARRAY *), 0,
  3824. DBTYPE_ARRAY|VT_INT,
  3825. 0, 0 },
  3826. { 12,
  3827. offsetof(SSafeArrayTestColsTight,a_ERROR),
  3828. offsetof(SSafeArrayTestColsTight,ERROR_cb),
  3829. offsetof(SSafeArrayTestColsTight,ERROR_status),
  3830. 0,0,0,
  3831. ALLPARTS,
  3832. DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  3833. sizeof (SAFEARRAY *), 0,
  3834. DBTYPE_ARRAY|DBTYPE_ERROR,
  3835. 0, 0 },
  3836. };
  3837. const ULONG cSafeArrayTestColsTight = sizeof aSafeArrayTestColsTight /
  3838. sizeof aSafeArrayTestColsTight[0];
  3839. void RunSafeArrayTightBindings(
  3840. ICommand * pQuery,
  3841. CDbRestriction & PropRst,
  3842. unsigned cExpectedHits,
  3843. unsigned numTest )
  3844. {
  3845. //
  3846. // Get 13 properties back
  3847. //
  3848. CDbColumns cols(cSafeArrayTestColsTight);
  3849. cols.Add( colSA_I4, 0 );
  3850. cols.Add( colSA_BSTR, 1 );
  3851. cols.Add( colSA_VARIANT, 2 );
  3852. cols.Add( colSA_R8, 3 );
  3853. cols.Add( colSA_DATE, 4 );
  3854. cols.Add( colSA_BOOL, 5 );
  3855. cols.Add( colSA_DECIMAL, 6 );
  3856. cols.Add( colSA_I1, 7 );
  3857. cols.Add( colSA_R4, 8 );
  3858. cols.Add( colSA_CY, 9 );
  3859. cols.Add( colSA_UINT, 10 );
  3860. cols.Add( colSA_INT, 11 );
  3861. cols.Add( colSA_ERROR, 12 );
  3862. BOOL fSeq = isEven( numTest );
  3863. CDbSortSet ss( 1 );
  3864. ss.Add( colSA_VARIANT, 0 );
  3865. //
  3866. // Do it!
  3867. //
  3868. CDbCmdTreeNode * pDbCmdTree = FormQueryTree( &PropRst,
  3869. cols,
  3870. fSeq ? 0 : &ss );
  3871. ICommandTree * pCmdTree = 0;
  3872. IRowsetScroll * pRowset = InstantiateRowset(
  3873. pQuery,
  3874. QUERY_SHALLOW, // Depth
  3875. 0,
  3876. pDbCmdTree, // DBCOMMANDTREE
  3877. fSeq ? IID_IRowset : IID_IRowsetScroll, // IID for i/f to return
  3878. 0,
  3879. &pCmdTree );
  3880. //
  3881. // Verify columns
  3882. //
  3883. CheckColumns( pRowset, cols, TRUE );
  3884. if ( !WaitForCompletion( pRowset, TRUE ) )
  3885. {
  3886. pCmdTree->Release();
  3887. pRowset->Release();
  3888. LogFail( "property query unsuccessful.\n" );
  3889. }
  3890. //
  3891. // Get data
  3892. //
  3893. DBCOUNTITEM cRowsReturned = 0;
  3894. HROW* pgrhRows = 0;
  3895. SCODE sc = pRowset->GetNextRows(0, 0, 10, &cRowsReturned, &pgrhRows);
  3896. if ( FAILED( sc ) )
  3897. {
  3898. pCmdTree->Release();
  3899. pRowset->Release();
  3900. LogFail( "IRowset->GetRowsAt G returned 0x%x\n", sc );
  3901. }
  3902. if ( 0 == cExpectedHits )
  3903. {
  3904. pCmdTree->Release();
  3905. pRowset->Release();
  3906. if ( cRowsReturned > 0 )
  3907. LogFail("RunPropQuery, %d returned rows, expected none\n",
  3908. cRowsReturned);
  3909. else
  3910. return;
  3911. }
  3912. if (sc != DB_S_ENDOFROWSET &&
  3913. cRowsReturned != 10)
  3914. {
  3915. LogError( "IRowset->GetRowsAt H returned %d of %d rows,"
  3916. " status (%x) != DB_S_ENDOFROWSET\n",
  3917. cRowsReturned, 10,
  3918. sc);
  3919. pCmdTree->Release();
  3920. pRowset->Release();
  3921. #if defined(UNIT_TEST)
  3922. cFailures++;
  3923. return;
  3924. #else
  3925. Fail();
  3926. #endif
  3927. }
  3928. //
  3929. // Expect 1 or 2 hits
  3930. //
  3931. if (sc != DB_S_ENDOFROWSET || cRowsReturned != cExpectedHits)
  3932. {
  3933. LogError( "IRowset->GetRowsAt I returned %d rows (expected %d),"
  3934. " status (%x)\n",
  3935. cRowsReturned, cExpectedHits, sc );
  3936. pCmdTree->Release();
  3937. pRowset->Release();
  3938. #if defined(UNIT_TEST)
  3939. cFailures++;
  3940. return;
  3941. #else
  3942. Fail();
  3943. #endif
  3944. }
  3945. //
  3946. // Patch the column index numbers with true column ids
  3947. //
  3948. DBID aDbCols[cSafeArrayTestColsTight];
  3949. aDbCols[0] = colSA_I4;
  3950. aDbCols[1] = colSA_BSTR;
  3951. aDbCols[2] = colSA_VARIANT;
  3952. aDbCols[3] = colSA_R8;
  3953. aDbCols[4] = colSA_DATE;
  3954. aDbCols[5] = colSA_BOOL;
  3955. aDbCols[6] = colSA_DECIMAL;
  3956. aDbCols[7] = colSA_I1;
  3957. aDbCols[8] = colSA_R4;
  3958. aDbCols[9] = colSA_CY;
  3959. aDbCols[10] = colSA_UINT;
  3960. aDbCols[11] = colSA_INT;
  3961. aDbCols[12] = colSA_ERROR;
  3962. IUnknown * pAccessor = (IUnknown *) pRowset; // hAccessor must be created on rowset
  3963. // to be used with rowset->GetData below
  3964. HACCESSOR hAccessor = MapColumns( pAccessor,
  3965. cSafeArrayTestColsTight,
  3966. aSafeArrayTestColsTight,
  3967. aDbCols,
  3968. TRUE );
  3969. //
  3970. // Fetch the data
  3971. //
  3972. SSafeArrayTestColsTight saData;
  3973. for (unsigned row = 0; row < cRowsReturned; row++)
  3974. {
  3975. sc = pRowset->GetData(pgrhRows[row], hAccessor, &saData );
  3976. if (S_OK != sc)
  3977. {
  3978. LogError("IRowset->GetData returned 0x%x (expected 0)\n",sc);
  3979. pCmdTree->Release();
  3980. pRowset->Release();
  3981. Fail();
  3982. }
  3983. //
  3984. // Verify the data.
  3985. //
  3986. PROPVARIANT var;
  3987. var.vt = VT_ARRAY | VT_I4;
  3988. var.parray = saData.a_I4;
  3989. CheckPropertyValue( var, vaI4 );
  3990. var.vt = VT_ARRAY | VT_BSTR;
  3991. var.parray = saData.a_BSTR;
  3992. CheckPropertyValue( var, vaBSTR );
  3993. var.vt = VT_ARRAY | VT_VARIANT;
  3994. var.parray = saData.a_VARIANT;
  3995. CheckPropertyValue( var, vaVARIANT );
  3996. var.vt = VT_ARRAY | VT_R8;
  3997. var.parray = saData.a_R8;
  3998. CheckPropertyValue( var, vaR8 );
  3999. var.vt = VT_ARRAY | VT_DATE;
  4000. var.parray = saData.a_DATE;
  4001. CheckPropertyValue( var, vaDATE );
  4002. var.vt = VT_ARRAY | VT_BOOL;
  4003. var.parray = saData.a_BOOL;
  4004. CheckPropertyValue( var, vaBOOL );
  4005. var.vt = VT_ARRAY | VT_DECIMAL;
  4006. var.parray = saData.a_DECIMAL;
  4007. CheckPropertyValue( var, vaDECIMAL );
  4008. var.vt = VT_ARRAY | VT_I1;
  4009. var.parray = saData.a_I1;
  4010. CheckPropertyValue( var, vaI1 );
  4011. var.vt = VT_ARRAY | VT_R4;
  4012. var.parray = saData.a_R4;
  4013. CheckPropertyValue( var, vaR4 );
  4014. var.vt = VT_ARRAY | VT_CY;
  4015. var.parray = saData.a_CY;
  4016. CheckPropertyValue( var, vaCY );
  4017. var.vt = VT_ARRAY | VT_UINT;
  4018. var.parray = saData.a_UINT;
  4019. CheckPropertyValue( var, vaUINT );
  4020. var.vt = VT_ARRAY | VT_INT;
  4021. var.parray = saData.a_INT;
  4022. CheckPropertyValue( var, vaINT );
  4023. var.vt = VT_ARRAY | VT_ERROR;
  4024. var.parray = saData.a_ERROR;
  4025. CheckPropertyValue( var, vaERROR );
  4026. }
  4027. sc = pRowset->ReleaseRows( cRowsReturned, pgrhRows, 0, 0, 0);
  4028. if (S_OK != sc)
  4029. {
  4030. LogError("IRowset->ReleaseRows returned 0x%x (expected 0)\n",sc);
  4031. pCmdTree->Release();
  4032. pRowset->Release();
  4033. Fail();
  4034. }
  4035. CoTaskMemFree(pgrhRows);
  4036. pgrhRows = 0;
  4037. //
  4038. // Clean up.
  4039. //
  4040. ReleaseAccessor( pAccessor, hAccessor);
  4041. pCmdTree->Release();
  4042. pRowset->Release();
  4043. } //RunSafeArrayTightBindings
  4044. static DBBINDING aSafeArrayTestByRefCols[] =
  4045. {
  4046. { 0, 0 * cbPPV, 0, 0,
  4047. 0, 0, 0,
  4048. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  4049. cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  4050. { 1, 1 * cbPPV, 0, 0,
  4051. 0, 0, 0,
  4052. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  4053. cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  4054. { 2, 2 * cbPPV, 0, 0,
  4055. 0, 0, 0,
  4056. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  4057. cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  4058. { 3, 3 * cbPPV, 0, 0,
  4059. 0, 0, 0,
  4060. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  4061. cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  4062. { 4, 4 * cbPPV, 0, 0,
  4063. 0, 0, 0,
  4064. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  4065. cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  4066. { 5, 5 * cbPPV, 0, 0,
  4067. 0, 0, 0,
  4068. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  4069. cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  4070. { 6, 6 * cbPPV, 0, 0,
  4071. 0, 0, 0,
  4072. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  4073. cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  4074. { 7, 7 * cbPPV, 0, 0,
  4075. 0, 0, 0,
  4076. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  4077. cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  4078. { 8, 8 * cbPPV, 0, 0,
  4079. 0, 0, 0,
  4080. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  4081. cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  4082. { 9, 9 * cbPPV, 0, 0,
  4083. 0, 0, 0,
  4084. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  4085. cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  4086. { 10,10* cbPPV, 0, 0,
  4087. 0, 0, 0,
  4088. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  4089. cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  4090. { 11,11* cbPPV, 0, 0,
  4091. 0, 0, 0,
  4092. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  4093. cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  4094. { 12,12* cbPPV, 0, 0,
  4095. 0, 0, 0,
  4096. DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM,
  4097. cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0},
  4098. };
  4099. const ULONG cSafeArrayTestByRefCols = sizeof aSafeArrayTestByRefCols / sizeof aSafeArrayTestByRefCols[0];
  4100. void RunSafeArrayByRefBindings(
  4101. ICommand * pQuery,
  4102. CDbRestriction & PropRst,
  4103. unsigned cExpectedHits,
  4104. unsigned numTest )
  4105. {
  4106. //
  4107. // Get 13 properties back
  4108. //
  4109. CDbColumns cols(cSafeArrayTestByRefCols);
  4110. cols.Add( colSA_I4, 0 );
  4111. cols.Add( colSA_BSTR, 1 );
  4112. cols.Add( colSA_VARIANT, 2 );
  4113. cols.Add( colSA_R8, 3 );
  4114. cols.Add( colSA_DATE, 4 );
  4115. cols.Add( colSA_BOOL, 5 );
  4116. cols.Add( colSA_DECIMAL, 6 );
  4117. cols.Add( colSA_I1, 7 );
  4118. cols.Add( colSA_R4, 8 );
  4119. cols.Add( colSA_CY, 9 );
  4120. cols.Add( colSA_UINT, 10 );
  4121. cols.Add( colSA_INT, 11 );
  4122. cols.Add( colSA_ERROR, 12 );
  4123. BOOL fSeq = isEven( numTest );
  4124. CDbSortSet ss( 1 );
  4125. ss.Add( colSA_CY, 0 );
  4126. //
  4127. // Do it!
  4128. //
  4129. CDbCmdTreeNode * pDbCmdTree = FormQueryTree( &PropRst,
  4130. cols,
  4131. fSeq ? 0 : &ss );
  4132. ICommandTree * pCmdTree = 0;
  4133. IRowsetScroll * pRowset = InstantiateRowset(
  4134. pQuery,
  4135. QUERY_SHALLOW, // Depth
  4136. 0,
  4137. pDbCmdTree, // DBCOMMANDTREE
  4138. fSeq ? IID_IRowset : IID_IRowsetScroll, // IID for i/f to return
  4139. 0,
  4140. &pCmdTree );
  4141. //
  4142. // Verify columns
  4143. //
  4144. CheckColumns( pRowset, cols, TRUE );
  4145. if ( !WaitForCompletion( pRowset, TRUE ) )
  4146. {
  4147. pCmdTree->Release();
  4148. pRowset->Release();
  4149. LogFail( "property query unsuccessful.\n" );
  4150. }
  4151. //
  4152. // Get data
  4153. //
  4154. DBCOUNTITEM cRowsReturned = 0;
  4155. HROW* pgrhRows = 0;
  4156. SCODE sc = pRowset->GetNextRows(0, 0, 10, &cRowsReturned, &pgrhRows);
  4157. if ( FAILED( sc ) )
  4158. {
  4159. pCmdTree->Release();
  4160. pRowset->Release();
  4161. LogFail( "IRowset->GetRowsAt G returned 0x%x\n", sc );
  4162. }
  4163. if ( 0 == cExpectedHits )
  4164. {
  4165. pCmdTree->Release();
  4166. pRowset->Release();
  4167. if ( cRowsReturned > 0 )
  4168. LogFail("RunPropQuery, %d returned rows, expected none\n",
  4169. cRowsReturned);
  4170. else
  4171. return;
  4172. }
  4173. if (sc != DB_S_ENDOFROWSET &&
  4174. cRowsReturned != 10)
  4175. {
  4176. LogError( "IRowset->GetRowsAt H returned %d of %d rows,"
  4177. " status (%x) != DB_S_ENDOFROWSET\n",
  4178. cRowsReturned, 10,
  4179. sc);
  4180. pCmdTree->Release();
  4181. pRowset->Release();
  4182. #if defined(UNIT_TEST)
  4183. cFailures++;
  4184. return;
  4185. #else
  4186. Fail();
  4187. #endif
  4188. }
  4189. //
  4190. // Expect 1 or 2 hits
  4191. //
  4192. if (sc != DB_S_ENDOFROWSET || cRowsReturned != cExpectedHits)
  4193. {
  4194. LogError( "IRowset->GetRowsAt I returned %d rows (expected %d),"
  4195. " status (%x)\n",
  4196. cRowsReturned, cExpectedHits, sc );
  4197. pCmdTree->Release();
  4198. pRowset->Release();
  4199. #if defined(UNIT_TEST)
  4200. cFailures++;
  4201. return;
  4202. #else
  4203. Fail();
  4204. #endif
  4205. }
  4206. //
  4207. // Patch the column index numbers with true column ids
  4208. //
  4209. DBID aDbCols[cSafeArrayTestByRefCols];
  4210. aDbCols[0] = colSA_I4;
  4211. aDbCols[1] = colSA_BSTR;
  4212. aDbCols[2] = colSA_VARIANT;
  4213. aDbCols[3] = colSA_R8;
  4214. aDbCols[4] = colSA_DATE;
  4215. aDbCols[5] = colSA_BOOL;
  4216. aDbCols[6] = colSA_DECIMAL;
  4217. aDbCols[7] = colSA_I1;
  4218. aDbCols[8] = colSA_R4;
  4219. aDbCols[9] = colSA_CY;
  4220. aDbCols[10] = colSA_UINT;
  4221. aDbCols[11] = colSA_INT;
  4222. aDbCols[12] = colSA_ERROR;
  4223. IUnknown * pAccessor = (IUnknown *) pRowset; // hAccessor must be created on rowset
  4224. // to be used with rowset->GetData below
  4225. HACCESSOR hAccessor = MapColumns( pAccessor,
  4226. cSafeArrayTestByRefCols,
  4227. aSafeArrayTestByRefCols,
  4228. aDbCols,
  4229. TRUE );
  4230. //
  4231. // Fetch the data
  4232. //
  4233. PROPVARIANT * aVarnt[cSafeArrayTestByRefCols];
  4234. for (unsigned row = 0; row < cRowsReturned; row++)
  4235. {
  4236. sc = pRowset->GetData(pgrhRows[row], hAccessor, aVarnt);
  4237. if (S_OK != sc)
  4238. {
  4239. LogError("IRowset->GetData returned 0x%x (expected 0)\n",sc);
  4240. pCmdTree->Release();
  4241. pRowset->Release();
  4242. Fail();
  4243. }
  4244. //
  4245. // Verify the data.
  4246. //
  4247. CheckPropertyValue( *aVarnt[0], vaI4 );
  4248. CheckPropertyValue( *aVarnt[1], vaBSTR );
  4249. CheckPropertyValue( *aVarnt[2], vaVARIANT );
  4250. CheckPropertyValue( *aVarnt[3], vaR8 );
  4251. CheckPropertyValue( *aVarnt[4], vaDATE );
  4252. CheckPropertyValue( *aVarnt[5], vaBOOL );
  4253. CheckPropertyValue( *aVarnt[6], vaDECIMAL );
  4254. CheckPropertyValue( *aVarnt[7], vaI1 );
  4255. CheckPropertyValue( *aVarnt[8], vaR4 );
  4256. CheckPropertyValue( *aVarnt[9], vaCY );
  4257. CheckPropertyValue( *aVarnt[10], vaUINT );
  4258. CheckPropertyValue( *aVarnt[11], vaINT );
  4259. CheckPropertyValue( *aVarnt[12], vaERROR );
  4260. }
  4261. sc = pRowset->ReleaseRows( cRowsReturned, pgrhRows, 0, 0, 0);
  4262. if (S_OK != sc)
  4263. {
  4264. LogError("IRowset->ReleaseRows returned 0x%x (expected 0)\n",sc);
  4265. pCmdTree->Release();
  4266. pRowset->Release();
  4267. Fail();
  4268. }
  4269. CoTaskMemFree(pgrhRows);
  4270. pgrhRows = 0;
  4271. //
  4272. // Clean up.
  4273. //
  4274. ReleaseAccessor( pAccessor, hAccessor);
  4275. pCmdTree->Release();
  4276. pRowset->Release();
  4277. } //RunSafeArrayByRefBindings
  4278. static DBBINDING aSafeArrayTestCols[] =
  4279. {
  4280. { 0, 0 * cbPV, 0, 0,
  4281. 0, 0, 0,
  4282. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  4283. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  4284. { 1, 1 * cbPV, 0, 0,
  4285. 0, 0, 0,
  4286. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  4287. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  4288. { 2, 2 * cbPV, 0, 0,
  4289. 0, 0, 0,
  4290. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  4291. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  4292. { 3, 3 * cbPV, 0, 0,
  4293. 0, 0, 0,
  4294. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  4295. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  4296. { 4, 4 * cbPV, 0, 0,
  4297. 0, 0, 0,
  4298. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  4299. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  4300. { 5, 5 * cbPV, 0, 0,
  4301. 0, 0, 0,
  4302. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  4303. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  4304. { 6, 6 * cbPV, 0, 0,
  4305. 0, 0, 0,
  4306. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  4307. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  4308. { 7, 7 * cbPV, 0, 0,
  4309. 0, 0, 0,
  4310. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  4311. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  4312. { 8, 8 * cbPV, 0, 0,
  4313. 0, 0, 0,
  4314. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  4315. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  4316. { 9, 9 * cbPV, 0, 0,
  4317. 0, 0, 0,
  4318. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  4319. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  4320. { 10,10* cbPV, 0, 0,
  4321. 0, 0, 0,
  4322. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  4323. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  4324. { 11,11* cbPV, 0, 0,
  4325. 0, 0, 0,
  4326. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  4327. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  4328. { 12,12* cbPV, 0, 0,
  4329. 0, 0, 0,
  4330. DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  4331. cbPV, 0, DBTYPE_VARIANT, 0, 0},
  4332. };
  4333. const ULONG cSafeArrayTestCols = sizeof aSafeArrayTestCols / sizeof aSafeArrayTestCols[0];
  4334. void RunSafeArrayQuery(
  4335. ICommand * pQuery,
  4336. CDbRestriction & PropRst,
  4337. unsigned cExpectedHits,
  4338. unsigned numTest )
  4339. {
  4340. RunSafeArrayTightBindings( pQuery, PropRst, cExpectedHits, numTest );
  4341. RunSafeArrayByRefBindings( pQuery, PropRst, cExpectedHits, numTest );
  4342. //
  4343. // Get twelve properties back
  4344. //
  4345. CDbColumns cols(cSafeArrayTestCols);
  4346. cols.Add( colSA_I4, 0 );
  4347. cols.Add( colSA_BSTR, 1 );
  4348. cols.Add( colSA_VARIANT, 2 );
  4349. cols.Add( colSA_R8, 3 );
  4350. cols.Add( colSA_DATE, 4 );
  4351. cols.Add( colSA_BOOL, 5 );
  4352. cols.Add( colSA_DECIMAL, 6 );
  4353. cols.Add( colSA_I1, 7 );
  4354. cols.Add( colSA_R4, 8 );
  4355. cols.Add( colSA_CY, 9 );
  4356. cols.Add( colSA_UINT, 10 );
  4357. cols.Add( colSA_INT, 11 );
  4358. cols.Add( colSA_ERROR, 12 );
  4359. BOOL fSeq = isEven( numTest );
  4360. CDbSortSet ss( 1 );
  4361. ss.Add( colSA_BSTR, 0 );
  4362. //
  4363. // Do it!
  4364. //
  4365. CDbCmdTreeNode * pDbCmdTree = FormQueryTree( &PropRst,
  4366. cols,
  4367. fSeq ? 0 : &ss );
  4368. ICommandTree * pCmdTree = 0;
  4369. IRowsetScroll * pRowset = InstantiateRowset(
  4370. pQuery,
  4371. QUERY_SHALLOW, // Depth
  4372. 0,
  4373. pDbCmdTree, // DBCOMMANDTREE
  4374. fSeq ? IID_IRowset : IID_IRowsetScroll, // IID for i/f to return
  4375. 0,
  4376. &pCmdTree );
  4377. //
  4378. // Verify columns
  4379. //
  4380. CheckColumns( pRowset, cols, TRUE );
  4381. if ( !WaitForCompletion( pRowset, TRUE ) )
  4382. {
  4383. pCmdTree->Release();
  4384. pRowset->Release();
  4385. LogFail( "property query unsuccessful.\n" );
  4386. }
  4387. //
  4388. // Get data
  4389. //
  4390. DBCOUNTITEM cRowsReturned = 0;
  4391. HROW* pgrhRows = 0;
  4392. SCODE sc = pRowset->GetNextRows(0, 0, 10, &cRowsReturned, &pgrhRows);
  4393. if ( FAILED( sc ) )
  4394. {
  4395. pCmdTree->Release();
  4396. pRowset->Release();
  4397. LogFail( "IRowset->GetRowsAt G returned 0x%x\n", sc );
  4398. }
  4399. if ( 0 == cExpectedHits )
  4400. {
  4401. pCmdTree->Release();
  4402. pRowset->Release();
  4403. if ( cRowsReturned > 0 )
  4404. LogFail("RunPropQuery, %d returned rows, expected none\n",
  4405. cRowsReturned);
  4406. else
  4407. return;
  4408. }
  4409. if (sc != DB_S_ENDOFROWSET &&
  4410. cRowsReturned != 10)
  4411. {
  4412. LogError( "IRowset->GetRowsAt H returned %d of %d rows,"
  4413. " status (%x) != DB_S_ENDOFROWSET\n",
  4414. cRowsReturned, 10,
  4415. sc);
  4416. pCmdTree->Release();
  4417. pRowset->Release();
  4418. #if defined(UNIT_TEST)
  4419. cFailures++;
  4420. return;
  4421. #else
  4422. Fail();
  4423. #endif
  4424. }
  4425. //
  4426. // Expect 1 or 2 hits
  4427. //
  4428. if (sc != DB_S_ENDOFROWSET || cRowsReturned != cExpectedHits)
  4429. {
  4430. LogError( "IRowset->GetRowsAt I returned %d rows (expected %d),"
  4431. " status (%x)\n",
  4432. cRowsReturned, cExpectedHits, sc );
  4433. pCmdTree->Release();
  4434. pRowset->Release();
  4435. #if defined(UNIT_TEST)
  4436. cFailures++;
  4437. return;
  4438. #else
  4439. Fail();
  4440. #endif
  4441. }
  4442. //
  4443. // Patch the column index numbers with true column ids
  4444. //
  4445. DBID aDbCols[cSafeArrayTestCols];
  4446. aDbCols[0] = colSA_I4;
  4447. aDbCols[1] = colSA_BSTR;
  4448. aDbCols[2] = colSA_VARIANT;
  4449. aDbCols[3] = colSA_R8;
  4450. aDbCols[4] = colSA_DATE;
  4451. aDbCols[5] = colSA_BOOL;
  4452. aDbCols[6] = colSA_DECIMAL;
  4453. aDbCols[7] = colSA_I1;
  4454. aDbCols[8] = colSA_R4;
  4455. aDbCols[9] = colSA_CY;
  4456. aDbCols[10] = colSA_UINT;
  4457. aDbCols[11] = colSA_INT;
  4458. aDbCols[12] = colSA_ERROR;
  4459. IUnknown * pAccessor = (IUnknown *) pRowset; // hAccessor must be created on rowset
  4460. // to be used with rowset->GetData below
  4461. HACCESSOR hAccessor = MapColumns(pAccessor, cSafeArrayTestCols, aSafeArrayTestCols, aDbCols);
  4462. //
  4463. // Fetch the data
  4464. //
  4465. PROPVARIANT aVarnt[cSafeArrayTestCols];
  4466. for (unsigned row = 0; row < cRowsReturned; row++)
  4467. {
  4468. sc = pRowset->GetData(pgrhRows[row], hAccessor, aVarnt);
  4469. if (S_OK != sc)
  4470. {
  4471. LogError("IRowset->GetData returned 0x%x (expected 0)\n",sc);
  4472. pCmdTree->Release();
  4473. pRowset->Release();
  4474. Fail();
  4475. }
  4476. //
  4477. // Verify the data.
  4478. //
  4479. CheckPropertyValue( aVarnt[0], vaI4 );
  4480. CheckPropertyValue( aVarnt[1], vaBSTR );
  4481. CheckPropertyValue( aVarnt[2], vaVARIANT );
  4482. CheckPropertyValue( aVarnt[3], vaR8 );
  4483. CheckPropertyValue( aVarnt[4], vaDATE );
  4484. CheckPropertyValue( aVarnt[5], vaBOOL );
  4485. CheckPropertyValue( aVarnt[6], vaDECIMAL );
  4486. CheckPropertyValue( aVarnt[7], vaI1 );
  4487. CheckPropertyValue( aVarnt[8], vaR4 );
  4488. CheckPropertyValue( aVarnt[9], vaCY );
  4489. CheckPropertyValue( aVarnt[10], vaUINT );
  4490. CheckPropertyValue( aVarnt[11], vaINT );
  4491. CheckPropertyValue( aVarnt[12], vaERROR );
  4492. for ( int i = 0; i < 13; i++ )
  4493. PropVariantClear( & aVarnt[i] );
  4494. }
  4495. sc = pRowset->ReleaseRows( cRowsReturned, pgrhRows, 0, 0, 0);
  4496. if (S_OK != sc)
  4497. {
  4498. LogError("IRowset->ReleaseRows returned 0x%x (expected 0)\n",sc);
  4499. pCmdTree->Release();
  4500. pRowset->Release();
  4501. Fail();
  4502. }
  4503. CoTaskMemFree(pgrhRows);
  4504. pgrhRows = 0;
  4505. //
  4506. // Clean up.
  4507. //
  4508. ReleaseAccessor( pAccessor, hAccessor);
  4509. pCmdTree->Release();
  4510. pRowset->Release();
  4511. } //RunSafeArrayQuery
  4512. //+-------------------------------------------------------------------------
  4513. //
  4514. // Function: RunSafeArrayTest, public
  4515. //
  4516. // Synopsis: Very minimal test of safe array property query
  4517. //
  4518. // History: 17-Jun-98 dlee Created
  4519. //
  4520. //--------------------------------------------------------------------------
  4521. void RunSafeArrayTest( void )
  4522. {
  4523. LogProgress( "SafeArray Retrieval Test\n" );
  4524. WCHAR *pwszScope = wcsTestPath;
  4525. DWORD dwDepth = QUERY_SHALLOW;
  4526. IUnknown * pIUnknown;
  4527. ICommand * pQuery = 0;
  4528. SCODE scIC = CICreateCommand( &pIUnknown,
  4529. 0,
  4530. IID_IUnknown,
  4531. TEST_CATALOG,
  4532. TEST_MACHINE );
  4533. if ( FAILED( scIC ) )
  4534. LogFail( "RunSafeArrayTest - error 0x%x Unable to create ICommand\n",
  4535. scIC );
  4536. scIC = pIUnknown->QueryInterface(IID_ICommand, (void **) &pQuery );
  4537. pIUnknown->Release();
  4538. if ( FAILED( scIC ) )
  4539. LogFail( "RunSafeArrayTest - error 0x%x Unable to QI ICommand\n",
  4540. scIC );
  4541. if ( 0 == pQuery )
  4542. LogFail( "RunSafeArrayTest - CICreateCommand succeeded, but returned null pQuery\n" );
  4543. scIC = SetScopeProperties( pQuery,
  4544. 1,
  4545. &pwszScope,
  4546. &dwDepth );
  4547. if ( FAILED( scIC ) )
  4548. LogFail( "RunSafeArrayTest - error 0x%x Unable to set scope '%ws'\n",
  4549. scIC, pwszScope );
  4550. CheckPropertiesOnCommand( pQuery );
  4551. unsigned numTest = 1;
  4552. {
  4553. LogProgress( " SafeArray test 1\n" );
  4554. CDbPropertyRestriction PropRst;
  4555. PropRst.SetProperty( colSA_I4 );
  4556. PropRst.SetRelation( DBOP_equal );
  4557. PropRst.SetValue( vaI4 );
  4558. RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ );
  4559. }
  4560. {
  4561. LogProgress( " SafeArray test 2\n" );
  4562. CDbPropertyRestriction PropRst;
  4563. PropRst.SetProperty( colSA_BSTR );
  4564. PropRst.SetRelation( DBOP_equal );
  4565. PropRst.SetValue( vaBSTR );
  4566. RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ );
  4567. }
  4568. {
  4569. LogProgress( " SafeArray test 3\n" );
  4570. CDbPropertyRestriction PropRst;
  4571. PropRst.SetProperty( colSA_VARIANT );
  4572. PropRst.SetRelation( DBOP_equal );
  4573. PropRst.SetValue( vaVARIANT );
  4574. RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ );
  4575. }
  4576. {
  4577. LogProgress( " SafeArray test 4\n" );
  4578. CDbPropertyRestriction PropRst;
  4579. PropRst.SetProperty( colSA_R8 );
  4580. PropRst.SetRelation( DBOP_equal );
  4581. PropRst.SetValue( vaR8 );
  4582. RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ );
  4583. }
  4584. {
  4585. LogProgress( " SafeArray test 5\n" );
  4586. CDbPropertyRestriction PropRst;
  4587. PropRst.SetProperty( colSA_DATE );
  4588. PropRst.SetRelation( DBOP_equal );
  4589. PropRst.SetValue( vaDATE );
  4590. RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ );
  4591. }
  4592. {
  4593. LogProgress( " SafeArray test 6\n" );
  4594. CDbPropertyRestriction PropRst;
  4595. PropRst.SetProperty( colSA_BOOL );
  4596. PropRst.SetRelation( DBOP_equal );
  4597. PropRst.SetValue( vaBOOL );
  4598. RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ );
  4599. }
  4600. {
  4601. LogProgress( " SafeArray test 7\n" );
  4602. CDbPropertyRestriction PropRst;
  4603. PropRst.SetProperty( colSA_DECIMAL );
  4604. PropRst.SetRelation( DBOP_equal );
  4605. PropRst.SetValue( vaDECIMAL );
  4606. RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ );
  4607. }
  4608. {
  4609. LogProgress( " SafeArray test 8\n" );
  4610. CDbPropertyRestriction PropRst;
  4611. PropRst.SetProperty( colSA_I1 );
  4612. PropRst.SetRelation( DBOP_equal );
  4613. PropRst.SetValue( vaI1 );
  4614. RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ );
  4615. }
  4616. {
  4617. LogProgress( " SafeArray test 9\n" );
  4618. CDbPropertyRestriction PropRst;
  4619. PropRst.SetProperty( colSA_R4 );
  4620. PropRst.SetRelation( DBOP_equal );
  4621. PropRst.SetValue( vaR4 );
  4622. RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ );
  4623. }
  4624. {
  4625. LogProgress( " SafeArray test 10\n" );
  4626. CDbPropertyRestriction PropRst;
  4627. PropRst.SetProperty( colSA_CY );
  4628. PropRst.SetRelation( DBOP_equal );
  4629. PropRst.SetValue( vaCY );
  4630. RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ );
  4631. }
  4632. {
  4633. LogProgress( " SafeArray test 11\n" );
  4634. CDbPropertyRestriction PropRst;
  4635. PropRst.SetProperty( colSA_UINT );
  4636. PropRst.SetRelation( DBOP_equal );
  4637. PropRst.SetValue( vaUINT );
  4638. RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ );
  4639. }
  4640. {
  4641. LogProgress( " SafeArray test 12\n" );
  4642. CDbPropertyRestriction PropRst;
  4643. PropRst.SetProperty( colSA_INT );
  4644. PropRst.SetRelation( DBOP_equal );
  4645. PropRst.SetValue( vaINT );
  4646. RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ );
  4647. }
  4648. {
  4649. LogProgress( " SafeArray test 13\n" );
  4650. CDbPropertyRestriction PropRst;
  4651. PropRst.SetProperty( colSA_ERROR );
  4652. PropRst.SetRelation( DBOP_equal );
  4653. PropRst.SetValue( vaERROR );
  4654. RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ );
  4655. }
  4656. pQuery->Release();
  4657. } //RunSafeArrayTest
  4658. //+-------------------------------------------------------------------------
  4659. //
  4660. // Function: CheckPropertyValue, public
  4661. //
  4662. // Synopsis: Check that a returned property value is as expected
  4663. //
  4664. // Arguments: [varntPropRet] -- Returned property value
  4665. // [varntPropExp] -- Expected property value
  4666. //
  4667. // Returns: nothing - calls Fail() if error
  4668. //
  4669. // History: 20 Oct 93 Alanw Created
  4670. //
  4671. //--------------------------------------------------------------------------
  4672. void CheckPropertyValue(
  4673. PROPVARIANT const & varntPropRet,
  4674. PROPVARIANT const & varntPropExp
  4675. ) {
  4676. if ( varntPropRet.vt != varntPropExp.vt )
  4677. {
  4678. LogError( "Invalid return data type for property!\n" );
  4679. LogError( " Got %x expected %x\n",
  4680. varntPropRet.vt, varntPropExp.vt );
  4681. cFailures++;
  4682. //Fail();
  4683. }
  4684. else if (varntPropExp.vt & VT_ARRAY)
  4685. {
  4686. SAFEARRAY * pSaRet = varntPropRet.parray;
  4687. SAFEARRAY * pSaExp = varntPropExp.parray;
  4688. if (pSaRet->fFeatures != pSaExp->fFeatures ||
  4689. // pSaRet->cLocks != pSaExp->cLocks ||
  4690. pSaRet->cDims != pSaExp->cDims ||
  4691. pSaRet->cbElements!= pSaExp->cbElements)
  4692. {
  4693. LogError( "Mismatched safearray param!\n" );
  4694. LogError( " Got %x expected %x\n", pSaRet, pSaExp );
  4695. cFailures++;
  4696. //Fail();
  4697. }
  4698. else
  4699. {
  4700. BOOL fValuesEqual = TRUE;
  4701. unsigned cDataElements = 1;
  4702. //
  4703. // get total data memory, and number of data elements in it.
  4704. //
  4705. for ( unsigned i = 0; i < pSaExp->cDims; i++ )
  4706. {
  4707. if ( pSaExp->rgsabound[i].cElements != pSaRet->rgsabound[i].cElements ||
  4708. pSaExp->rgsabound[i].lLbound != pSaRet->rgsabound[i].lLbound )
  4709. {
  4710. LogError( "Mismatched safearray dimension %d!\n", i );
  4711. LogError( " Got %x expected %x\n", pSaRet, pSaExp );
  4712. fValuesEqual = FALSE;
  4713. //Fail();
  4714. }
  4715. cDataElements *= pSaExp->rgsabound[i].cElements;
  4716. }
  4717. if (fValuesEqual)
  4718. {
  4719. ULONG cb = cDataElements * pSaExp->cbElements;
  4720. if ( varntPropExp.vt == (VT_ARRAY|VT_VARIANT ))
  4721. {
  4722. // Not needed as the engine doesn't support it yet.
  4723. LogError( "can't validate arrays of variant\n" );
  4724. }
  4725. else if (varntPropExp.vt != (VT_ARRAY|VT_BSTR))
  4726. {
  4727. fValuesEqual = memcmp( pSaExp->pvData, pSaRet->pvData, cb ) == 0;
  4728. if (! fValuesEqual)
  4729. {
  4730. if ( 0 == ( cb % sizeof ULONGLONG ) )
  4731. {
  4732. ULONG c = cb / sizeof ULONGLONG;
  4733. unsigned __int64 *pE = (unsigned __int64 *) pSaExp->pvData;
  4734. unsigned __int64 *pR = (unsigned __int64 *) pSaRet->pvData;
  4735. for ( ULONG i = 0; i < c; i++ )
  4736. {
  4737. printf( "%d: e %#I64x, r %#I64x\n",
  4738. i, pE[i], pR[i] );
  4739. }
  4740. }
  4741. printf( "varntPropExp: %#x\n", varntPropExp.vt );
  4742. printf( "varntPropRet: %#x\n", varntPropRet.vt );
  4743. LogError("Incorrect value for safearray property.\n");
  4744. // " Got %d, expected %d\n", i,
  4745. // varntPropRet.cal.pElems[i],
  4746. // varntPropExp.cal.pElems[i]);
  4747. }
  4748. }
  4749. else
  4750. {
  4751. BSTR * rgbstrExp = (BSTR *)pSaExp->pvData;
  4752. BSTR * rgbstrRet = (BSTR *)pSaRet->pvData;
  4753. for (unsigned i=0; i<cDataElements; i++)
  4754. {
  4755. fValuesEqual = (BSTRLEN(rgbstrRet[i]) ==
  4756. BSTRLEN(rgbstrExp[i])) &&
  4757. (memcmp(rgbstrRet[i],
  4758. rgbstrExp[i],
  4759. BSTRLEN(rgbstrExp[i])) == 0);
  4760. if (! fValuesEqual)
  4761. {
  4762. LogError("Incorrect value for BSTR array property [%d].\n"
  4763. " Got <%ws>, expected <%ws>\n", i,
  4764. rgbstrRet[i],
  4765. rgbstrExp[i]);
  4766. break;
  4767. }
  4768. }
  4769. }
  4770. }
  4771. if (! fValuesEqual)
  4772. {
  4773. cFailures++;
  4774. //Fail();
  4775. }
  4776. }
  4777. }
  4778. else if (varntPropExp.vt & VT_VECTOR)
  4779. {
  4780. if (varntPropExp.cal.cElems != varntPropRet.cal.cElems)
  4781. {
  4782. LogError( "Incorrect value count for property.\n"
  4783. " Got count %d, expected count %d\n",
  4784. varntPropRet.cal.cElems, varntPropExp.cal.cElems);
  4785. cFailures++;
  4786. //Fail();
  4787. }
  4788. BOOL fValuesEqual = FALSE;
  4789. for (unsigned i=0; i<varntPropRet.cal.cElems; i++) {
  4790. switch (varntPropExp.vt)
  4791. {
  4792. case VT_VECTOR|VT_I4:
  4793. fValuesEqual = varntPropRet.cal.pElems[i] ==
  4794. varntPropExp.cal.pElems[i];
  4795. if (! fValuesEqual)
  4796. LogError("Incorrect value for vector property [%d].\n"
  4797. " Got %d, expected %d\n", i,
  4798. varntPropRet.cal.pElems[i],
  4799. varntPropExp.cal.pElems[i]);
  4800. break;
  4801. case VT_VECTOR|VT_LPWSTR:
  4802. fValuesEqual = wcscmp(varntPropRet.calpwstr.pElems[i],
  4803. varntPropExp.calpwstr.pElems[i]) == 0;
  4804. if (! fValuesEqual)
  4805. LogError("Incorrect value for vector property [%d].\n"
  4806. " Got <%ws>, expected <%ws>\n", i,
  4807. varntPropRet.calpwstr.pElems[i],
  4808. varntPropExp.calpwstr.pElems[i]);
  4809. break;
  4810. case VT_VECTOR|VT_BSTR:
  4811. fValuesEqual = (BSTRLEN(varntPropRet.cabstr.pElems[i]) ==
  4812. BSTRLEN(varntPropExp.cabstr.pElems[i])) &&
  4813. (memcmp(varntPropRet.cabstr.pElems[i],
  4814. varntPropExp.cabstr.pElems[i],
  4815. BSTRLEN(varntPropExp.cabstr.pElems[i])) == 0);
  4816. if (! fValuesEqual)
  4817. LogError("Incorrect value for vector property [%d].\n"
  4818. " Got <%ws>, expected <%ws>\n", i,
  4819. varntPropRet.cabstr.pElems[i],
  4820. varntPropExp.cabstr.pElems[i]);
  4821. break;
  4822. case VT_VECTOR|VT_CF:
  4823. {
  4824. CLIPDATA & cdR = varntPropRet.caclipdata.pElems[i];
  4825. CLIPDATA & cdE = varntPropExp.caclipdata.pElems[i];
  4826. fValuesEqual = ( ( cdR.cbSize == cdE.cbSize ) &&
  4827. ( cdR.ulClipFmt == cdE.ulClipFmt ) &&
  4828. ( 0 != cdR.pClipData ) &&
  4829. ( 0 != cdE.pClipData ) &&
  4830. ( 0 == memcmp( cdR.pClipData,
  4831. cdE.pClipData,
  4832. CBPCLIPDATA( cdR ) ) ) );
  4833. if ( !fValuesEqual )
  4834. LogError( "Incorrect value for VT_VECTOR|VT_CF property\n" );
  4835. break;
  4836. }
  4837. default:
  4838. LogError("Unexpected property variant type %x\n", varntPropExp.vt);
  4839. }
  4840. if (! fValuesEqual)
  4841. {
  4842. cFailures++;
  4843. //Fail();
  4844. }
  4845. }
  4846. }
  4847. else
  4848. {
  4849. BOOL fValuesEqual = FALSE;
  4850. switch (varntPropExp.vt)
  4851. {
  4852. case VT_I4:
  4853. fValuesEqual = varntPropRet.iVal == varntPropExp.iVal;
  4854. if (! fValuesEqual)
  4855. LogError("Incorrect value for property.\n"
  4856. " Got %d, expected %d\n",
  4857. varntPropRet.iVal, varntPropExp.iVal);
  4858. break;
  4859. case VT_LPWSTR:
  4860. case DBTYPE_WSTR | DBTYPE_BYREF:
  4861. fValuesEqual = wcscmp(varntPropRet.pwszVal, varntPropExp.pwszVal)
  4862. == 0;
  4863. if (! fValuesEqual)
  4864. LogError("Incorrect value for property.\n"
  4865. " Got <%ws>, expected <%ws>\n",
  4866. varntPropRet.pwszVal, varntPropExp.pwszVal);
  4867. break;
  4868. case VT_BSTR:
  4869. fValuesEqual =
  4870. ( SysStringLen( varntPropRet.bstrVal ) ==
  4871. SysStringLen( varntPropExp.bstrVal ) ) &&
  4872. memcmp( varntPropRet.bstrVal, varntPropExp.bstrVal,
  4873. SysStringLen( varntPropExp.bstrVal ) ) == 0;
  4874. if ( SysStringLen( varntPropRet.bstrVal ) !=
  4875. SysStringLen( varntPropExp.bstrVal ) )
  4876. LogError("Incorrect BSTR length for property.\n"
  4877. " Got %d, expected %d\n",
  4878. SysStringLen( varntPropRet.bstrVal ),
  4879. SysStringLen( varntPropExp.bstrVal ) );
  4880. else if (! fValuesEqual)
  4881. LogError("Incorrect value for property.\n"
  4882. " Got <%ws>, expected <%ws>\n",
  4883. varntPropRet.pwszVal, varntPropExp.pwszVal);
  4884. break;
  4885. case VT_CLSID:
  4886. fValuesEqual = *varntPropRet.puuid == *varntPropExp.puuid;
  4887. if (! fValuesEqual)
  4888. LogError("Incorrect value for guid property.\n");
  4889. break;
  4890. case VT_BLOB:
  4891. fValuesEqual =
  4892. (varntPropRet.blob.cbSize == varntPropExp.blob.cbSize) &&
  4893. memcmp(varntPropRet.blob.pBlobData, varntPropExp.blob.pBlobData,
  4894. varntPropExp.blob.cbSize)
  4895. == 0;
  4896. if (! fValuesEqual)
  4897. LogError("Incorrect value for blob property.\n");
  4898. break;
  4899. case VT_CF:
  4900. {
  4901. CLIPDATA & cdR = *varntPropRet.pclipdata;
  4902. CLIPDATA & cdE = *varntPropExp.pclipdata;
  4903. fValuesEqual = ( ( cdR.cbSize == cdE.cbSize ) &&
  4904. ( cdR.ulClipFmt == cdE.ulClipFmt ) &&
  4905. ( 0 != cdR.pClipData ) &&
  4906. ( 0 != cdE.pClipData ) &&
  4907. ( 0 == memcmp( cdR.pClipData,
  4908. cdE.pClipData,
  4909. CBPCLIPDATA( cdR ) ) ) );
  4910. if ( !fValuesEqual )
  4911. LogError( "Incorrect value for VT_CF property\n" );
  4912. break;
  4913. }
  4914. case VT_EMPTY:
  4915. // nothing to check
  4916. fValuesEqual = TRUE;
  4917. break;
  4918. default:
  4919. LogError("Unexpected property variant type %d\n", varntPropExp.vt);
  4920. }
  4921. if (! fValuesEqual)
  4922. {
  4923. cFailures++;
  4924. //Fail();
  4925. }
  4926. }
  4927. return;
  4928. } //CheckPropertyValue
  4929. #ifdef DO_CONTENT_TESTS
  4930. //+-------------------------------------------------------------------------
  4931. //
  4932. // Function: DoContentQuery, public
  4933. //
  4934. // Synopsis: Execute a retricted content query and check results
  4935. //
  4936. // Arguments: [pQuery] -- ICommand * for the query
  4937. // [CiRst] -- content restirction
  4938. // [cExpectedHits] -- expected number of hits
  4939. //
  4940. // Returns: BOOL - FALSE if first content query, and less than the
  4941. // expected number of hits was found. Probably indicates
  4942. // that the content index was not up-to-date.
  4943. //
  4944. // History: 01 Aug 1995 AlanW Created
  4945. //
  4946. //--------------------------------------------------------------------------
  4947. const unsigned MAX_CI_RETRIES = 5;
  4948. const unsigned CI_SLEEP_TICKS = 15 * 1000;
  4949. BOOL DoContentQuery(
  4950. ICommand * pQuery,
  4951. CDbRestriction & CiRst,
  4952. unsigned cExpectedHits )
  4953. {
  4954. static fFirstTime = TRUE;
  4955. //
  4956. // Get three properties back
  4957. //
  4958. CDbColumns cols(3);
  4959. cols.Add( psName, 0 );
  4960. cols.Add( psPath, 1 );
  4961. cols.Add( psRank, 2 );
  4962. //
  4963. // Do it!
  4964. //
  4965. unsigned cRetries = 0;
  4966. DBCOUNTITEM cRowsReturned = 0;
  4967. HROW* pgrhRows = 0;
  4968. SCODE sc;
  4969. IRowset * pRowset = 0;
  4970. do {
  4971. CDbCmdTreeNode * pCmdTree = FormQueryTree(&CiRst, cols, 0);
  4972. pRowset = InstantiateRowset( pQuery,
  4973. QUERY_SHALLOW, // Depth
  4974. wcsTestPath, // Scope
  4975. pCmdTree, // DBCOMMANDTREE
  4976. IID_IRowset); // IID of i/f to return
  4977. //
  4978. // Verify columns
  4979. //
  4980. CheckColumns( pRowset, cols, TRUE );
  4981. if ( !WaitForCompletion( pRowset, TRUE ) )
  4982. {
  4983. LogError( "Content query unsuccessful.\n" );
  4984. pRowset->Release();
  4985. Fail();
  4986. }
  4987. //
  4988. // Get data
  4989. //
  4990. sc = pRowset->GetNextRows(0, 0, 10, &cRowsReturned, &pgrhRows);
  4991. if ( FAILED( sc ) )
  4992. {
  4993. LogError( "IRowset->GetNextRows returned 0x%x\n", sc );
  4994. pRowset->Release();
  4995. Fail();
  4996. }
  4997. //
  4998. // Check to see if the CI is up-to-date
  4999. //
  5000. IRowsetQueryStatus * pRowsetQueryStatus = 0;
  5001. SCODE scTemp = pRowset->QueryInterface(IID_IRowsetQueryStatus,
  5002. (void **) &pRowsetQueryStatus);
  5003. if ( FAILED( scTemp ) && scTemp != E_NOINTERFACE )
  5004. {
  5005. LogError( "IRowset::QI IRowsetQueryStatus failed, 0x%x\n", sc );
  5006. cFailures++;
  5007. }
  5008. DWORD dwStatus = 0;
  5009. if (pRowsetQueryStatus != 0)
  5010. {
  5011. scTemp = pRowsetQueryStatus->GetStatus( &dwStatus );
  5012. pRowsetQueryStatus->Release();
  5013. if ( QUERY_RELIABILITY_STATUS(dwStatus) & STAT_CONTENT_OUT_OF_DATE )
  5014. {
  5015. FreeHrowsArray( pRowset, cRowsReturned, &pgrhRows );
  5016. pRowset->Release();
  5017. cRetries++;
  5018. if (cRetries < MAX_CI_RETRIES)
  5019. {
  5020. Sleep( CI_SLEEP_TICKS );
  5021. continue;
  5022. }
  5023. }
  5024. break;
  5025. }
  5026. else if (fFirstTime && cRowsReturned < cExpectedHits)
  5027. {
  5028. FreeHrowsArray( pRowset, cRowsReturned, &pgrhRows );
  5029. pRowset->Release();
  5030. cRetries++;
  5031. if (cRetries < MAX_CI_RETRIES)
  5032. Sleep( CI_SLEEP_TICKS );
  5033. }
  5034. else
  5035. {
  5036. break;
  5037. }
  5038. } while ( cRetries < MAX_CI_RETRIES );
  5039. if (cRetries >= MAX_CI_RETRIES)
  5040. {
  5041. LogError( "Content query test skipped due to timeout\n" );
  5042. return FALSE;
  5043. }
  5044. fFirstTime = FALSE;
  5045. if ( 0 == cExpectedHits )
  5046. {
  5047. pRowset->Release();
  5048. if ( cRowsReturned > 0 )
  5049. LogFail("DoContentQuery, %d returned rows, expected none\n",
  5050. cRowsReturned);
  5051. else
  5052. return TRUE;
  5053. }
  5054. if (sc != DB_S_ENDOFROWSET && cRowsReturned != 10)
  5055. {
  5056. LogError( "IRowset->GetNextRows returned %d of %d rows,"
  5057. " status (%x) != DB_S_ENDOFROWSET\n",
  5058. cRowsReturned, 10,
  5059. sc);
  5060. pRowset->Release();
  5061. #if defined(UNIT_TEST)
  5062. cFailures++;
  5063. return TRUE;
  5064. #else
  5065. Fail();
  5066. #endif
  5067. }
  5068. //
  5069. // Expect 1 to 5 hits
  5070. //
  5071. if (sc != DB_S_ENDOFROWSET || cRowsReturned != cExpectedHits)
  5072. {
  5073. LogError( "IRowset->GetNextRows returned %d rows (expected %d),"
  5074. " status (%x)\n",
  5075. cRowsReturned, cExpectedHits, sc );
  5076. pRowset->Release();
  5077. #if defined(UNIT_TEST)
  5078. cFailures++;
  5079. return TRUE;
  5080. #else
  5081. Fail();
  5082. #endif
  5083. }
  5084. FreeHrowsArray( pRowset, cRowsReturned, &pgrhRows );
  5085. //
  5086. // Clean up.
  5087. //
  5088. pRowset->Release();
  5089. return TRUE;
  5090. } //DoContentQuery
  5091. //+-------------------------------------------------------------------------
  5092. //
  5093. // Function: ContentTest, public
  5094. //
  5095. // Synopsis: Very minimal test of Content query
  5096. //
  5097. // History: 13-May-93 KyleP Created
  5098. // 15 Oct 94 Alanw Converted to OLE-DB query
  5099. //
  5100. //--------------------------------------------------------------------------
  5101. void ContentTest()
  5102. {
  5103. LogProgress( "Content Query\n" );
  5104. WCHAR *pwszScope = wcsTestPath;
  5105. DWORD dwDepth = QUERY_SHALLOW;
  5106. ICommand * pQuery = 0;
  5107. SCODE scIC = CICreateCommand( (IUnknown **)&pQuery,
  5108. 0,
  5109. IID_ICommand,
  5110. CONTENT_CATALOG,
  5111. TEST_MACHINE );
  5112. if ( FAILED( scIC ) )
  5113. LogFail( "RunPropTest - error 0x%x Unable to create ICommand\n", scIC );
  5114. if ( 0 == pQuery )
  5115. LogFail( "RunPropTest - CICreateCommand succeeded, but returned null pQuery\n" );
  5116. scIC = SetScopeProperties( pQuery,
  5117. 1,
  5118. &pwszScope,
  5119. &dwDepth );
  5120. // simple content query
  5121. {
  5122. LogProgress( " Content Query test 0\n" );
  5123. CDbContentRestriction CiRst( L"country", psContents);
  5124. if (! DoContentQuery( pQuery, CiRst, 2 ))
  5125. {
  5126. pQuery->Release();
  5127. return;
  5128. }
  5129. }
  5130. // content query on property
  5131. {
  5132. LogProgress( " Content Query test 1\n" );
  5133. CDbContentRestriction CiRst( L"alanw", psAuthor);
  5134. DoContentQuery( pQuery, CiRst, 2 );
  5135. }
  5136. // natural language query
  5137. {
  5138. LogProgress( " Content Query test 2\n" );
  5139. CDbNatLangRestriction CiRst( L"who is oscar wilde", psContents);
  5140. DoContentQuery( pQuery, CiRst, 1 );
  5141. }
  5142. // content query with prefix match
  5143. {
  5144. LogProgress( " Content Query test 3\n" );
  5145. CDbContentRestriction CiRst( L"cont", psContents, GENERATE_METHOD_PREFIX );
  5146. DoContentQuery( pQuery, CiRst, 1 );
  5147. }
  5148. // content query with stemming
  5149. {
  5150. LogProgress( " Content Query test 4\n" );
  5151. CDbContentRestriction CiRst( L"temptation", psContents, GENERATE_METHOD_INFLECT );
  5152. DoContentQuery( pQuery, CiRst, 1 );
  5153. }
  5154. // content query with more obscure stemming (prefix match)
  5155. {
  5156. LogProgress( " Content Query test 4A\n" );
  5157. CDbContentRestriction CiRst( L"crea", psContents, GENERATE_METHOD_PREFIX );
  5158. DoContentQuery( pQuery, CiRst, 1 );
  5159. }
  5160. // content query with more obscure stemming (stemmed)
  5161. {
  5162. LogProgress( " Content Query test 4B\n" );
  5163. CDbContentRestriction CiRst( L"crea", psContents, GENERATE_METHOD_INFLECT );
  5164. DoContentQuery( pQuery, CiRst, 0 );
  5165. }
  5166. // content query with more obscure stemming (prefix match)
  5167. {
  5168. LogProgress( " Content Query test 4C\n" );
  5169. CDbContentRestriction CiRst( L"create", psContents, GENERATE_METHOD_PREFIX );
  5170. DoContentQuery( pQuery, CiRst, 1 );
  5171. }
  5172. // content query with more obscure stemming (stemmed)
  5173. {
  5174. LogProgress( " Content Query test 4D\n" );
  5175. CDbContentRestriction CiRst( L"create", psContents, GENERATE_METHOD_INFLECT );
  5176. DoContentQuery( pQuery, CiRst, 1 );
  5177. }
  5178. // and content query
  5179. {
  5180. LogProgress( " Content Query test 5\n" );
  5181. CDbBooleanNodeRestriction CiRst( DBOP_and );
  5182. CDbContentRestriction *pRst1 = new
  5183. CDbContentRestriction( L"country", psContents);
  5184. CDbContentRestriction *pRst2 = new
  5185. CDbContentRestriction( L"content", psContents);
  5186. CiRst.AppendChild(pRst1);
  5187. CiRst.AppendChild(pRst2);
  5188. DoContentQuery( pQuery, CiRst, 1 );
  5189. }
  5190. // and not content query
  5191. {
  5192. LogProgress( " Content Query test 6\n" );
  5193. CDbBooleanNodeRestriction CiRst( DBOP_and );
  5194. CDbContentRestriction *pRst1 = new
  5195. CDbContentRestriction( L"country", psContents);
  5196. CDbContentRestriction *pRst2 = new
  5197. CDbContentRestriction( L"content", psContents);
  5198. CDbNotRestriction *pRst3 = new CDbNotRestriction( pRst2 );
  5199. CiRst.AppendChild(pRst1);
  5200. CiRst.AppendChild(pRst3);
  5201. DoContentQuery( pQuery, CiRst, 1 );
  5202. }
  5203. // proximity content query
  5204. {
  5205. LogProgress( " Content Query test 7\n" );
  5206. CDbProximityNodeRestriction CiRst;
  5207. CDbContentRestriction *pRst1 = new
  5208. CDbContentRestriction( L"country", psContents);
  5209. CDbContentRestriction *pRst2 = new
  5210. CDbContentRestriction( L"temptations", psContents);
  5211. CiRst.AppendChild(pRst1);
  5212. CiRst.AppendChild(pRst2);
  5213. DoContentQuery( pQuery, CiRst, 1 );
  5214. }
  5215. // vector or query
  5216. {
  5217. LogProgress( " Content Query test 8\n" );
  5218. CDbVectorRestriction CiRst( VECTOR_RANK_MIN );
  5219. CDbContentRestriction *pRst1 = new
  5220. CDbContentRestriction( L"country", psContents);
  5221. CDbContentRestriction *pRst2 = new
  5222. CDbContentRestriction( L"temptations", psContents);
  5223. CDbContentRestriction *pRst3 = new
  5224. CDbContentRestriction( L"DELETE", psContents);
  5225. pRst1->SetWeight( 500 );
  5226. pRst2->SetWeight( 1000 );
  5227. pRst3->SetWeight( 50 );
  5228. CiRst.AppendChild( pRst1 );
  5229. CiRst.AppendChild( pRst2 );
  5230. CiRst.AppendChild( pRst3 );
  5231. // This might return 3 if the test directory is on FAT
  5232. const unsigned cMatches = 2;
  5233. DoContentQuery( pQuery, CiRst, cMatches );
  5234. }
  5235. pQuery->Release();
  5236. } //ContentTest
  5237. #endif // DO_CONTENT_TESTS
  5238. #if defined( DO_NOTIFICATION )
  5239. class CTestRowsetNotify : public IRowsetNotify
  5240. {
  5241. public:
  5242. CTestRowsetNotify() :
  5243. _fChecking(FALSE),
  5244. _cRef(1),
  5245. _dwReasonToCheck(0),
  5246. _cNotifies(0) {}
  5247. ~CTestRowsetNotify()
  5248. {
  5249. }
  5250. void StartCheck(DWORD dwReason)
  5251. {
  5252. _fChecking = TRUE;
  5253. _dwReasonToCheck = dwReason;
  5254. _cNotifies = 0;
  5255. }
  5256. void TestCheck( ULONG cNotifies )
  5257. {
  5258. if (_cNotifies != cNotifies )
  5259. LogError ( "CTestRowsetNotify::TestCheck failed, "
  5260. "reason %d, exp %d got %d\n",
  5261. _dwReasonToCheck, cNotifies, _cNotifies );
  5262. _fChecking = FALSE;
  5263. }
  5264. //
  5265. // IUnknown methods.
  5266. //
  5267. STDMETHOD(QueryInterface) (THIS_ REFIID riid,LPVOID *ppiuk)
  5268. {
  5269. *ppiuk = (void **) this; // hold our breath and jump
  5270. AddRef();
  5271. return S_OK;
  5272. }
  5273. STDMETHOD_(ULONG, AddRef) (THIS)
  5274. { return ++_cRef; }
  5275. STDMETHOD_(ULONG, Release) (THIS)
  5276. { return --_cRef; }
  5277. //
  5278. // IRowsetNotify methods.
  5279. //
  5280. STDMETHOD(OnFieldChange) ( IRowset * pRowset,
  5281. HROW hRow,
  5282. DBORDINAL cColumns,
  5283. DBORDINAL rgColumns[],
  5284. DBREASON eReason,
  5285. DBEVENTPHASE ePhase,
  5286. BOOL fCantDeny )
  5287. {
  5288. if ( _fChecking && eReason == _dwReasonToCheck )
  5289. {
  5290. _cNotifies++;
  5291. }
  5292. return S_OK;
  5293. }
  5294. STDMETHOD(OnRowChange) ( IRowset * pRowset,
  5295. DBCOUNTITEM cRows,
  5296. const HROW rghRows[],
  5297. DBREASON eReason,
  5298. DBEVENTPHASE ePhase,
  5299. BOOL fCantDeny )
  5300. {
  5301. if ( _fChecking && eReason == _dwReasonToCheck )
  5302. {
  5303. _cNotifies++;
  5304. }
  5305. return S_OK;
  5306. }
  5307. STDMETHOD(OnRowsetChange) ( IRowset * pRowset,
  5308. DBREASON eReason,
  5309. DBEVENTPHASE ePhase,
  5310. BOOL fCantDeny )
  5311. {
  5312. if ( _fChecking && eReason == _dwReasonToCheck )
  5313. {
  5314. _cNotifies++;
  5315. }
  5316. return S_OK;
  5317. }
  5318. private:
  5319. ULONG _cRef;
  5320. BOOL _fChecking;
  5321. DWORD _dwReasonToCheck;
  5322. ULONG _cNotifies;
  5323. };
  5324. class CTestWatchNotify : public IRowsetWatchNotify
  5325. {
  5326. public:
  5327. CTestWatchNotify() :
  5328. _fChecking(FALSE),
  5329. _fRequery(FALSE),
  5330. _fComplete(FALSE),
  5331. _cRowChanges(0),
  5332. _cRef(1) {}
  5333. void DoChecking(BOOL fChecking)
  5334. {
  5335. _fChecking = fChecking;
  5336. }
  5337. ~CTestWatchNotify()
  5338. {
  5339. if (_fChecking)
  5340. {
  5341. if (1 != _cRef) // NOTE: notify objects are static allocated
  5342. {
  5343. LogFail( "Bad refcount on CTestWatchNotify: %#x, %d.\n",
  5344. this, _cRef );
  5345. }
  5346. }
  5347. }
  5348. //
  5349. // IUnknown methods.
  5350. //
  5351. STDMETHOD(QueryInterface) (THIS_ REFIID riid,LPVOID *ppiuk)
  5352. {
  5353. *ppiuk = (void **) this; // hold our breath and jump
  5354. AddRef();
  5355. return S_OK;
  5356. }
  5357. STDMETHOD_(ULONG, AddRef) (THIS)
  5358. { /*printf( "addref: %d\n", _cRef+1 );*/ return ++_cRef; }
  5359. STDMETHOD_(ULONG, Release) (THIS)
  5360. { /*printf( "release: %d\n", _cRef-1 );*/ return --_cRef; }
  5361. //void DumpRef() { printf( "ref: %d\n", _cRef ); }
  5362. //
  5363. // IRowsetNotifyWatch method
  5364. //
  5365. STDMETHOD(OnChange) (THIS_ IRowset* pRowset, DBWATCHNOTIFY changeType)
  5366. {
  5367. switch (changeType)
  5368. {
  5369. case DBWATCHNOTIFY_ROWSCHANGED:
  5370. _cRowChanges++; break;
  5371. case DBWATCHNOTIFY_QUERYDONE:
  5372. _fComplete = TRUE; break;
  5373. case DBWATCHNOTIFY_QUERYREEXECUTED:
  5374. _fRequery = TRUE; break;
  5375. default:
  5376. _BadChangeType = changeType;
  5377. }
  5378. return S_OK;
  5379. }
  5380. private:
  5381. ULONG _cRef;
  5382. BOOL _fChecking;
  5383. BOOL _fComplete;
  5384. BOOL _fRequery;
  5385. ULONG _cRowChanges;
  5386. DBWATCHNOTIFY _BadChangeType;
  5387. };
  5388. //+-------------------------------------------------------------------------
  5389. //
  5390. // Function: NotificationTest, public
  5391. //
  5392. // Synopsis: Test basic notification functionality
  5393. //
  5394. // Returns: Nothing
  5395. //
  5396. // Notes: At the point this is called, the notification has been
  5397. // set up. This function adds/deletes/modifies files and
  5398. // expects to get notifications of these changes.
  5399. //
  5400. // History: 14 Oct 94 dlee created
  5401. //
  5402. //--------------------------------------------------------------------------
  5403. void NotificationTest()
  5404. {
  5405. LogProgress( " Notification test\n" );
  5406. //
  5407. // Makes files in the nt\system32 directory that look like "X.zzz"
  5408. //
  5409. WCHAR wcsSysDir[MAX_PATH];
  5410. if( !GetSystemDirectory( wcsSysDir, sizeof(wcsSysDir) / sizeof(WCHAR) ) )
  5411. {
  5412. LogFail( "Unable to determine system directory.\n" );
  5413. }
  5414. wcscat(wcsSysDir,L"\\X.zzz");
  5415. unsigned iNamePos = wcslen(wcsSysDir) - 5;
  5416. DWORD dwStart = GetTickCount();
  5417. //
  5418. // create / touch / delete files for 5 seconds
  5419. //
  5420. while ((GetTickCount() - dwStart) < 3000)
  5421. {
  5422. Sleep(rand() % 300);
  5423. wcsSysDir[iNamePos] = (WCHAR) ('a' + (rand() % 10));
  5424. HANDLE h = CreateFile(wcsSysDir,
  5425. GENERIC_READ | GENERIC_WRITE,
  5426. FILE_SHARE_READ,
  5427. 0,
  5428. OPEN_ALWAYS,
  5429. FILE_ATTRIBUTE_NORMAL |
  5430. (((rand() % 103) < 20) ? FILE_FLAG_DELETE_ON_CLOSE : 0),
  5431. 0);
  5432. if (INVALID_HANDLE_VALUE != h)
  5433. {
  5434. DWORD dw = 0xf0f0f0f0;
  5435. DWORD dwWritten;
  5436. WriteFile(h,&dw,sizeof(DWORD),&dwWritten,0);
  5437. CloseHandle(h);
  5438. }
  5439. else
  5440. {
  5441. LogFail( "Can't create test file in the system32 directory.\n" );
  5442. }
  5443. }
  5444. //
  5445. // sleep some more to pick up all the notifications
  5446. //
  5447. Sleep(1000);
  5448. } //NotificationTest
  5449. #endif // defined( DO_NOTIFICATION )
  5450. //+-------------------------------------------------------------------------
  5451. //
  5452. // Function: CheckColumns, public
  5453. //
  5454. // Synopsis: Verify that the cursor contains all the requested columns
  5455. // Also, check to see if the IColumnsInfo and IColumnsRowset
  5456. // interfaces are supported. Print out column info. and rowset
  5457. // properties if the very verbose option is chosen.
  5458. //
  5459. // Arguments: [pRowset] - a pointer to an IRowset* to be tested.
  5460. // [rColumns] - a reference to a CDbColumns giving the input
  5461. // columns
  5462. //
  5463. // Returns: Nothing
  5464. //
  5465. // Notes: This function may be called prior to the rowset population
  5466. // having completed.
  5467. //
  5468. // History: 14 Nov 94 Alanw Created
  5469. //
  5470. //--------------------------------------------------------------------------
  5471. char *DBTYPE_Tag (DBTYPE type)
  5472. {
  5473. #define CASE(name) \
  5474. case DBTYPE_ ## name: \
  5475. return #name
  5476. switch (type)
  5477. {
  5478. CASE (NULL);
  5479. CASE (BOOL);
  5480. CASE (I1);
  5481. CASE (UI1);
  5482. CASE (I2);
  5483. CASE (I4);
  5484. CASE (UI2);
  5485. CASE (UI4);
  5486. CASE (I8);
  5487. CASE (UI8);
  5488. CASE (R4);
  5489. CASE (R8);
  5490. CASE (CY);
  5491. CASE (DATE);
  5492. CASE (VARIANT);
  5493. CASE (GUID);
  5494. CASE (STR);
  5495. CASE (BYTES);
  5496. CASE (WSTR);
  5497. CASE (NUMERIC);
  5498. default:
  5499. return "BAD";
  5500. }
  5501. #undef CASE
  5502. }
  5503. void PrintColumnFlags (DBCOLUMNFLAGS flags)
  5504. {
  5505. #define FLAG(name) \
  5506. if (flags & DBCOLUMNFLAGS_ ## name) \
  5507. printf (#name " ")
  5508. FLAG (ISBOOKMARK);
  5509. FLAG (MAYDEFER);
  5510. // FLAG (MAYREFERENCE);
  5511. FLAG (WRITE);
  5512. FLAG (WRITEUNKNOWN);
  5513. // FLAG (ISSIGNED);
  5514. FLAG (ISFIXEDLENGTH);
  5515. FLAG (ISNULLABLE);
  5516. FLAG (MAYBENULL);
  5517. FLAG (ISCHAPTER);
  5518. FLAG (ISLONG);
  5519. FLAG (ISROWID);
  5520. FLAG (ISROWVER);
  5521. FLAG (CACHEDEFERRED);
  5522. #undef FLAG
  5523. }
  5524. DBPROP * LocateProperty (
  5525. REFIID rPropSet,
  5526. DWORD dwPropId,
  5527. ULONG cPropSets,
  5528. DBPROPSET * pPropSets)
  5529. {
  5530. for (unsigned i=0; i<cPropSets; i++, pPropSets++)
  5531. {
  5532. if (pPropSets->guidPropertySet != rPropSet)
  5533. continue;
  5534. for (unsigned j=0; j<pPropSets->cProperties; j++)
  5535. {
  5536. if (pPropSets->rgProperties[j].dwPropertyID == dwPropId)
  5537. return &pPropSets->rgProperties[j];
  5538. }
  5539. return 0;
  5540. }
  5541. return 0;
  5542. }
  5543. DBPROPINFO UNALIGNED * LocatePropertyInfo (
  5544. REFIID rPropSet,
  5545. DWORD dwPropId,
  5546. ULONG cPropInfoSets,
  5547. DBPROPINFOSET * pPropInfoSets)
  5548. {
  5549. for (unsigned i=0; i<cPropInfoSets; i++, pPropInfoSets++)
  5550. {
  5551. if (pPropInfoSets->guidPropertySet != rPropSet)
  5552. continue;
  5553. for (unsigned j=0; j<pPropInfoSets->cPropertyInfos; j++)
  5554. {
  5555. if (pPropInfoSets->rgPropertyInfos[j].dwPropertyID == dwPropId)
  5556. return &pPropInfoSets->rgPropertyInfos[j];
  5557. }
  5558. return 0;
  5559. }
  5560. return 0;
  5561. }
  5562. BOOL CheckBooleanProperty (
  5563. REFIID rPropSet,
  5564. DWORD dwPropId,
  5565. ULONG cProps,
  5566. DBPROPSET * pProps)
  5567. {
  5568. DBPROP * pPropDesc = LocateProperty( rPropSet, dwPropId, cProps, pProps );
  5569. if (pPropDesc)
  5570. {
  5571. if ( !( (pPropDesc->vValue.vt == VT_EMPTY &&
  5572. pPropDesc->dwStatus == DBPROPSTATUS_NOTSUPPORTED) ||
  5573. (pPropDesc->vValue.vt == VT_BOOL &&
  5574. (pPropDesc->vValue.boolVal == VARIANT_TRUE ||
  5575. pPropDesc->vValue.boolVal == VARIANT_FALSE)) ) )
  5576. {
  5577. LogError( "Bad boolean property value %d, %d\n",
  5578. pPropDesc->vValue.vt, pPropDesc->vValue.lVal );
  5579. }
  5580. return (pPropDesc->vValue.vt == VT_BOOL &&
  5581. pPropDesc->vValue.boolVal == VARIANT_TRUE);
  5582. }
  5583. return FALSE;
  5584. }
  5585. BOOL CheckNumericProperty (
  5586. REFIID rPropSet,
  5587. DWORD dwPropId,
  5588. ULONG cProps,
  5589. DBPROPSET * pProps,
  5590. LONG & rlVal)
  5591. {
  5592. DBPROP * pPropDesc = LocateProperty( rPropSet, dwPropId, cProps, pProps );
  5593. if (pPropDesc)
  5594. {
  5595. if ( !( (pPropDesc->vValue.vt == VT_EMPTY &&
  5596. pPropDesc->dwStatus == DBPROPSTATUS_NOTSUPPORTED) ||
  5597. (pPropDesc->vValue.vt == VT_I4) ) )
  5598. {
  5599. LogError( "Bad numeric property value %d\n", pPropDesc->vValue.vt );
  5600. return FALSE;
  5601. }
  5602. rlVal = pPropDesc->vValue.lVal;
  5603. return (pPropDesc->vValue.vt == VT_I4);
  5604. }
  5605. return FALSE;
  5606. }
  5607. void CheckSafeArrayProperty (
  5608. REFIID rPropSet,
  5609. DWORD dwPropId,
  5610. ULONG cProps,
  5611. DBPROPSET * pProps )
  5612. {
  5613. DBPROP * pPropDesc = LocateProperty( rPropSet, dwPropId, cProps, pProps );
  5614. if (pPropDesc)
  5615. {
  5616. if ( pPropDesc->vValue.vt == (VT_ARRAY | VT_BSTR ) )
  5617. {
  5618. if ( 1 != SafeArrayGetDim( pPropDesc->vValue.parray ) )
  5619. printf( "Bad array dimension\n" );
  5620. else
  5621. {
  5622. long LBound = 1;
  5623. long UBound = 0;
  5624. SafeArrayGetLBound( pPropDesc->vValue.parray, 1, &LBound );
  5625. SafeArrayGetUBound( pPropDesc->vValue.parray, 1, &UBound );
  5626. for ( long j = LBound; j <= UBound; j++ )
  5627. {
  5628. WCHAR ** pwcsVal;
  5629. SCODE sc = SafeArrayPtrOfIndex( pPropDesc->vValue.parray, &j, (void **)&pwcsVal );
  5630. if ( SUCCEEDED(sc) )
  5631. {
  5632. if ( j != LBound )
  5633. printf( ", " );
  5634. printf( "%ws", *pwcsVal );
  5635. }
  5636. }
  5637. }
  5638. }
  5639. else if ( pPropDesc->vValue.vt == VT_BSTR )
  5640. {
  5641. printf( "%ws", pPropDesc->vValue.bstrVal );
  5642. }
  5643. else if ( pPropDesc->vValue.vt == (VT_ARRAY | VT_I4 ) )
  5644. {
  5645. if ( 1 != SafeArrayGetDim( pPropDesc->vValue.parray ) )
  5646. printf( "Bad array dimension\n" );
  5647. else
  5648. {
  5649. long LBound = 1;
  5650. long UBound = 0;
  5651. SafeArrayGetLBound( pPropDesc->vValue.parray, 1, &LBound );
  5652. SafeArrayGetUBound( pPropDesc->vValue.parray, 1, &UBound );
  5653. for ( long j = LBound; j <= UBound; j++ )
  5654. {
  5655. ULONG ulVal;
  5656. SCODE sc = SafeArrayGetElement( pPropDesc->vValue.parray, &j, &ulVal );
  5657. if ( SUCCEEDED(sc) )
  5658. {
  5659. if ( j != LBound )
  5660. printf( ", " );
  5661. printf( "%u", ulVal );
  5662. }
  5663. }
  5664. }
  5665. }
  5666. else if ( pPropDesc->vValue.vt == VT_I4 )
  5667. {
  5668. printf( "%u", pPropDesc->vValue.lVal );
  5669. }
  5670. else
  5671. printf( "Unknown VT type %d\n", pPropDesc->vValue.vt );
  5672. }
  5673. else
  5674. printf( "n/a" );
  5675. }
  5676. //
  5677. // GetBooleanProperty - return boolean property value setting for dbprop
  5678. //
  5679. BOOL GetBooleanProperty ( IRowset * pRowset, DBPROPID dbprop )
  5680. {
  5681. DBPROPSET *pPropInfo = 0;
  5682. ULONG cPropSets = 0;
  5683. DBPROPIDSET PropIdSet;
  5684. DBPROPID PropID = dbprop;
  5685. PropIdSet.rgPropertyIDs = &PropID;
  5686. PropIdSet.cPropertyIDs = 1;
  5687. PropIdSet.guidPropertySet = DBPROPSET_ROWSET;
  5688. IRowsetInfo *pIRowInfo = 0;
  5689. SCODE sc = pRowset->QueryInterface(IID_IRowsetInfo,(void **) &pIRowInfo);
  5690. sc = pIRowInfo->GetProperties( 1, &PropIdSet, &cPropSets, &pPropInfo );
  5691. pIRowInfo->Release();
  5692. BOOL fReturnValue = FALSE;
  5693. if ( FAILED( sc ) || cPropSets != 1 || pPropInfo->cProperties != 1 )
  5694. {
  5695. LogFail( "IRowsetInfo::GetProperties returned sc=0x%lx, cPropSets=%d\n", sc, cPropSets );
  5696. }
  5697. else
  5698. {
  5699. if (pPropInfo->rgProperties->vValue.vt == VT_BOOL &&
  5700. pPropInfo->rgProperties->dwStatus == DBPROPSTATUS_OK)
  5701. {
  5702. fReturnValue = (pPropInfo->rgProperties->vValue.boolVal == VARIANT_TRUE);
  5703. }
  5704. else
  5705. {
  5706. LogFail( "IRowsetInfo::GetProperties returned bad DBPROPSET,"
  5707. " vt = %d status = %x\n",
  5708. pPropInfo->rgProperties->vValue.vt, pPropInfo->rgProperties->dwStatus );
  5709. }
  5710. if (pPropInfo)
  5711. {
  5712. if (pPropInfo->rgProperties)
  5713. CoTaskMemFree(pPropInfo->rgProperties);
  5714. CoTaskMemFree(pPropInfo);
  5715. }
  5716. }
  5717. return fReturnValue;
  5718. }
  5719. void PrintRowsetProps (ULONG cProps, DBPROPSET * pProps)
  5720. {
  5721. printf("\nRowset Properties:" );
  5722. unsigned cBoolProps = 0;
  5723. #define BOOLPROP(name) \
  5724. if (CheckBooleanProperty( DBPROPSET_ROWSET, DBPROP_ ## name, cProps, pProps) ) \
  5725. { if ((cBoolProps % 4) == 0) printf("\n\t"); \
  5726. cBoolProps++; \
  5727. printf (#name " "); \
  5728. }
  5729. BOOLPROP (ABORTPRESERVE);
  5730. BOOLPROP (APPENDONLY);
  5731. BOOLPROP (BLOCKINGSTORAGEOBJECTS);
  5732. BOOLPROP (BOOKMARKS);
  5733. BOOLPROP (BOOKMARKSKIPPED);
  5734. BOOLPROP (CACHEDEFERRED);
  5735. BOOLPROP (CANFETCHBACKWARDS);
  5736. BOOLPROP (CANHOLDROWS);
  5737. BOOLPROP (CANSCROLLBACKWARDS);
  5738. BOOLPROP (CHANGEINSERTEDROWS);
  5739. #ifdef DBPROP_CHAPTERED
  5740. BOOLPROP (CHAPTERED);
  5741. #endif // DBPROP_CHAPTERED
  5742. BOOLPROP (COLUMNRESTRICT);
  5743. BOOLPROP (COMMITPRESERVE);
  5744. BOOLPROP (DEFERRED);
  5745. BOOLPROP (DELAYSTORAGEOBJECTS);
  5746. BOOLPROP (IMMOBILEROWS);
  5747. BOOLPROP (LITERALBOOKMARKS);
  5748. BOOLPROP (LITERALIDENTITY);
  5749. #ifdef DBPROP_MULTICHAPTERED
  5750. BOOLPROP (MULTICHAPTERED);
  5751. #endif // DBPROP_MULTICHAPTERED
  5752. BOOLPROP (MAYWRITECOLUMN);
  5753. BOOLPROP (ORDEREDBOOKMARKS);
  5754. BOOLPROP (OTHERINSERT);
  5755. BOOLPROP (OTHERUPDATEDELETE);
  5756. BOOLPROP (OWNINSERT);
  5757. BOOLPROP (OWNUPDATEDELETE);
  5758. BOOLPROP (QUICKRESTART);
  5759. BOOLPROP (REENTRANTEVENTS);
  5760. BOOLPROP (REMOVEDELETED);
  5761. BOOLPROP (REPORTMULTIPLECHANGES);
  5762. BOOLPROP (RETURNPENDINGINSERTS);
  5763. BOOLPROP (ROWRESTRICT);
  5764. BOOLPROP (SERVERCURSOR);
  5765. BOOLPROP (STRONGIDENTITY);
  5766. BOOLPROP (TRANSACTEDOBJECT);
  5767. cBoolProps = 0;
  5768. BOOLPROP (IAccessor);
  5769. BOOLPROP (IChapteredRowset);
  5770. BOOLPROP (IColumnsInfo);
  5771. BOOLPROP (IColumnsRowset);
  5772. BOOLPROP (IConnectionPointContainer);
  5773. BOOLPROP (IDBAsynchStatus);
  5774. BOOLPROP (IRowset);
  5775. BOOLPROP (IRowsetChange);
  5776. BOOLPROP (IRowsetIdentity);
  5777. BOOLPROP (IRowsetInfo);
  5778. BOOLPROP (IRowsetLocate);
  5779. BOOLPROP (IRowsetResynch);
  5780. BOOLPROP (IRowsetScroll);
  5781. BOOLPROP (IRowsetUpdate);
  5782. BOOLPROP (ISupportErrorInfo);
  5783. BOOLPROP (IRowsetAsynch);
  5784. BOOLPROP (IRowsetWatchAll);
  5785. BOOLPROP (IRowsetWatchRegion);
  5786. // The following are per-column
  5787. // BOOLPROP (ILockBytes);
  5788. // BOOLPROP (ISequentialStream);
  5789. // BOOLPROP (IStorage);
  5790. // BOOLPROP (IStream);
  5791. #undef BOOLPROP
  5792. printf("\n");
  5793. LONG n;
  5794. #define NUMPROP(name) \
  5795. if (CheckNumericProperty( DBPROPSET_ROWSET, DBPROP_ ## name, cProps, pProps, n) ) \
  5796. printf ("\t" #name ":\t%d\n", n); \
  5797. else \
  5798. printf ("\t" #name ":\t--\n");
  5799. NUMPROP( BOOKMARKTYPE );
  5800. NUMPROP( COMMANDTIMEOUT );
  5801. NUMPROP( MAXOPENROWS );
  5802. #ifdef DBPROP_MAXOPENROWSPERCHAPTER
  5803. NUMPROP( MAXOPENROWSPERCHAPTER );
  5804. #endif // DBPROP_MAXOPENROWSPERCHAPTER
  5805. NUMPROP( MAXPENDINGROWS );
  5806. NUMPROP( MAXROWS );
  5807. #ifdef DBPROP_MAXPENDINGCHANGESCHAPTER
  5808. NUMPROP( MAXPENDINGCHANGESPERCHAPTER );
  5809. #endif // DBPROP_MAXPENDINGCHANGESCHAPTER
  5810. NUMPROP( MEMORYUSAGE );
  5811. NUMPROP( NOTIFICATIONGRANULARITY );
  5812. NUMPROP( NOTIFICATIONPHASES );
  5813. NUMPROP( NOTIFYROWSETRELEASE );
  5814. NUMPROP( NOTIFYROWSETFETCHPOSITIONCHANGE );
  5815. // NUMPROP( NOTIFYCOLUMNSET, et al. );
  5816. NUMPROP( ROWSET_ASYNCH );
  5817. NUMPROP( ROWTHREADMODEL );
  5818. NUMPROP( UPDATABILITY );
  5819. #undef NUMPROP
  5820. #define BOOLPROP(name) \
  5821. if (CheckBooleanProperty( guidQueryExt, DBPROP_ ## name, cProps, pProps) ) \
  5822. { if ((cBoolProps % 4) == 0) printf("\n\t"); \
  5823. cBoolProps++; \
  5824. printf (#name " "); \
  5825. }
  5826. cBoolProps = 0;
  5827. BOOLPROP (USECONTENTINDEX);
  5828. BOOLPROP (DEFERNONINDEXEDTRIMMING);
  5829. BOOLPROP (USEEXTENDEDDBTYPES);
  5830. #undef BOOLPROP
  5831. printf("\n\n");
  5832. #define SAPROP(name) \
  5833. printf ( "\t" #name ": "); \
  5834. CheckSafeArrayProperty( guidFsCiFrmwrkExt, DBPROP_ ## name, cProps, pProps); \
  5835. printf ( "\n" );
  5836. SAPROP (CI_INCLUDE_SCOPES);
  5837. SAPROP (CI_DEPTHS);
  5838. SAPROP (CI_CATALOG_NAME);
  5839. #undef SAPROP
  5840. #define SAPROP(name) \
  5841. printf ( "\t" #name ": "); \
  5842. CheckSafeArrayProperty( guidCiFrmwrkExt, DBPROP_ ## name, cProps, pProps); \
  5843. printf ( "\n" );
  5844. SAPROP (MACHINE);
  5845. #undef SAPROP
  5846. printf ( "\n" );
  5847. #define SAPROP(name) \
  5848. printf ( "\t" #name ": "); \
  5849. CheckSafeArrayProperty( guidMsidxsExt, MSIDXSPROP_ ## name, cProps, pProps); \
  5850. printf ( "\n" );
  5851. SAPROP (ROWSETQUERYSTATUS);
  5852. SAPROP (COMMAND_LOCALE_STRING);
  5853. SAPROP (QUERY_RESTRICTION);
  5854. #undef SAPROP
  5855. }
  5856. //
  5857. // CheckRowsetProperties - print rowset properties. If IServiceProperties is
  5858. // supported, check that the set of properties returned
  5859. // by GetPropertyInfo is the same.
  5860. //
  5861. void CheckRowsetProperties( ULONG cProps,
  5862. DBPROPSET * pProps,
  5863. IUnknown * pUnk,
  5864. BOOL fCheckAllProperties = TRUE )
  5865. {
  5866. IServiceProperties *pSvcProp = 0;
  5867. SCODE sc = pUnk->QueryInterface(IID_IServiceProperties,(void **) &pSvcProp);
  5868. DBPROPSTATUS ExpStatus = fCheckAllProperties ? DBPROPSTATUS_OK :
  5869. DBPROPSTATUS_CONFLICTING;
  5870. if (SUCCEEDED( sc ))
  5871. {
  5872. DBPROPINFOSET * pPropInfoSet = 0;
  5873. ULONG cPropInfoSet = 0;
  5874. WCHAR * pwszDescriptions = 0;
  5875. DBPROPIDSET PropID;
  5876. PropID.cPropertyIDs = 0;
  5877. PropID.rgPropertyIDs = 0;
  5878. PropID.guidPropertySet = DBPROPSET_ROWSETALL;
  5879. sc = pSvcProp->GetPropertyInfo( 1, &PropID,
  5880. &cPropInfoSet, &pPropInfoSet,
  5881. &pwszDescriptions );
  5882. pSvcProp->Release();
  5883. if ( FAILED( sc ) )
  5884. {
  5885. LogFail( "IServiceProperties::GetPropertyInfo returned 0x%lx\n",
  5886. sc );
  5887. }
  5888. //
  5889. // Check that all properties returned by GetProperties are in the
  5890. // propinfo structures.
  5891. //
  5892. for (unsigned iPropSet=0; iPropSet < cProps; iPropSet++)
  5893. {
  5894. DBPROP *pDbProp = pProps[iPropSet].rgProperties;
  5895. for (unsigned iProp=0; iProp<pProps[iPropSet].cProperties; iProp++)
  5896. {
  5897. DBPROPINFO UNALIGNED * pPropInfo = LocatePropertyInfo(
  5898. pProps[iPropSet].guidPropertySet,
  5899. pDbProp[iProp].dwPropertyID,
  5900. cPropInfoSet, pPropInfoSet );
  5901. if (0 == pPropInfo)
  5902. {
  5903. LogError("Property info record couldn't be found for property %ws %d\n",
  5904. FormatGuid(pProps[iPropSet].guidPropertySet),
  5905. pDbProp[iProp].dwPropertyID);
  5906. cFailures++;
  5907. continue;
  5908. }
  5909. if (pDbProp[iProp].dwStatus != ExpStatus)
  5910. {
  5911. LogError("Property status error (%d) for property %ws %d (%ws)\n",
  5912. pDbProp[iProp].dwStatus,
  5913. FormatGuid(pProps[iPropSet].guidPropertySet),
  5914. pDbProp[iProp].dwPropertyID,
  5915. pPropInfo->pwszDescription);
  5916. cFailures++;
  5917. }
  5918. if (pPropInfo->vtType != pDbProp[iProp].vValue.vt)
  5919. {
  5920. LogError("Property type mismatch (%d %d) for property %ws %d (%ws)\n",
  5921. pPropInfo->vtType, pDbProp[iProp].vValue.vt,
  5922. FormatGuid(pProps[iPropSet].guidPropertySet),
  5923. pDbProp[iProp].dwPropertyID,
  5924. pPropInfo->pwszDescription);
  5925. cFailures++;
  5926. }
  5927. }
  5928. }
  5929. if (fCheckAllProperties)
  5930. {
  5931. //
  5932. // Check that all properties returned by GetPropertyInfo are in the
  5933. // DBPROP structures.
  5934. //
  5935. for (iPropSet=0; iPropSet<cPropInfoSet; iPropSet++)
  5936. {
  5937. DBPROPINFO UNALIGNED *pPropInfo = pPropInfoSet[iPropSet].rgPropertyInfos;
  5938. for ( unsigned iProp=0;
  5939. iProp < pPropInfoSet[iPropSet].cPropertyInfos;
  5940. iProp++)
  5941. {
  5942. DBPROP * pDbProp = LocateProperty(
  5943. pPropInfoSet[iPropSet].guidPropertySet,
  5944. pPropInfo[iProp].dwPropertyID,
  5945. cProps, pProps );
  5946. if (0 == pDbProp)
  5947. {
  5948. LogError("Property record couldn't be found for property %ws %d\n",
  5949. FormatGuid(pPropInfoSet[iPropSet].guidPropertySet),
  5950. pPropInfo[iProp].dwPropertyID);
  5951. cFailures++;
  5952. }
  5953. }
  5954. }
  5955. }
  5956. //
  5957. // Free all the structures in the DBPROPINFOSET
  5958. //
  5959. for (iPropSet=0; iPropSet<cPropInfoSet; iPropSet++)
  5960. {
  5961. DBPROPINFO UNALIGNED *pPropInfo = pPropInfoSet[iPropSet].rgPropertyInfos;
  5962. for (unsigned iProp=0;
  5963. iProp<pPropInfoSet[iPropSet].cPropertyInfos;
  5964. iProp++)
  5965. {
  5966. VARIANT v;
  5967. RtlCopyMemory( &v, &pPropInfo[iProp].vValues, sizeof v );
  5968. VariantClear( &v );
  5969. }
  5970. CoTaskMemFree( pPropInfo );
  5971. }
  5972. CoTaskMemFree( pPropInfoSet );
  5973. CoTaskMemFree( pwszDescriptions );
  5974. }
  5975. else
  5976. {
  5977. //
  5978. // Check the status of all properties returned by GetProperties.
  5979. //
  5980. for (unsigned iPropSet=0; iPropSet < cProps; iPropSet++)
  5981. {
  5982. DBPROP *pDbProp = pProps[iPropSet].rgProperties;
  5983. for (unsigned iProp=0; iProp<pProps[iPropSet].cProperties; iProp++)
  5984. {
  5985. if (pDbProp[iProp].dwStatus != ExpStatus)
  5986. {
  5987. LogError("Property status error (%d) for property %ws %d\n",
  5988. pDbProp[iProp].dwStatus,
  5989. FormatGuid(pProps[iPropSet].guidPropertySet),
  5990. pDbProp[iProp].dwPropertyID );
  5991. cFailures++;
  5992. }
  5993. }
  5994. }
  5995. }
  5996. if (fVerbose > 1)
  5997. {
  5998. PrintRowsetProps (cProps, pProps);
  5999. printf ("\n");
  6000. }
  6001. for (unsigned i=0; i<cProps; i++)
  6002. {
  6003. CoTaskMemFree(pProps[i].rgProperties);
  6004. }
  6005. CoTaskMemFree(pProps);
  6006. }
  6007. void CheckPropertiesInError( ICommand* pCmd, BOOL fQuiet )
  6008. {
  6009. if (! fQuiet)
  6010. LogProgress( " Checking properties in error\n" );
  6011. DBPROPSET * pPropInfo = 0;
  6012. ULONG cPropsets = 0;
  6013. DBPROPIDSET PropIDSet;
  6014. PropIDSet.rgPropertyIDs = 0;
  6015. PropIDSet.cPropertyIDs = 0;
  6016. PropIDSet.guidPropertySet = DBPROPSET_PROPERTIESINERROR;
  6017. ICommandProperties *pCmdProp = 0;
  6018. SCODE sc = pCmd->QueryInterface(IID_ICommandProperties,(void **) &pCmdProp);
  6019. sc = pCmdProp->GetProperties( 1, &PropIDSet, &cPropsets, &pPropInfo );
  6020. pCmdProp->Release();
  6021. if ( FAILED( sc ) )
  6022. {
  6023. LogFail( "ICommandProperties::GetProperties returned 0x%lx\n", sc );
  6024. }
  6025. if ( 0 == cPropsets || 0 == pPropInfo )
  6026. {
  6027. LogFail( "ICommandProperties::GetProperties returned no properties\n");
  6028. }
  6029. if (!fQuiet)
  6030. fVerbose++;
  6031. CheckRowsetProperties( cPropsets, pPropInfo, pCmd, FALSE );
  6032. if (!fQuiet)
  6033. fVerbose--;
  6034. }
  6035. void CheckPropertiesOnCommand( ICommand* pCmd, BOOL fQuiet )
  6036. {
  6037. if (! fQuiet)
  6038. LogProgress( " Verifying rowset properties (from command object)\n" );
  6039. DBPROPSET * pPropInfo = 0;
  6040. ULONG cPropsets = 0;
  6041. ICommandProperties *pCmdProp = 0;
  6042. SCODE sc = pCmd->QueryInterface(IID_ICommandProperties,(void **) &pCmdProp);
  6043. sc = pCmdProp->GetProperties( 0, 0, &cPropsets, &pPropInfo );
  6044. pCmdProp->Release();
  6045. if ( FAILED( sc ) )
  6046. {
  6047. //
  6048. // This isn't really kosher, but it helps to avoid spurious (client-side) memory leaks.
  6049. //
  6050. pCmd->Release();
  6051. LogFail( "ICommandProperties::GetProperties returned 0x%lx\n", sc );
  6052. }
  6053. CheckRowsetProperties( cPropsets, pPropInfo, pCmd );
  6054. }
  6055. void CheckColumns( IUnknown* pRowset, CDbColumns& rColumns, BOOL fQuiet )
  6056. {
  6057. if (! fQuiet)
  6058. LogProgress( " Verifying output columns\n" );
  6059. DBPROPSET * pPropInfo = 0;
  6060. ULONG cPropsets = 0;
  6061. IRowsetInfo *pIRowInfo = 0;
  6062. SCODE sc = pRowset->QueryInterface(IID_IRowsetInfo,(void **) &pIRowInfo);
  6063. sc = pIRowInfo->GetProperties( 0, 0, &cPropsets, &pPropInfo );
  6064. pIRowInfo->Release();
  6065. if ( FAILED( sc ) )
  6066. {
  6067. LogFail( "IRowsetInfo::GetProperties returned 0x%lx\n", sc );
  6068. }
  6069. CheckRowsetProperties( cPropsets, pPropInfo, pRowset );
  6070. DBID aDbCols[MAXCOLUMNS];
  6071. if (rColumns.Count() > MAXCOLUMNS)
  6072. {
  6073. LogError( "TEST ERROR: MAXCOLUMNS is too small\n" );
  6074. CantRun();
  6075. }
  6076. for (ULONG x = 0; x < rColumns.Count(); x++)
  6077. aDbCols[x] = * ((DBID *) &rColumns.Get(x));
  6078. aDbCols[0].uGuid.pguid = &(((DBID *)(&rColumns.Get(0)))->uGuid.guid);
  6079. if (aDbCols[0].eKind == DBKIND_GUID_PROPID)
  6080. aDbCols[0].eKind = DBKIND_PGUID_PROPID;
  6081. else
  6082. aDbCols[0].eKind = DBKIND_PGUID_NAME;
  6083. IColumnsInfo *pIColInfo = 0;
  6084. sc = pRowset->QueryInterface(IID_IColumnsInfo,(void **) &pIColInfo);
  6085. if ( FAILED( sc ) )
  6086. {
  6087. if ( sc == E_NOINTERFACE )
  6088. LogError( "IColumnsInfo failed (must be supported for MapColumnIDs), 0x%x\n", sc );
  6089. LogError( "IRowset::QI IColumnsInfo failed, 0x%x\n", sc );
  6090. cFailures++;
  6091. }
  6092. DBORDINAL aColIds[MAXCOLUMNS];
  6093. sc = pIColInfo->MapColumnIDs(rColumns.Count(), aDbCols, aColIds);
  6094. if (S_OK != sc)
  6095. {
  6096. LogFail( "CheckColumns, IRowset->MapColumnIDs returned 0x%lx\n",sc);
  6097. }
  6098. unsigned iExpCol = 1;
  6099. for (unsigned i = 0; i < rColumns.Count(); i++)
  6100. {
  6101. DBID dbidCol = rColumns.Get(i);
  6102. if (dbidCol.eKind = DBKIND_GUID_PROPID &&
  6103. dbidCol.uName.ulPropid == PROPID_DBBMK_BOOKMARK &&
  6104. dbidCol.uGuid.guid == guidBmk)
  6105. {
  6106. if (aColIds[i] != 0)
  6107. {
  6108. LogError( "IRowset->MapColumnIDs returned unexpected column number for bookmark col.\n" );
  6109. cFailures++;
  6110. }
  6111. }
  6112. else
  6113. {
  6114. if (aColIds[i] != iExpCol)
  6115. {
  6116. LogError( "IRowset->MapColumnIDs returned unexpected column number for col. %d\n", i);
  6117. cFailures++;
  6118. }
  6119. iExpCol++;
  6120. }
  6121. }
  6122. DBORDINAL cColumns = 0;
  6123. DBCOLUMNINFO *pColumnInfo = 0;
  6124. WCHAR *pColumnNames = 0;
  6125. sc = pIColInfo->GetColumnInfo( &cColumns, &pColumnInfo, &pColumnNames );
  6126. if ( FAILED( sc ) )
  6127. {
  6128. LogError( "IColumnsInfo::GetColumnInfo failed, 0x%x\n", sc );
  6129. cFailures++;
  6130. }
  6131. else
  6132. {
  6133. if ( cColumns < rColumns.Count() )
  6134. {
  6135. LogError( "Rowset has too few columns, %d %d\n",
  6136. cColumns, rColumns.Count() );
  6137. cFailures++;
  6138. }
  6139. }
  6140. if (pColumnInfo != 0)
  6141. {
  6142. if (fVerbose > 1)
  6143. printf("Columns Info:\n" );
  6144. for (ULONG iCol = 0; iCol < cColumns; iCol++)
  6145. {
  6146. DBCOLUMNINFO &Info = pColumnInfo [iCol];
  6147. if ( ( 0 == Info.iOrdinal &&
  6148. ! ( Info.dwFlags & DBCOLUMNFLAGS_ISBOOKMARK) ) ||
  6149. Info.iOrdinal > cColumns)
  6150. {
  6151. LogError( "IColumnsInfo->GetColumnInfo returned bad column number %d) for col. %d\n", Info.iOrdinal, iCol);
  6152. cFailures++;
  6153. }
  6154. if (Info.columnid.eKind != DBKIND_GUID_PROPID &&
  6155. Info.columnid.eKind != DBKIND_GUID_NAME &&
  6156. Info.columnid.eKind != DBKIND_PGUID_PROPID &&
  6157. Info.columnid.eKind != DBKIND_PGUID_NAME &&
  6158. Info.columnid.eKind != DBKIND_NAME)
  6159. {
  6160. LogError( "IColumnsInfo->GetColumnInfo returned bad column kind %d) for col. %d\n", Info.columnid.eKind, iCol);
  6161. cFailures++;
  6162. }
  6163. if (fVerbose > 1)
  6164. {
  6165. if (Info.columnid.eKind == DBKIND_GUID_PROPID)
  6166. printf ("(G) %-12li ", Info.columnid.uName.ulPropid);
  6167. else if (Info.columnid.eKind == DBKIND_GUID_NAME)
  6168. printf ("(G) '%-10ls' ", Info.columnid.uName.pwszName);
  6169. else if (Info.columnid.eKind == DBKIND_PGUID_PROPID)
  6170. printf ("(PG) %-12li ", Info.columnid.uName.ulPropid);
  6171. else if (Info.columnid.eKind == DBKIND_PGUID_NAME)
  6172. printf ("(PG) '%-10ls' ", Info.columnid.uName.pwszName);
  6173. else if (Info.columnid.eKind == DBKIND_NAME)
  6174. printf ("'%-14ls' ", Info.columnid.uName.pwszName);
  6175. else
  6176. printf ("BAD NAME ");
  6177. printf ("'%-14ls' %2lu %6s %2lu", Info.pwszName, Info.iOrdinal,
  6178. DBTYPE_Tag (Info.wType), Info.ulColumnSize);
  6179. printf ("\n ");
  6180. PrintColumnFlags (Info.dwFlags);
  6181. printf ("\n");
  6182. }
  6183. }
  6184. CoTaskMemFree(pColumnInfo);
  6185. CoTaskMemFree(pColumnNames);
  6186. }
  6187. IColumnsRowset *pIColRowset = 0;
  6188. sc = pRowset->QueryInterface(IID_IColumnsRowset,(void **) &pIColRowset );
  6189. if ( FAILED( sc ) && sc != E_NOINTERFACE )
  6190. {
  6191. LogError( "IRowset::qi for IColumnsRowset failed, 0x%x\n", sc );
  6192. cFailures++;
  6193. }
  6194. if (0 == pIColRowset && 0 == pIColInfo)
  6195. {
  6196. LogError( "At least one of IColumnsInfo and IColumnsRowset "
  6197. "must be implemented\n" );
  6198. cFailures++;
  6199. }
  6200. if (pIColRowset)
  6201. {
  6202. IRowset *pRowsetCols = 0;
  6203. SCODE scCC = pIColRowset->GetColumnsRowset(0, 0, 0, IID_IRowset, 0, 0,
  6204. (IUnknown**)&pRowsetCols);
  6205. if (FAILED(scCC))
  6206. {
  6207. LogError( "IColumnsRowset::GetColumnsRowset failed, 0x%x\n", scCC );
  6208. cFailures++;
  6209. }
  6210. if (SUCCEEDED(scCC))
  6211. pRowsetCols->Release();
  6212. }
  6213. if (pIColInfo)
  6214. {
  6215. pIColInfo->Release();
  6216. pIColInfo = 0;
  6217. }
  6218. if ( pIColRowset )
  6219. {
  6220. pIColRowset->Release();
  6221. pIColRowset = 0;
  6222. }
  6223. } //CheckColumns
  6224. //+-------------------------------------------------------------------------
  6225. //
  6226. // Function: BasicTest, public
  6227. //
  6228. // Synopsis: Test basic cursor functionality
  6229. //
  6230. // Arguments: [pCursor] - a pointer to an IRowset* to be tested.
  6231. // [fSequential] - if TRUE, the pCursor will not support
  6232. // IRowsetLocate, etc.
  6233. // [hChapt] - chapter pointer
  6234. // [cCols] - # of columns over which to test
  6235. //
  6236. // Returns: Nothing
  6237. //
  6238. // Notes: The passed in cursor is assumed to be set up with the
  6239. // usual column bindings. It is also assumed that the
  6240. // query has not necesarily completed.
  6241. //
  6242. // History: 26 Sep 94 AlanW Created from DownLevel test
  6243. // 11 Nov 94 Alanw Converted for phase 3
  6244. //
  6245. //--------------------------------------------------------------------------
  6246. void BasicTest(
  6247. IRowset* pCursor,
  6248. BOOL fSequential,
  6249. HCHAPTER hChapt,
  6250. unsigned cCols,
  6251. BOOL fByRef,
  6252. ICommandTree * pCmdTree )
  6253. {
  6254. int fFailed = 0;
  6255. DBCOUNTITEM cRows = 0;
  6256. IRowsetScroll * pIRowsetScroll = 0;
  6257. BOOL fChaptered = GetBooleanProperty( pCursor, DBPROP_IChapteredRowset );
  6258. if (cCols != cBasicTestCols && cCols != cBasicTestCols-1)
  6259. LogFail( "TEST ERROR - bad cCols (%d) passed to BasicTest\n", cCols );
  6260. SCODE sc = pCursor->QueryInterface(IID_IRowsetScroll,(void **) &pIRowsetScroll );
  6261. if ( FAILED( sc ) && sc != E_NOINTERFACE )
  6262. {
  6263. LogError( "IRowset::qi for IRowsetScroll failed, 0x%x\n", sc );
  6264. cFailures++;
  6265. }
  6266. if ( fSequential )
  6267. {
  6268. if (0 != pIRowsetScroll )
  6269. {
  6270. LogError( "Sequential cursor supports IRowsetScroll\n" );
  6271. cFailures++;
  6272. }
  6273. }
  6274. else
  6275. {
  6276. if (0 == pIRowsetScroll )
  6277. {
  6278. LogError( "Non-sequential cursor does not support IRowsetScroll\n" );
  6279. cFailures++;
  6280. }
  6281. else
  6282. {
  6283. sc = pIRowsetScroll->GetApproximatePosition(hChapt, 0,0,
  6284. 0, &cRows);
  6285. if ( FAILED( sc ) )
  6286. {
  6287. LogError( "IRowset->GetApproximatePosition returned 0x%lx\n", sc );
  6288. cFailures++;
  6289. }
  6290. if ( cRows == 0 )
  6291. {
  6292. LogError( "Query failed to return data\n" );
  6293. pIRowsetScroll->Release();
  6294. pCursor->Release();
  6295. Fail();
  6296. }
  6297. }
  6298. }
  6299. //
  6300. // Patch the column index numbers with true numbers
  6301. //
  6302. DBID aDbCols[cBasicTestCols];
  6303. aDbCols[0] = psClassid;
  6304. aDbCols[1] = psSize;
  6305. aDbCols[2] = psWriteTime;
  6306. aDbCols[3] = psAttr;
  6307. aDbCols[4] = psName;
  6308. aDbCols[5] = psPath;
  6309. aDbCols[6] = psSelf;
  6310. IUnknown * pAccessor = (IUnknown *) pCursor; // hAccessor must be created on rowset
  6311. // to be used with rowset->GetData below
  6312. if (fByRef)
  6313. {
  6314. aBasicTestCols[5].dwMemOwner = DBMEMOWNER_PROVIDEROWNED;
  6315. }
  6316. else
  6317. {
  6318. aBasicTestCols[5].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
  6319. }
  6320. HACCESSOR hAccessor = MapColumns( pAccessor,
  6321. cCols,
  6322. aBasicTestCols,
  6323. aDbCols,
  6324. fByRef );
  6325. DBID aDbAltCols[cBasicAltCols];
  6326. aDbAltCols[0] = psSize;
  6327. aDbAltCols[1] = psWriteTime;
  6328. aDbAltCols[2] = psWriteTime;
  6329. aDbAltCols[3] = psWriteTime;
  6330. HACCESSOR hAccessor2 = MapColumns( pAccessor,
  6331. cBasicAltCols,
  6332. aBasicAltCols,
  6333. aDbAltCols,
  6334. fByRef );
  6335. #if defined( DO_NOTIFICATION )
  6336. IConnectionPoint *pConnectionPoint = 0;
  6337. DWORD dwAdviseID = 0;
  6338. CTestWatchNotify Notify;
  6339. if ( ! fSequential )
  6340. {
  6341. Notify.DoChecking(TRUE);
  6342. //
  6343. // Get the connection point container
  6344. //
  6345. IConnectionPointContainer *pConnectionPointContainer = 0;
  6346. sc = pCursor->QueryInterface(IID_IConnectionPointContainer,
  6347. (void **) &pConnectionPointContainer);
  6348. if (FAILED(sc))
  6349. {
  6350. LogError( "IRowset->QI for IConnectionPointContainer failed: 0x%x\n",
  6351. sc );
  6352. pCursor->Release();
  6353. Fail();
  6354. }
  6355. //
  6356. // Make a connection point from the connection point container
  6357. //
  6358. sc = pConnectionPointContainer->FindConnectionPoint(
  6359. IID_IRowsetWatchNotify,
  6360. &pConnectionPoint);
  6361. if (FAILED(sc) && CONNECT_E_NOCONNECTION != sc )
  6362. {
  6363. LogError( "FindConnectionPoint failed: 0x%x\n",sc );
  6364. pCursor->Release();
  6365. Fail();
  6366. }
  6367. pConnectionPointContainer->Release();
  6368. if (0 != pConnectionPoint)
  6369. {
  6370. //
  6371. // Give a callback object to the connection point
  6372. //
  6373. sc = pConnectionPoint->Advise((IUnknown *) &Notify,
  6374. &dwAdviseID);
  6375. if (FAILED(sc))
  6376. {
  6377. LogError( "IConnectionPoint->Advise failed: 0x%x\n",sc );
  6378. pConnectionPoint->Release();
  6379. pCursor->Release();
  6380. Fail();
  6381. }
  6382. }
  6383. }
  6384. #endif // DO_NOTIFICATION
  6385. DBCOUNTITEM totalRowsFetched = 0;
  6386. DBCOUNTITEM cRowsReturned = 0;
  6387. HROW ahRows[10];
  6388. HROW* phRows = ahRows;
  6389. LONGLONG PrevFileSize = 0x7fffffffffffffff;
  6390. //
  6391. // Try passing chapters to non-chaptered rowsets.
  6392. // This causes an exception, so just do it once for each case.
  6393. //
  6394. static BOOL fTriedChaptOnNonChaptered = FALSE;
  6395. #if 0 // NOTE: null chapters work on chaptered rowsets!
  6396. static BOOL fTriedNoChaptOnChaptered = FALSE;
  6397. if ( !fTriedNoChaptOnChaptered && 0 != hChapt )
  6398. {
  6399. fTriedNoChaptOnChaptered = TRUE;
  6400. sc = pCursor->GetNextRows(DB_NULL_HCHAPTER, 0, 10, &cRowsReturned, &phRows);
  6401. if (!FAILED(sc))
  6402. LogFail("chaptered IRowset->GetNextRows should have failed\n");
  6403. }
  6404. #endif 0
  6405. if ( !fTriedChaptOnNonChaptered && (0 == hChapt) )
  6406. {
  6407. fTriedChaptOnNonChaptered = TRUE;
  6408. sc = pCursor->GetNextRows(DBCHP_FIRST, 0, 10, &cRowsReturned, &phRows);
  6409. if (!FAILED(sc))
  6410. LogFail("unchaptered IRowset->GetNextRows should have failed\n");
  6411. }
  6412. do
  6413. {
  6414. sc = pCursor->GetNextRows(hChapt, 0, 10, &cRowsReturned, &phRows);
  6415. if ( FAILED( sc ) )
  6416. {
  6417. LogError( "IRowset->GetNextRows returned 0x%x\n", sc );
  6418. pCursor->Release();
  6419. Fail();
  6420. }
  6421. if (sc != DB_S_ENDOFROWSET &&
  6422. cRowsReturned != 10)
  6423. {
  6424. LogError( "IRowset->GetNextRows returned %d of %d rows,"
  6425. " status (%x) != DB_S_ENDOFROWSET\n",
  6426. cRowsReturned, 10,
  6427. sc);
  6428. #if defined (UNIT_TEST)
  6429. cFailures++;
  6430. #else // defined(UNIT_TEST)
  6431. pCursor->Release();
  6432. Fail();
  6433. #endif // defined(UNIT_TEST)
  6434. }
  6435. totalRowsFetched += cRowsReturned;
  6436. if ( (0 != pIRowsetScroll ) &&
  6437. (totalRowsFetched > cRows) )
  6438. {
  6439. //
  6440. // check that no more rows have been added while we were
  6441. // fetching.
  6442. //
  6443. LogProgress("Checking for expansion of result set\n");
  6444. SCODE sc1 = pIRowsetScroll->GetApproximatePosition(hChapt,
  6445. 0,0, 0, &cRows);
  6446. if ( totalRowsFetched > cRows )
  6447. {
  6448. LogError("Fetched more rows than exist in the result set, %d %d\n",
  6449. totalRowsFetched, cRows);
  6450. cFailures++;
  6451. }
  6452. }
  6453. //
  6454. // Make sure the hits are sorted by size and that the query
  6455. // really was shallow and that the length fields are correct.
  6456. //
  6457. unsigned i;
  6458. for (i = 0; i < cRowsReturned; i++)
  6459. {
  6460. SBasicTest Row;
  6461. Row.pIPSStorage = 0;
  6462. SCODE sc1 = pCursor->GetData(ahRows[i],hAccessor,&Row);
  6463. if ( FAILED( sc1 ) )
  6464. LogFail( "IRowset->GetData returned 0x%x\n", sc1 );
  6465. LONGLONG size = Row.size;
  6466. if ( PrevFileSize < size &&
  6467. ( ! fChaptered || hChapt != DB_NULL_HCHAPTER) )
  6468. LogFail("Hitset not sorted by filesize\n");
  6469. if (wcsstr( Row.pwcPath, L"system32\\drivers\\" ) ||
  6470. wcsstr( Row.pwcPath, L"SYSTEM32\\DRIVERS\\" ) ||
  6471. wcsstr( Row.pwcPath, L"System32\\Drivers\\" ))
  6472. LogFail("Query wasn't shallow as expected\n");
  6473. if ( Row.sClsid == DBSTATUS_S_OK &&
  6474. Row.cbClsid != sizeof CLSID )
  6475. LogFail("length of clsid column not correct: %d\n", Row.cbClsid);
  6476. if ( Row.sSize != DBSTATUS_S_OK ||
  6477. Row.cbSize != sizeof LONGLONG )
  6478. LogFail("status or length of size column not correct: %d\n",
  6479. Row.cbSize);
  6480. if ( Row.sWriteTime != DBSTATUS_S_OK ||
  6481. Row.cbWriteTime != sizeof LONGLONG)
  6482. LogFail("status or length of time column not correct: %d\n", Row.cbWriteTime);
  6483. if ( Row.sAttr != DBSTATUS_S_OK ||
  6484. Row.cbAttr != sizeof ULONG)
  6485. LogFail("length of attr column not correct: %d\n", Row.cbAttr);
  6486. if ( Row.sName == DBSTATUS_S_OK &&
  6487. Row.cbName != wcslen(Row.awcName) * sizeof (WCHAR) )
  6488. LogFail( "length of name column 0x%x not consistent with data 0x%x\n",
  6489. Row.cbName,
  6490. wcslen(Row.awcName) * sizeof WCHAR );
  6491. if ( Row.sPath == DBSTATUS_S_OK &&
  6492. Row.cbPath != (wcslen(Row.pwcPath) * sizeof (WCHAR)) )
  6493. LogFail("length of path column not consistent with data\n");
  6494. if ( !fByRef )
  6495. CoTaskMemFree(Row.pwcPath);
  6496. if ( 0 != Row.pIPSStorage )
  6497. {
  6498. Row.pIPSStorage->Release();
  6499. Row.pIPSStorage = 0;
  6500. }
  6501. SBasicAltTest AltRow;
  6502. SCODE sc2 = pCursor->GetData(ahRows[i], hAccessor2, &AltRow);
  6503. if ( FAILED( sc2 ) )
  6504. LogFail( "IRowset->GetData returned 0x%x\n", sc2 );
  6505. if ( AltRow.sSize != DBSTATUS_S_OK ||
  6506. AltRow.cbSize != sizeof AltRow.Size )
  6507. LogFail("status or length of alt size column not correct: %d\n",
  6508. AltRow.cbSize);
  6509. if ( AltRow.Size != Row.size )
  6510. LogFail("size column doesn't compare in alt. accessor\n");
  6511. //
  6512. // Check time conversions
  6513. //
  6514. FILETIME LocalFTime;
  6515. SYSTEMTIME SysTime;
  6516. FileTimeToSystemTime((FILETIME *) &(Row.writeTime), &SysTime);
  6517. if ( AltRow.sWriteTime1 != DBSTATUS_S_OK ||
  6518. AltRow.cbWriteTime1 != sizeof AltRow.writeTime1)
  6519. LogFail("status or length of writeTime1 column not correct: %d\n",
  6520. AltRow.cbWriteTime1);
  6521. if ( AltRow.sWriteTime2 != DBSTATUS_S_OK ||
  6522. AltRow.cbWriteTime2 != sizeof AltRow.writeTime2)
  6523. LogFail("status or length of writeTime2 column not correct: %d\n",
  6524. AltRow.cbWriteTime2);
  6525. if ( AltRow.sWriteTime3 != DBSTATUS_S_OK ||
  6526. AltRow.cbWriteTime3 != sizeof AltRow.writeTime3)
  6527. LogFail("status or length of writeTime3 column not correct: %d\n",
  6528. AltRow.cbWriteTime3);
  6529. if ( SysTime.wYear != AltRow.writeTime1.year ||
  6530. SysTime.wMonth != AltRow.writeTime1.month ||
  6531. SysTime.wDay != AltRow.writeTime1.day)
  6532. LogFail("Write time 1 mismatch\n");
  6533. if ( SysTime.wHour != AltRow.writeTime2.hour ||
  6534. SysTime.wMinute != AltRow.writeTime2.minute ||
  6535. SysTime.wSecond != AltRow.writeTime2.second)
  6536. LogFail("Write time 2 mismatch\n");
  6537. if ( SysTime.wYear != AltRow.writeTime3.year ||
  6538. SysTime.wMonth != AltRow.writeTime3.month ||
  6539. SysTime.wDay != AltRow.writeTime3.day ||
  6540. SysTime.wHour != AltRow.writeTime3.hour ||
  6541. SysTime.wMinute != AltRow.writeTime3.minute ||
  6542. SysTime.wSecond != AltRow.writeTime3.second ||
  6543. SysTime.wMilliseconds != AltRow.writeTime3.fraction/1000000)
  6544. LogFail("Write time 3 mismatch\n");
  6545. PrevFileSize = size;
  6546. }
  6547. if (fVerbose > 1)
  6548. {
  6549. for (i = 0; i < cRowsReturned; i++)
  6550. {
  6551. SBasicTest Row;
  6552. Row.pIPSStorage = 0;
  6553. SCODE sc1 = pCursor->GetData(ahRows[i],hAccessor,&Row);
  6554. if ( FAILED( sc1 ) )
  6555. {
  6556. LogError( "IRowset->GetData returned 0x%x\n", sc1 );
  6557. pCursor->Release();
  6558. Fail();
  6559. }
  6560. //
  6561. // print name, attributes and size
  6562. //
  6563. printf( "\t%-16.16ws%04x\t%7d\t",
  6564. Row.awcName,
  6565. Row.attr,
  6566. (ULONG) Row.size );
  6567. //
  6568. // print file mod. time
  6569. //
  6570. FILETIME LocalFTime;
  6571. SYSTEMTIME SysTime;
  6572. FileTimeToLocalFileTime((FILETIME *) &(Row.writeTime),
  6573. &LocalFTime);
  6574. FileTimeToSystemTime(&LocalFTime, &SysTime);
  6575. printf("%02d/%02d/%02d %2d:%02d:%02d\n",
  6576. SysTime.wMonth, SysTime.wDay, SysTime.wYear % 100,
  6577. SysTime.wHour, SysTime.wMinute, SysTime.wSecond);
  6578. if ( !fByRef )
  6579. CoTaskMemFree(Row.pwcPath);
  6580. if (0 != Row.pIPSStorage )
  6581. {
  6582. Row.pIPSStorage->Release();
  6583. Row.pIPSStorage = 0;
  6584. }
  6585. }
  6586. }
  6587. if (0 != cRowsReturned)
  6588. {
  6589. SCODE sc1 = pCursor->ReleaseRows(cRowsReturned, ahRows, 0, 0, 0);
  6590. if ( FAILED( sc1 ) )
  6591. {
  6592. LogError( "IRowset->ReleaseRows returned 0x%x\n", sc1 );
  6593. pCursor->Release();
  6594. Fail();
  6595. }
  6596. cRowsReturned = 0;
  6597. }
  6598. } while (SUCCEEDED(sc) && sc != DB_S_ENDOFROWSET);
  6599. if (0 != cRowsReturned)
  6600. {
  6601. SCODE sc1 = pCursor->ReleaseRows(cRowsReturned, ahRows, 0, 0, 0);
  6602. if ( FAILED( sc1 ) )
  6603. {
  6604. LogError( "IRowset->ReleaseRows returned 0x%x\n", sc1 );
  6605. pCursor->Release();
  6606. Fail();
  6607. }
  6608. }
  6609. if ( 0 == totalRowsFetched && 0 != hChapt )
  6610. LogFail("Chapter had no rows for GetNextRows()\n");
  6611. ReleaseAccessor( pAccessor, hAccessor);
  6612. ReleaseAccessor( pAccessor, hAccessor2);
  6613. #if defined( DO_NOTIFICATION )
  6614. if ( ! fSequential && 0 != pConnectionPoint )
  6615. {
  6616. NotificationTest();
  6617. //
  6618. // Clean up notification stuff
  6619. //
  6620. sc = pConnectionPoint->Unadvise(dwAdviseID);
  6621. if (S_OK != sc)
  6622. {
  6623. LogError( "IConnectionPoint->Unadvise returned 0x%lx\n",sc);
  6624. pCursor->Release();
  6625. Fail();
  6626. }
  6627. pConnectionPoint->Release();
  6628. //Notify.Release();
  6629. }
  6630. #endif // DO_NOTIFICATION
  6631. if (0 != pIRowsetScroll )
  6632. {
  6633. pIRowsetScroll->Release();
  6634. pIRowsetScroll = 0;
  6635. }
  6636. #if !defined(UNIT_TEST)
  6637. if (cFailures) {
  6638. pCursor->Release();
  6639. Fail();
  6640. }
  6641. #endif // !UNIT_TEST
  6642. } //BasicTest
  6643. //+-------------------------------------------------------------------------
  6644. //
  6645. // Function: BackwardsFetchTest, public
  6646. //
  6647. // Synopsis: Test backwards fetching
  6648. //
  6649. // Arguments: [pRowset] - IRowset to be tested
  6650. //
  6651. // History: 03-Sep-97 SitaramR Created
  6652. //
  6653. //--------------------------------------------------------------------------
  6654. void BackwardsFetchTest( IRowset* pRowset )
  6655. {
  6656. //
  6657. // Patch the column index numbers with true numbers
  6658. //
  6659. DBID aDbCols[cBasicTestCols];
  6660. aDbCols[0] = psClassid;
  6661. aDbCols[1] = psSize;
  6662. aDbCols[2] = psWriteTime;
  6663. aDbCols[3] = psAttr;
  6664. aDbCols[4] = psName;
  6665. aDbCols[5] = psPath;
  6666. aDbCols[6] = psSelf;
  6667. IUnknown * pAccessor = (IUnknown *) pRowset; // hAccessor must be created on rowset
  6668. // to be used with rowset->GetData below
  6669. aBasicTestCols[5].dwMemOwner = DBMEMOWNER_PROVIDEROWNED;
  6670. HACCESSOR hAccessor = MapColumns( pAccessor,
  6671. cBasicTestCols,
  6672. aBasicTestCols,
  6673. aDbCols,
  6674. TRUE );
  6675. DBCOUNTITEM cRowsReturned = 0;
  6676. HROW ahRows[10];
  6677. HROW* phRows = ahRows;
  6678. //
  6679. // Backwards fetch for GetNextRows
  6680. //
  6681. SCODE sc = pRowset->RestartPosition( 0 );
  6682. if ( FAILED( sc ) )
  6683. {
  6684. LogError( "IRowset->RestartPosition returned 0x%x\n", sc );
  6685. pRowset->Release();
  6686. Fail();
  6687. }
  6688. sc = pRowset->GetNextRows(0, 9, -9, &cRowsReturned, &phRows);
  6689. if ( FAILED( sc ) )
  6690. {
  6691. LogError( "IRowset->GetNextRows returned 0x%x\n", sc );
  6692. pRowset->Release();
  6693. Fail();
  6694. }
  6695. if ( cRowsReturned != 9 )
  6696. {
  6697. LogError( "IRowset->GetNextRows returned %d of %d rows,"
  6698. " status (%x) != DB_S_ENDOFROWSET\n",
  6699. cRowsReturned,
  6700. 10,
  6701. sc);
  6702. #if defined (UNIT_TEST)
  6703. cFailures++;
  6704. #else
  6705. pRowset->Release();
  6706. Fail();
  6707. #endif
  6708. }
  6709. //
  6710. // Check data of some of the fields
  6711. //
  6712. for ( unsigned i = 0; i < cRowsReturned; i++)
  6713. {
  6714. SBasicTest Row;
  6715. Row.pIPSStorage = 0;
  6716. SCODE sc1 = pRowset->GetData(ahRows[i],hAccessor,&Row);
  6717. if ( FAILED( sc1 ) )
  6718. LogFail( "IRowset->GetData returned 0x%x\n", sc1 );
  6719. if (wcsstr( Row.pwcPath, L"system32\\drivers\\" ) ||
  6720. wcsstr( Row.pwcPath, L"SYSTEM32\\DRIVERS\\" ) ||
  6721. wcsstr( Row.pwcPath, L"System32\\Drivers\\" ))
  6722. LogFail("Query wasn't shallow as expected\n");
  6723. if ( Row.sClsid == DBSTATUS_S_OK &&
  6724. Row.cbClsid != sizeof CLSID )
  6725. LogFail("length of clsid column not correct: %d\n", Row.cbClsid);
  6726. if ( Row.sSize != DBSTATUS_S_OK ||
  6727. Row.cbSize != sizeof LONGLONG )
  6728. LogFail("status or length of size column not correct: %d\n",
  6729. Row.cbSize);
  6730. }
  6731. if (0 != cRowsReturned)
  6732. {
  6733. SCODE sc1 = pRowset->ReleaseRows(cRowsReturned, ahRows, 0, 0, 0);
  6734. if ( FAILED( sc1 ) )
  6735. {
  6736. LogError( "IRowset->ReleaseRows returned 0x%x\n", sc1 );
  6737. pRowset->Release();
  6738. Fail();
  6739. }
  6740. }
  6741. sc = pRowset->RestartPosition( 0 );
  6742. if ( FAILED( sc ) )
  6743. {
  6744. LogError( "IRowset->RestartPosition returned 0x%x\n", sc );
  6745. pRowset->Release();
  6746. Fail();
  6747. }
  6748. //
  6749. // Backwards fetch for GetRowsAt
  6750. //
  6751. IRowsetLocate *pRowsetLocate = 0;
  6752. sc = pRowset->QueryInterface(IID_IRowsetLocate,(void **) &pRowsetLocate );
  6753. if ( FAILED( sc ) && sc != E_NOINTERFACE )
  6754. {
  6755. LogError( "IRowset::qi for IRowsetLocate failed, 0x%x\n", sc );
  6756. #if defined (UNIT_TEST)
  6757. cFailures++;
  6758. #else
  6759. pRowset->Release();
  6760. Fail();
  6761. #endif
  6762. }
  6763. sc = pRowsetLocate->GetRowsAt(0, 0, 1, &bmkFirst, 9, -10, &cRowsReturned, &phRows);
  6764. if ( FAILED( sc ) )
  6765. {
  6766. LogError( "IRowsetLocate->GetRowsAt returned 0x%x\n", sc );
  6767. pRowsetLocate->Release();
  6768. Fail();
  6769. }
  6770. if ( cRowsReturned != 10 )
  6771. {
  6772. LogError( "IRowset->GetRowsAt returned %d of %d rows,"
  6773. " status (%x) != DB_S_ENDOFROWSET\n",
  6774. cRowsReturned,
  6775. 10,
  6776. sc);
  6777. #if defined (UNIT_TEST)
  6778. cFailures++;
  6779. #else
  6780. pRowsetLocate->Release();
  6781. Fail();
  6782. #endif
  6783. }
  6784. //
  6785. // Check data of some of the fields
  6786. //
  6787. for ( i = 0; i < cRowsReturned; i++)
  6788. {
  6789. SBasicTest Row;
  6790. Row.pIPSStorage = 0;
  6791. SCODE sc1 = pRowsetLocate->GetData(ahRows[i],hAccessor,&Row);
  6792. if ( FAILED( sc1 ) )
  6793. LogFail( "IRowset->GetData returned 0x%x\n", sc1 );
  6794. if (wcsstr( Row.pwcPath, L"system32\\drivers\\" ) ||
  6795. wcsstr( Row.pwcPath, L"SYSTEM32\\DRIVERS\\" ) ||
  6796. wcsstr( Row.pwcPath, L"System32\\Drivers\\" ))
  6797. LogFail("Query wasn't shallow as expected\n");
  6798. if ( Row.sClsid == DBSTATUS_S_OK &&
  6799. Row.cbClsid != sizeof CLSID )
  6800. LogFail("length of clsid column not correct: %d\n", Row.cbClsid);
  6801. if ( Row.sSize != DBSTATUS_S_OK ||
  6802. Row.cbSize != sizeof LONGLONG )
  6803. LogFail("status or length of size column not correct: %d\n",
  6804. Row.cbSize);
  6805. }
  6806. HROW ahRows2[10];
  6807. HROW ahRows3[10];
  6808. DBCOUNTITEM cRowsReturned2;
  6809. HROW *phRows2 = ahRows2;
  6810. //
  6811. // Forward fetch rows 1 to 10 for CheckHrowIdentity comparison below
  6812. //
  6813. sc = pRowsetLocate->GetRowsAt(0, 0, 1, &bmkFirst, 0, 10, &cRowsReturned2, &phRows2);
  6814. if ( FAILED( sc ) )
  6815. {
  6816. LogError( "IRowsetLocate->GetRowsAt returned 0x%x\n", sc );
  6817. pRowsetLocate->Release();
  6818. Fail();
  6819. }
  6820. if ( cRowsReturned2 != 10 )
  6821. {
  6822. LogError( "IRowset->GetRowsAt returned %d of %d rows,"
  6823. " status (%x) != DB_S_ENDOFROWSET\n",
  6824. cRowsReturned,
  6825. 10,
  6826. sc);
  6827. #if defined (UNIT_TEST)
  6828. cFailures++;
  6829. #else
  6830. pRowsetLocate->Release();
  6831. Fail();
  6832. #endif
  6833. }
  6834. //
  6835. // Reverse ahRows2 into ahRows3 in preparation for CheckHrowIdentity
  6836. // comparison below.
  6837. //
  6838. for ( i=0; i<10; i++ )
  6839. ahRows3[i] = ahRows2[9-i];
  6840. //
  6841. // Check that forward fetch of rows 1 thru 10 and backwards fetch of
  6842. // rows 10 thru 1 (and then reversed) are the same.
  6843. //
  6844. int fFailed = CheckHrowIdentity( 0, 0, 10, ahRows, 10, ahRows3 );
  6845. if ( fFailed > 0 )
  6846. {
  6847. LogError( "Backwards fetch CheckHrowIdentity returned 0x%x\n", fFailed );
  6848. pRowsetLocate->Release();
  6849. Fail();
  6850. }
  6851. if (0 != cRowsReturned2)
  6852. {
  6853. SCODE sc1 = pRowsetLocate->ReleaseRows(cRowsReturned2, ahRows2, 0, 0, 0);
  6854. if ( FAILED( sc1 ) )
  6855. {
  6856. LogError( "IRowset->ReleaseRows returned 0x%x\n", sc1 );
  6857. pRowsetLocate->Release();
  6858. Fail();
  6859. }
  6860. }
  6861. if (0 != cRowsReturned)
  6862. {
  6863. SCODE sc1 = pRowsetLocate->ReleaseRows(cRowsReturned, ahRows, 0, 0, 0);
  6864. if ( FAILED( sc1 ) )
  6865. {
  6866. LogError( "IRowset->ReleaseRows returned 0x%x\n", sc1 );
  6867. pRowsetLocate->Release();
  6868. Fail();
  6869. }
  6870. }
  6871. pRowsetLocate->Release();
  6872. //
  6873. // Backwards fetch for GetRowsAtRatio
  6874. //
  6875. IRowsetScroll *pRowsetScroll = 0;
  6876. sc = pRowset->QueryInterface(IID_IRowsetScroll,(void **) &pRowsetScroll );
  6877. if ( FAILED( sc ) && sc != E_NOINTERFACE )
  6878. {
  6879. LogError( "IRowset::qi for IRowsetScroll failed, 0x%x\n", sc );
  6880. #if defined (UNIT_TEST)
  6881. cFailures++;
  6882. #else
  6883. pRowset->Release();
  6884. Fail();
  6885. #endif
  6886. }
  6887. sc = pRowsetScroll->GetRowsAtRatio(0, 0, 50, 100, -9, &cRowsReturned, &phRows);
  6888. if ( FAILED( sc ) )
  6889. {
  6890. LogError( "IRowsetScroll->GetRowsAtRatio returned 0x%x\n", sc );
  6891. pRowsetScroll->Release();
  6892. Fail();
  6893. }
  6894. //
  6895. // Check data of some of the fields
  6896. //
  6897. for ( i = 0; i < cRowsReturned; i++)
  6898. {
  6899. SBasicTest Row;
  6900. Row.pIPSStorage = 0;
  6901. SCODE sc1 = pRowsetScroll->GetData(ahRows[i],hAccessor,&Row);
  6902. if ( FAILED( sc1 ) )
  6903. LogFail( "IRowsetScroll->GetData returned 0x%x\n", sc1 );
  6904. if (wcsstr( Row.pwcPath, L"system32\\drivers\\" ) ||
  6905. wcsstr( Row.pwcPath, L"SYSTEM32\\DRIVERS\\" ) ||
  6906. wcsstr( Row.pwcPath, L"System32\\Drivers\\" ))
  6907. LogFail("Query wasn't shallow as expected\n");
  6908. if ( Row.sClsid == DBSTATUS_S_OK &&
  6909. Row.cbClsid != sizeof CLSID )
  6910. LogFail("length of clsid column not correct: %d\n", Row.cbClsid);
  6911. if ( Row.sSize != DBSTATUS_S_OK ||
  6912. Row.cbSize != sizeof LONGLONG )
  6913. LogFail("status or length of size column not correct: %d\n",
  6914. Row.cbSize);
  6915. }
  6916. if (0 != cRowsReturned)
  6917. {
  6918. SCODE sc1 = pRowsetScroll->ReleaseRows(cRowsReturned, ahRows, 0, 0, 0);
  6919. if ( FAILED( sc1 ) )
  6920. {
  6921. LogError( "IRowsetScroll->ReleaseRows returned 0x%x\n", sc1 );
  6922. pRowsetScroll->Release();
  6923. Fail();
  6924. }
  6925. }
  6926. pRowsetScroll->Release();
  6927. ReleaseAccessor( pAccessor, hAccessor);
  6928. }
  6929. //+-------------------------------------------------------------------------
  6930. //
  6931. // Function: FetchTest, public
  6932. //
  6933. // Synopsis: Test GetNextRows variations
  6934. //
  6935. // Arguments: [pRowset] - a pointer to an IRowset to be tested.
  6936. //
  6937. // Returns: Nothing
  6938. //
  6939. // Notes: The passed in Rowset is assumed to be set up with the
  6940. // usual column bindings and is capable of supporting
  6941. // Rowset movement via bookmarks in GetRowsAt.
  6942. //
  6943. // History: 30 Sep 94 AlanW Created from BasicTest test
  6944. //
  6945. // ToDo: add tests:
  6946. // backward fetch
  6947. // caller/callee allocated hrow array
  6948. // fetch of 0 rows
  6949. //
  6950. //--------------------------------------------------------------------------
  6951. void FetchTest( IRowset* pRowset )
  6952. {
  6953. LogProgress( " Row fetch test\n" );
  6954. int fFailed = 0;
  6955. HROW hBad = (HROW) 0xDEDEDEDE;
  6956. ULONG cRefsLeft = 0;
  6957. DBROWSTATUS RowStatus = 0;
  6958. // Try releasing a bad HROW (bug #7449)
  6959. SCODE sc = pRowset->ReleaseRows( 1, &hBad, 0, &cRefsLeft, &RowStatus );
  6960. if (sc != DB_E_ERRORSOCCURRED ||
  6961. RowStatus != DBROWSTATUS_E_INVALID)
  6962. {
  6963. LogError( "ReleaseRows of bad handle returned %x, %x\n", sc, RowStatus );
  6964. fFailed++;
  6965. }
  6966. cFailures += fFailed;
  6967. #if !defined(UNIT_TEST)
  6968. if (fFailed) {
  6969. pRowset->Release();
  6970. Fail();
  6971. }
  6972. #endif // !UNIT_TEST
  6973. } //FetchTest
  6974. //+-------------------------------------------------------------------------
  6975. //
  6976. // Function: BindingTest, public
  6977. //
  6978. // Synopsis: Test some of the many possible error paths in CreateAccessor
  6979. //
  6980. // Arguments: [pCursor] - a pointer to an IRowset* to be tested.
  6981. //
  6982. // Returns: Nothing
  6983. //
  6984. // Notes: The helper function TryBinding does much of the work,
  6985. // trying a couple of different scenarios with each input
  6986. // binding set, checking results and reporting errors.
  6987. //
  6988. // History: 02 Jul 94 AlanW Created
  6989. //
  6990. //--------------------------------------------------------------------------
  6991. static DBBINDING aTestBindings[] =
  6992. {
  6993. { 0, // binding 0
  6994. 0,
  6995. 0,
  6996. 0,
  6997. 0,0,0,
  6998. DBPART_VALUE,
  6999. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  7000. sizeof (VARIANT),
  7001. 0, DBTYPE_VARIANT,
  7002. 0,0},
  7003. { 2, // binding 1
  7004. 0,
  7005. 0,
  7006. 0,
  7007. 0,0,0,
  7008. DBPART_VALUE,
  7009. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  7010. 0,
  7011. 0, DBTYPE_I8,
  7012. 0,0},
  7013. { 2, // binding 2
  7014. 2 * sizeof (VARIANT),
  7015. 0,
  7016. 0,
  7017. 0,0,0,
  7018. (DBPART) 0x01000000,
  7019. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  7020. sizeof (VARIANT),
  7021. 0, DBTYPE_VARIANT,
  7022. 0,0},
  7023. { 2, // binding 3
  7024. 3 * sizeof (VARIANT),
  7025. 0,
  7026. 0,
  7027. 0,0,0,
  7028. DBPART_STATUS,
  7029. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  7030. sizeof (VARIANT),
  7031. 0, DBTYPE_VARIANT,
  7032. 0,0},
  7033. { 2, // binding 4
  7034. 7,
  7035. 0,
  7036. 0,
  7037. 0,0,0,
  7038. DBPART_VALUE,
  7039. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  7040. 1,
  7041. 0, DBTYPE_I8,
  7042. 0,0},
  7043. { 1, // binding 5
  7044. 0,
  7045. 0,
  7046. 0,
  7047. 0,0,0,
  7048. DBPART_VALUE|DBPART_STATUS,
  7049. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  7050. 1,
  7051. 0, DBTYPE_I8,
  7052. 0,0},
  7053. { 1, // binding 6
  7054. 0,
  7055. 0,
  7056. 0,
  7057. 0,0,0,
  7058. DBPART_VALUE,
  7059. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  7060. 1,
  7061. 0, DBTYPE_GUID,
  7062. 0,0},
  7063. { 1, // binding 7
  7064. 0,
  7065. 0,
  7066. 0,
  7067. 0,0,0,
  7068. DBPART_VALUE,
  7069. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  7070. 1,
  7071. 0, DBTYPE_GUID,
  7072. 0,0},
  7073. { 1, // binding 8
  7074. 0,
  7075. 0,
  7076. 0,
  7077. (ITypeInfo *) 1,0,0,
  7078. DBPART_VALUE,
  7079. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  7080. 1,
  7081. 0, DBTYPE_VARIANT,
  7082. 0,0},
  7083. { 1, // binding 9
  7084. 0,
  7085. 0,
  7086. 0,
  7087. 0,0,0,
  7088. DBPART_VALUE,
  7089. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  7090. 1,
  7091. 0, DBTYPE_GUID,
  7092. 0,0},
  7093. { 1, // binding 10
  7094. 0,
  7095. 0,
  7096. 0,
  7097. 0,0,0,
  7098. DBPART_VALUE,
  7099. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  7100. 1,
  7101. 0, DBTYPE_I4|DBTYPE_BYREF,
  7102. 0,0},
  7103. { 1, // binding 11
  7104. 0,
  7105. 20,
  7106. 0,
  7107. 0,0,0,
  7108. DBPART_VALUE,
  7109. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  7110. 1,
  7111. DBBINDFLAG_HTML, DBTYPE_WSTR,
  7112. 0,0},
  7113. { 1, // binding 12
  7114. 0,
  7115. 20,
  7116. 0,
  7117. 0,0,0,
  7118. DBPART_VALUE,
  7119. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  7120. 1,
  7121. 0x20, DBTYPE_WSTR,
  7122. 0,0},
  7123. };
  7124. int TryBinding(
  7125. int iTest,
  7126. IAccessor * pIAccessor,
  7127. DBACCESSORFLAGS dwAccessorFlags,
  7128. ULONG cBindings,
  7129. ULONG iFirstBinding,
  7130. SCODE scExpected,
  7131. DBBINDSTATUS FailStatus = DBBINDSTATUS_OK)
  7132. {
  7133. HACCESSOR hAccessor = 0;
  7134. DBBINDSTATUS aBindStatus[20];
  7135. SCODE sc = pIAccessor->CreateAccessor( dwAccessorFlags,
  7136. cBindings,
  7137. &(aTestBindings[iFirstBinding]),
  7138. 0,
  7139. &hAccessor,
  7140. aBindStatus );
  7141. int iRet = 0;
  7142. if (scExpected != sc)
  7143. {
  7144. LogError( "IAccessor->CreateAccessor test %d returned 0x%x (expected 0x%x)\n",
  7145. iTest,
  7146. sc,
  7147. scExpected );
  7148. iRet = 1;
  7149. }
  7150. if ((SUCCEEDED(sc) || DB_E_ERRORSOCCURRED == sc) &&
  7151. DBBINDSTATUS_OK != FailStatus)
  7152. {
  7153. for (unsigned i=0; i<cBindings; i++)
  7154. {
  7155. if (aBindStatus[i] == FailStatus)
  7156. break;
  7157. }
  7158. if (i == cBindings)
  7159. {
  7160. LogError( "IAccessor->CreateAccessor test %d returned DBBINDSTATUS 0x%x (expected 0x%x)\n",
  7161. iTest,
  7162. aBindStatus[0],
  7163. FailStatus );
  7164. iRet = 1;
  7165. }
  7166. }
  7167. if (! FAILED(sc))
  7168. pIAccessor->ReleaseAccessor( hAccessor, 0);
  7169. return iRet;
  7170. } //TryBinding
  7171. void BindingTest( IUnknown* pUnk, BOOL fICommand, BOOL fSequential )
  7172. {
  7173. LogProgress( " Accessor binding test\n" );
  7174. int fFailed = 0;
  7175. DBACCESSORFLAGS StdFlags = DBACCESSOR_ROWDATA;
  7176. IAccessor * pIAcc = 0;
  7177. SCODE sc = pUnk->QueryInterface( IID_IAccessor, (void **)&pIAcc);
  7178. if ( FAILED( sc ) || pIAcc == 0 )
  7179. {
  7180. LogFail( "QueryInterface for IAccessor returned 0x%lx\n", sc );
  7181. }
  7182. // regr test for bug #71492, check that we can QI to IConvertType
  7183. // from IAccessor
  7184. IConvertType * pICvtType = 0;
  7185. sc = pUnk->QueryInterface( IID_IConvertType, (void **)&pICvtType);
  7186. if ( FAILED( sc ) || pICvtType == 0 )
  7187. {
  7188. LogError( "QueryInterface for IConvertType returned 0x%lx\n", sc );
  7189. fFailed++;
  7190. }
  7191. else
  7192. {
  7193. pICvtType->Release();
  7194. }
  7195. sc = pIAcc->QueryInterface( IID_IConvertType, (void **)&pICvtType);
  7196. if ( FAILED( sc ) || pICvtType == 0 )
  7197. {
  7198. LogError( "QueryInterface for IConvertType from accessor returned 0x%lx\n", sc );
  7199. fFailed++;
  7200. }
  7201. else
  7202. {
  7203. pICvtType->Release();
  7204. }
  7205. SCODE scExpected = (fSequential & !fICommand) ? DB_E_ERRORSOCCURRED : S_OK;
  7206. DBBINDSTATUS BindStatExp = (fSequential & !fICommand) ?
  7207. DBBINDSTATUS_BADORDINAL :
  7208. DBBINDSTATUS_OK;
  7209. // Test the return value for a bad column ordinal
  7210. aTestBindings[0].iOrdinal = 0;
  7211. fFailed += TryBinding( 1, pIAcc, StdFlags, 1, 0, scExpected, BindStatExp);
  7212. scExpected = fICommand ? S_OK : DB_E_ERRORSOCCURRED;
  7213. BindStatExp = fICommand ? DBBINDSTATUS_OK : DBBINDSTATUS_BADORDINAL;
  7214. // Test the return value for another bad column ordinal
  7215. aTestBindings[0].iOrdinal = 1000;
  7216. fFailed += TryBinding( 2, pIAcc, StdFlags, 1, 0, scExpected, BindStatExp);
  7217. // Don't allow room for the I8 to be returned
  7218. // But that's ok! fixed-len fields are allowed to pass bogus
  7219. // values for length
  7220. fFailed += TryBinding( 3, pIAcc, StdFlags, 1, 1, S_OK );
  7221. // bogus accessor flags (no bits on, and unused bits turned on)
  7222. fFailed += TryBinding( 4, pIAcc, 0, 1, 1, DB_E_BADACCESSORFLAGS );
  7223. fFailed += TryBinding( 5, pIAcc, DBACCESSOR_ROWDATA|(DBACCESSOR_OPTIMIZED<<1), 1, 1, DB_E_BADACCESSORFLAGS );
  7224. // null binding array
  7225. fFailed += TryBinding( 6, pIAcc, StdFlags, 0, 1, DB_E_NULLACCESSORNOTSUPPORTED );
  7226. // ofs doesn't support Param accessors (yet)
  7227. fFailed += TryBinding( 7, pIAcc, DBACCESSOR_PARAMETERDATA, 1, 1, DB_E_BADACCESSORFLAGS ); //E_NOTIMPL );
  7228. #if 0 // Replace these with some other test...
  7229. // ofs doesn't support writable accessors
  7230. fFailed += TryBinding( 8, pIAcc, DBACCESSOR_ROWDATA, 1, 1, DB_E_ACCESSVIOLATION );
  7231. #endif //
  7232. // ofs doesn't support passbyref accessors
  7233. fFailed += TryBinding( 9, pIAcc, DBACCESSOR_ROWDATA|DBACCESSOR_PASSBYREF, 1, 1, DB_E_BYREFACCESSORNOTSUPPORTED );
  7234. // bogus dbcolumnpart -- none of the valid bits turned on
  7235. fFailed += TryBinding( 10, pIAcc, StdFlags, 1, 2, DB_E_ERRORSOCCURRED, DBBINDSTATUS_BADBINDINFO );
  7236. // just ask for status -- not for data too
  7237. fFailed += TryBinding( 11, pIAcc, StdFlags, 1, 3, S_OK );
  7238. // bad alignment for output data -- No longer fatal.
  7239. fFailed += TryBinding( 12, pIAcc, StdFlags, 1, 4, S_OK );
  7240. // overlap value and status output fields
  7241. fFailed += TryBinding( 13, pIAcc, StdFlags, 1, 5, DB_E_ERRORSOCCURRED, DBBINDSTATUS_BADBINDINFO );
  7242. // make sure each of the two duplicate bindings used below is ok by itself
  7243. fFailed += TryBinding( 14, pIAcc, StdFlags, 1, 6, S_OK );
  7244. fFailed += TryBinding( 15, pIAcc, StdFlags, 1, 7, S_OK );
  7245. // overlap value fields in two bindings
  7246. fFailed += TryBinding( 16, pIAcc, StdFlags, 2, 6, DB_E_ERRORSOCCURRED, DBBINDSTATUS_BADBINDINFO );
  7247. // supply ITypeInfo field
  7248. fFailed += TryBinding( 17, pIAcc, StdFlags, 1, 8, DB_E_ERRORSOCCURRED, DBBINDSTATUS_BADBINDINFO );
  7249. // direct bind to GUID type
  7250. fFailed += TryBinding( 18, pIAcc, StdFlags, 1, 9, S_OK );
  7251. // unsupported byref binding
  7252. fFailed += TryBinding( 19, pIAcc, StdFlags, 1, 10, DB_E_ERRORSOCCURRED, DBBINDSTATUS_BADBINDINFO ); //danleg changed hraccess... UNSUPPORTEDCONVERSION );
  7253. // unsupported HTML flag
  7254. fFailed += TryBinding( 20, pIAcc, StdFlags, 1, 11, DB_E_ERRORSOCCURRED, DBBINDSTATUS_BADBINDINFO );
  7255. // unknown dwFlags field
  7256. fFailed += TryBinding( 21, pIAcc, StdFlags, 1, 12, DB_E_ERRORSOCCURRED, DBBINDSTATUS_BADBINDINFO );
  7257. cFailures += fFailed;
  7258. pIAcc->Release();
  7259. #if !defined(UNIT_TEST)
  7260. if (fFailed) {
  7261. pUnk->Release();
  7262. Fail();
  7263. }
  7264. #endif // !UNIT_TEST
  7265. } //BindingTest
  7266. void TestIAccessorOnCommand( ICommandTree * pCmdTree )
  7267. {
  7268. DBID aDbCols[cBasicTestCols];
  7269. aDbCols[0] = psClassid;
  7270. aDbCols[1] = psSize;
  7271. aDbCols[2] = psWriteTime;
  7272. aDbCols[3] = psAttr;
  7273. aDbCols[4] = psName;
  7274. aDbCols[5] = psPath;
  7275. aDbCols[6] = psSelf;
  7276. HACCESSOR hAccessor = MapColumns( pCmdTree,
  7277. cBasicTestCols,
  7278. aBasicTestCols,
  7279. aDbCols,
  7280. FALSE );
  7281. //
  7282. // Clean up.
  7283. //
  7284. ReleaseAccessor( pCmdTree, hAccessor);
  7285. }
  7286. #define MAX_BOOKMARK_LENGTH 16
  7287. DBBINDING aMoveTestCols[] =
  7288. {
  7289. // the iOrdinal field is filled out after the cursor is created
  7290. {
  7291. 0,
  7292. sizeof DBLENGTH,
  7293. 0,
  7294. 0,
  7295. 0,0,0,
  7296. DBPART_VALUE|DBPART_LENGTH,
  7297. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  7298. MAX_BOOKMARK_LENGTH,
  7299. 0, DBTYPE_BYTES,
  7300. 0, 0},
  7301. };
  7302. const ULONG cMoveTestCols = sizeof aMoveTestCols / sizeof aMoveTestCols[0];
  7303. struct BookmarkBinding {
  7304. DBLENGTH cbBmk;
  7305. BYTE abBmk[MAX_BOOKMARK_LENGTH];
  7306. };
  7307. BookmarkBinding aBmks[21];
  7308. HACCESSOR hBmkAccessor = 0;
  7309. //+-------------------------------------------------------------------------
  7310. //
  7311. // Function: GetBookmarks, public
  7312. //
  7313. // Synopsis: Retrieve bookmarks into the global bookmarks array
  7314. //
  7315. // Effects: aBmks is loaded with bookmarks, one for each row
  7316. //
  7317. // Arguments: [pRowset] - a pointer to IRowsetLocate
  7318. // [cRows] - nuumber of HROWs in the array
  7319. // [phRows] - a pointer to the HROWs array
  7320. //
  7321. // Returns: 0/1 - count of failures
  7322. //
  7323. // Notes: Assumes hBmkAccessor is bound to the rowset for
  7324. // retrieving into the BookmarkBinding struct.
  7325. //
  7326. // History: 30 Mar 1995 AlanW Created
  7327. //
  7328. //--------------------------------------------------------------------------
  7329. int GetBookmarks(
  7330. IRowsetLocate * pRowset,
  7331. DBCOUNTITEM cRows,
  7332. HROW * phRows )
  7333. {
  7334. int fFailed = 0;
  7335. SCODE sc;
  7336. for (unsigned i=0; i<cRows; i++)
  7337. {
  7338. sc = pRowset->GetData(phRows[i], hBmkAccessor, &aBmks[i]);
  7339. if (FAILED(sc) || DB_S_ERRORSOCCURRED == sc)
  7340. {
  7341. if (! fFailed)
  7342. LogError( "IRowset::GetData for bookmark failed 0x%x\n", sc );
  7343. fFailed++;
  7344. }
  7345. }
  7346. if (fFailed)
  7347. LogError(" %d/%d failures\n", fFailed, cRows);
  7348. return fFailed != 0;
  7349. }
  7350. //+-------------------------------------------------------------------------
  7351. //
  7352. // Function: CheckHrowIdentity, private
  7353. //
  7354. // Synopsis: Check for hrow identity among two arrays of HROWs
  7355. //
  7356. // Arguments: [pRowsetIdentity] - if non-zero, a pointer to an
  7357. // IRowsetIdentity for comparing the HROWs.
  7358. // [lOffset] - offset of matching rows in the two arrays.
  7359. // Positive if second array is shifted from first,
  7360. // negative otherwise.
  7361. // [cRows1] - count of rows in first array
  7362. // [phRows1] - pointer to HROWs, first array
  7363. // [cRows2] - count of rows in second array
  7364. // [phRows2] - pointer to HROWs, second array
  7365. //
  7366. // Returns: int - error count
  7367. //
  7368. // Notes:
  7369. //
  7370. // History: 03 Apr 95 AlanW Created
  7371. //
  7372. //--------------------------------------------------------------------------
  7373. int CheckHrowIdentity(
  7374. IRowsetIdentity * pRowsetIdentity,
  7375. DBROWCOUNT lOffset,
  7376. DBCOUNTITEM cRows1,
  7377. HROW * phRows1,
  7378. DBCOUNTITEM cRows2,
  7379. HROW * phRows2
  7380. ) {
  7381. int fFailed = 0;
  7382. SCODE sc;
  7383. DBROWCOUNT o1 = 0, o2 = 0;
  7384. DBCOUNTITEM cRows = min(cRows1, cRows2);
  7385. if (lOffset < 0)
  7386. {
  7387. o1 = -lOffset;
  7388. if (cRows1 - o1 < cRows)
  7389. cRows = cRows1 - o1;
  7390. }
  7391. else if (lOffset > 0)
  7392. {
  7393. o2 = lOffset;
  7394. if (cRows2 - o2 < cRows)
  7395. cRows = cRows2 - o2;
  7396. }
  7397. for (unsigned i=0; i<cRows; i++)
  7398. {
  7399. int fHrowEqual = 0;
  7400. // Compare HROWs for identity
  7401. if (pRowsetIdentity)
  7402. {
  7403. sc = pRowsetIdentity->IsSameRow(phRows1[i+o1], phRows2[i+o2]);
  7404. if (sc == S_OK)
  7405. fHrowEqual = 1;
  7406. else if (sc == S_FALSE)
  7407. fHrowEqual = 0;
  7408. else
  7409. {
  7410. LogError("IRowsetIdentity->IsSameRow returned %x\n", sc);
  7411. fFailed++;
  7412. fHrowEqual = 1; // only one error for this
  7413. }
  7414. }
  7415. else
  7416. fHrowEqual = (phRows1[i+o1] == phRows2[i+o2]);
  7417. if (! fHrowEqual)
  7418. {
  7419. LogError( "Hrows didn't compare for equality (used identity %d), %x %x\n",
  7420. ( 0 != pRowsetIdentity ), phRows1[i+o1], phRows2[i+o2] );
  7421. fFailed++;
  7422. }
  7423. if (o1 == o2 || phRows1 == phRows2)
  7424. continue;
  7425. // Now compare two which should be unequal
  7426. if (pRowsetIdentity)
  7427. {
  7428. sc = pRowsetIdentity->IsSameRow(phRows1[i], phRows2[i]);
  7429. if (sc == S_OK)
  7430. fHrowEqual = 1;
  7431. else if (sc == S_FALSE)
  7432. fHrowEqual = 0;
  7433. else
  7434. {
  7435. LogError("IRowsetIdentity->IsSameRow (2) returned %x\n", sc);
  7436. fFailed++;
  7437. fHrowEqual = 1; // only one error for this
  7438. }
  7439. }
  7440. else
  7441. fHrowEqual = (phRows1[i] == phRows2[i]);
  7442. if (fHrowEqual)
  7443. {
  7444. LogError("Different Hrows compared equal, %x %x\n",
  7445. phRows1[i], phRows2[i]);
  7446. fFailed++;
  7447. }
  7448. }
  7449. return fFailed;
  7450. }
  7451. //+-------------------------------------------------------------------------
  7452. //
  7453. // Function: MoveTest, public
  7454. //
  7455. // Synopsis: Test IRowsetLocate and IRowsetScroll methods
  7456. //
  7457. // Arguments: [pRowset] - a rowset supporting IRowsetLocate and
  7458. // optionally IRowsetScroll
  7459. // [hChapt] - rowset chapter if chaptered
  7460. //
  7461. // Returns: Nothing, exits if test error
  7462. //
  7463. // Notes: IRowsetLocate tests:
  7464. // QI to IRowsetLocate
  7465. // QI to IRowsetIdentity
  7466. // Bind to bookmark column
  7467. // Compare bookmarks with standard bookmark combinations
  7468. // Move to beginning and fetch
  7469. // Get bookmarks for fetched rows
  7470. // Compare bookmarks for first and second rows
  7471. // Fetch starting at second row
  7472. // Check bookmark equivalence for overlapping rows
  7473. // Check HROW identity for overlapping rows
  7474. // Move to end and fetch, check cRowsReturned and status
  7475. // Move after end and fetch, check cRowsReturned and status
  7476. //
  7477. // IRowsetScroll tests:
  7478. // QI to IRowsetScroll
  7479. // Scroll to 50% and fetch, check GetApproximatePosition
  7480. // Scroll to 14/27 and fetch, compare rows from 50% fetch
  7481. // Scroll to 14/13, check for error
  7482. // Check GetApproximatePosition with std bookmarks
  7483. //
  7484. // History: 16 Aug 94 AlanW Created
  7485. // 02 Apr 95 AlanW Updated for ole-db phase 3, bookmark
  7486. // bindings.
  7487. //
  7488. //--------------------------------------------------------------------------
  7489. BookmarkBinding FirstRowBmk;
  7490. BookmarkBinding SecondRowBmk;
  7491. BookmarkBinding LastRowBmk;
  7492. BookmarkBinding PenultimateRowBmk;
  7493. const long cLocateTest = 7;
  7494. const long cLocateTest2 = 9;
  7495. void MoveTest(
  7496. IRowset * pRowset, HCHAPTER hChapt
  7497. ) {
  7498. int fFailed = 0;
  7499. if (hChapt == DB_NULL_HCHAPTER)
  7500. LogProgress( " IRowsetLocate test\n" );
  7501. IRowsetLocate * pRowsetLocate = 0;
  7502. SCODE sc = pRowset->QueryInterface(IID_IRowsetLocate,
  7503. (void **)&pRowsetLocate);
  7504. if (FAILED(sc) || pRowsetLocate == 0) {
  7505. LogFail("QueryInterface to IRowsetLocate failed\n");
  7506. }
  7507. IRowsetIdentity * pRowsetIdentity = 0;
  7508. sc = pRowset->QueryInterface(IID_IRowsetIdentity,
  7509. (void **)&pRowsetIdentity);
  7510. if (FAILED(sc) && (sc != E_NOINTERFACE || pRowsetIdentity != 0)) {
  7511. LogError("QueryInterface to IRowsetIdentity failed (%x)\n", sc);
  7512. pRowsetIdentity = 0;
  7513. fFailed++;
  7514. }
  7515. BOOL fCompareOrdered = GetBooleanProperty( pRowset, DBPROP_ORDEREDBOOKMARKS );
  7516. BOOL fBookmarkBound = FALSE;
  7517. // need to know how many rows in the chapter total, so that tests
  7518. // below can be relaxed if there are just a few.
  7519. DBCOUNTITEM cTableRows;
  7520. IRowsetScroll * pIRowsetScroll = 0;
  7521. SCODE sca = pRowset->QueryInterface(IID_IRowsetScroll,(void **) &pIRowsetScroll );
  7522. if ( FAILED( sca ) )
  7523. {
  7524. LogError( "IRowset::qi for rowsetscroll returned 0x%lx\n", sca );
  7525. fFailed++;
  7526. }
  7527. sca = pIRowsetScroll->GetApproximatePosition(hChapt,
  7528. 0,0, 0, &cTableRows);
  7529. if ( FAILED( sca ) )
  7530. {
  7531. LogError( "IRowsetScroll::GetApproximatePosition returned 0x%lx\n", sca );
  7532. fFailed++;
  7533. }
  7534. if (fVerbose > 1)
  7535. LogProgress(" Movable rowset has %d rows\n",cTableRows);
  7536. pIRowsetScroll->Release();
  7537. //
  7538. // Get the column number for the standard bookmark if available
  7539. //
  7540. hBmkAccessor = MapColumns(pRowset, 1, aMoveTestCols, &psBookmark);
  7541. fBookmarkBound = TRUE;
  7542. if ( aMoveTestCols[0].iOrdinal != 0 )
  7543. {
  7544. LogError( "Bookmark column is not ordinal 0 ( = %d)\n",
  7545. aMoveTestCols[0].iOrdinal );
  7546. fFailed++;
  7547. }
  7548. HROW* phRows = 0;
  7549. DBROWCOUNT cRowsRequested = 1000;
  7550. DBCOUNTITEM cRowsReturned = 0;
  7551. //
  7552. // Fetch 1000 rows from the beginning of the rowset.
  7553. //
  7554. sc = pRowsetLocate->GetRowsAt( 0, hChapt, 1, &bmkFirst, 0,
  7555. cRowsRequested, &cRowsReturned, &phRows);
  7556. if ( FAILED( sc ) )
  7557. {
  7558. LogError( "IRowsetLocate->GetRowsAt(1000) returned 0x%x\n", sc );
  7559. fFailed++;
  7560. }
  7561. else if (sc != DB_S_ENDOFROWSET &&
  7562. cRowsReturned != (DBCOUNTITEM) cRowsRequested)
  7563. {
  7564. LogError( "IRowsetLocate->GetRowsAt J returned %d of %d rows\n",
  7565. cRowsReturned, cRowsRequested);
  7566. fFailed++;
  7567. }
  7568. if (phRows)
  7569. FreeHrowsArray( pRowsetLocate, cRowsReturned, &phRows);
  7570. //
  7571. // Fetch 10 rows from the beginning of the rowset.
  7572. //
  7573. cRowsRequested = 10;
  7574. sc = pRowsetLocate->GetRowsAt(0, hChapt, 1,&bmkFirst, 0,
  7575. cRowsRequested, &cRowsReturned, &phRows);
  7576. if ( FAILED( sc ) )
  7577. {
  7578. LogError( "IRowsetLocate->GetRowsAt K returned 0x%x\n", sc );
  7579. fFailed++;
  7580. }
  7581. else if (sc != DB_S_ENDOFROWSET &&
  7582. cRowsReturned != (DBCOUNTITEM) cRowsRequested)
  7583. {
  7584. LogError( "IRowsetLocate->GetRowsAt L returned %d of %d rows\n",
  7585. cRowsReturned, cRowsRequested);
  7586. fFailed++;
  7587. }
  7588. HROW* phRows2 = 0;
  7589. DBCOUNTITEM cRowsReturned2 = 0;
  7590. DWORD dwCompare = 0xFFFFFFFF;
  7591. if (fBookmarkBound)
  7592. {
  7593. fFailed += GetBookmarks( pRowsetLocate, cRowsReturned, phRows);
  7594. FirstRowBmk = aBmks[0];
  7595. if ( cRowsReturned > 1 )
  7596. SecondRowBmk = aBmks[1];
  7597. else
  7598. SecondRowBmk.cbBmk = 0;
  7599. sc = pRowsetLocate->Compare(hChapt, 1,&bmkFirst,
  7600. FirstRowBmk.cbBmk, FirstRowBmk.abBmk, &dwCompare);
  7601. if ( FAILED( sc ) )
  7602. {
  7603. LogError( "IRowsetLocate->Compare of DBBMK_FIRST returned 0x%x\n", sc );
  7604. fFailed++;
  7605. }
  7606. else if (dwCompare != DBCOMPARE_NE)
  7607. {
  7608. // DBBMK_FIRST is not the same as the first row's bookmark
  7609. LogError( "Compare of DBBMK_FIRST and returned bookmark not "
  7610. "notequal (%d)\n", dwCompare );
  7611. fFailed++;
  7612. }
  7613. if (cRowsReturned >= 2)
  7614. {
  7615. sc = pRowsetLocate->Compare(hChapt,
  7616. FirstRowBmk.cbBmk, FirstRowBmk.abBmk,
  7617. SecondRowBmk.cbBmk, SecondRowBmk.abBmk,
  7618. &dwCompare);
  7619. if ( FAILED( sc ) )
  7620. {
  7621. LogError( "IRowsetLocate->Compare returned 0x%x\n", sc );
  7622. fFailed++;
  7623. }
  7624. else if ((fCompareOrdered && dwCompare != DBCOMPARE_LT) ||
  7625. (! fCompareOrdered && dwCompare != DBCOMPARE_NE))
  7626. {
  7627. LogError( "Compare of first and second returned bookmarks not "
  7628. "%s (%d)\n",
  7629. fCompareOrdered? "less than" : "not equal",
  7630. dwCompare );
  7631. fFailed++;
  7632. }
  7633. //
  7634. // Fetch 10 rows starting at the second row. Compare
  7635. // the overlapping returned HROWs.
  7636. //
  7637. sc = pRowsetLocate->GetRowsAt(0, hChapt,
  7638. SecondRowBmk.cbBmk, SecondRowBmk.abBmk, 0,
  7639. cRowsRequested, &cRowsReturned2, &phRows2);
  7640. if ( FAILED( sc ) )
  7641. {
  7642. LogError("IRowsetLocate->GetRowsAt (2) returned 0x%x\n", sc );
  7643. fFailed++;
  7644. }
  7645. else if (sc != DB_S_ENDOFROWSET &&
  7646. cRowsReturned2 != (DBCOUNTITEM) cRowsRequested)
  7647. {
  7648. LogError("IRowsetLocate->GetRowsAt (2) returned %d of %d rows\n",
  7649. cRowsReturned2, cRowsRequested);
  7650. fFailed++;
  7651. }
  7652. else if (sc == DB_S_ENDOFROWSET &&
  7653. cRowsReturned2 < (DBCOUNTITEM) cRowsRequested &&
  7654. cRowsReturned2 != cRowsReturned - 1)
  7655. {
  7656. LogError("IRowsetLocate->GetRowsAt (2) returned inconsistent row count, %d - %d\n",
  7657. cRowsReturned2, cRowsReturned);
  7658. fFailed++;
  7659. }
  7660. fFailed += CheckHrowIdentity(pRowsetIdentity, -1,
  7661. cRowsReturned, phRows,
  7662. cRowsReturned2, phRows2);
  7663. fFailed += GetBookmarks( pRowsetLocate, 1, phRows2);
  7664. sc = pRowsetLocate->Compare(hChapt,
  7665. SecondRowBmk.cbBmk, SecondRowBmk.abBmk,
  7666. aBmks[0].cbBmk, aBmks[0].abBmk,
  7667. &dwCompare);
  7668. if ( FAILED( sc ) )
  7669. {
  7670. LogError( "IRowsetLocate->Compare returned 0x%x\n", sc );
  7671. fFailed++;
  7672. }
  7673. else if (dwCompare != DBCOMPARE_EQ)
  7674. {
  7675. LogError( "Compare of second row bookmarks not equal (%d)\n",
  7676. dwCompare );
  7677. fFailed++;
  7678. }
  7679. FreeHrowsArray( pRowsetLocate, cRowsReturned2, &phRows2);
  7680. }
  7681. }
  7682. FreeHrowsArray( pRowsetLocate, cRowsReturned, &phRows);
  7683. //
  7684. // Fetch at end, 3 cases:
  7685. // Last - 1 expect 2 rows returned
  7686. // Last + 0 expect 1 row returned
  7687. // Last + 1 expect 0 rows
  7688. //
  7689. sc = pRowsetLocate->GetRowsAt(0, hChapt, 1,&bmkLast, -1,
  7690. cRowsRequested, &cRowsReturned, &phRows);
  7691. PenultimateRowBmk.cbBmk = 0;
  7692. LastRowBmk.cbBmk = 0;
  7693. if ( FAILED( sc ) )
  7694. {
  7695. LogError( "IRowsetLocate->GetRowsAt M returned 0x%x\n", sc );
  7696. fFailed++;
  7697. }
  7698. else if (sc != DB_S_ENDOFROWSET ||
  7699. (cRowsReturned != 2 && cTableRows >= 2 ) )
  7700. {
  7701. LogError( "IRowsetLocate->GetRowsAt N returned %d rows at DBBMK_LAST - 1, sc: %lx\n",
  7702. cRowsReturned, sc );
  7703. fFailed++;
  7704. }
  7705. else if (fBookmarkBound && cRowsReturned >= 2)
  7706. {
  7707. fFailed += GetBookmarks( pRowsetLocate, cRowsReturned, phRows);
  7708. LastRowBmk = aBmks[1];
  7709. PenultimateRowBmk = aBmks[0];
  7710. sc = pRowsetLocate->Compare(hChapt, 1,&bmkLast,
  7711. LastRowBmk.cbBmk, LastRowBmk.abBmk, &dwCompare);
  7712. if ( FAILED( sc ) )
  7713. {
  7714. LogError( "IRowsetLocate->Compare of DBBMK_LAST returned 0x%x\n", sc );
  7715. fFailed++;
  7716. }
  7717. else if (dwCompare != DBCOMPARE_NE)
  7718. {
  7719. // DBBMK_LAST is not the same as the last row's bookmark
  7720. LogError( "Compare of DBBMK_LAST and returned bookmark not "
  7721. "notequal (%d)\n", dwCompare );
  7722. fFailed++;
  7723. }
  7724. if (cRowsReturned >= 2)
  7725. {
  7726. sc = pRowsetLocate->Compare(hChapt,
  7727. LastRowBmk.cbBmk, LastRowBmk.abBmk,
  7728. aBmks[0].cbBmk, aBmks[0].abBmk,
  7729. &dwCompare);
  7730. if ( FAILED( sc ) )
  7731. {
  7732. LogError( "IRowsetLocate->Compare returned 0x%x\n", sc );
  7733. fFailed++;
  7734. }
  7735. else if ((fCompareOrdered && dwCompare != DBCOMPARE_GT) ||
  7736. (! fCompareOrdered && dwCompare != DBCOMPARE_NE))
  7737. {
  7738. LogError( "Compare of last and penultimate returned bookmarks not "
  7739. "%s (%d)\n",
  7740. fCompareOrdered? "greater than" : "not equal",
  7741. dwCompare );
  7742. fFailed++;
  7743. }
  7744. }
  7745. }
  7746. FreeHrowsArray( pRowsetLocate, cRowsReturned, &phRows);
  7747. sc = pRowsetLocate->GetRowsAt(0, hChapt, 1,&bmkLast, 0,
  7748. cRowsRequested, &cRowsReturned, &phRows);
  7749. if ( FAILED( sc ) )
  7750. {
  7751. LogError( "IRowsetLocate->GetRowsAt O returned 0x%x\n", sc );
  7752. fFailed++;
  7753. }
  7754. else if (sc != DB_S_ENDOFROWSET ||
  7755. cRowsReturned != 1 )
  7756. {
  7757. LogError( "IRowsetLocate->GetRowsAt P returned %d rows at DBBMK_LAST, sc: %lx\n",
  7758. cRowsReturned, sc );
  7759. fFailed++;
  7760. }
  7761. FreeHrowsArray( pRowsetLocate, cRowsReturned, &phRows);
  7762. sc = pRowsetLocate->GetRowsAt(0, hChapt, 1,&bmkLast, 1,
  7763. cRowsRequested, &cRowsReturned, &phRows);
  7764. if ( FAILED( sc ) /* && DB_E_BADSTARTPOSITION != sc */ )
  7765. {
  7766. LogError( "IRowsetLocate->GetRowsAt Q returned 0x%x\n", sc );
  7767. fFailed++;
  7768. }
  7769. else if ( sc != DB_S_ENDOFROWSET || cRowsReturned != 0 )
  7770. {
  7771. LogError( "IRowsetLocate->GetRowsAt R returned sc 0x%x, %d rows at DBBMK_LAST + 1\n",
  7772. sc, cRowsReturned );
  7773. fFailed++;
  7774. }
  7775. if (0 == cRowsReturned &&
  7776. phRows != 0) // Bug #7668 (part)
  7777. {
  7778. LogError("HROW array allocated without returned rows\n");
  7779. fFailed++;
  7780. }
  7781. FreeHrowsArray( pRowsetLocate, cRowsReturned, &phRows);
  7782. // OLE-DB spec. bug #1007
  7783. sc = pRowsetLocate->GetRowsAt(0, hChapt, 1,&bmkLast, 0,
  7784. 1, &cRowsReturned, &phRows);
  7785. if ( FAILED( sc ) )
  7786. {
  7787. LogError( "IRowsetLocate->GetRowsAt S returned 0x%x\n", sc );
  7788. fFailed++;
  7789. }
  7790. else if (sc == DB_S_ENDOFROWSET ||
  7791. cRowsReturned != 1 )
  7792. {
  7793. LogError( "IRowsetLocate->GetRowsAt T returned ENDOFROWSET inappropriately"
  7794. " at DBBMK_LAST, %d\n",
  7795. cRowsReturned );
  7796. fFailed++;
  7797. }
  7798. FreeHrowsArray( pRowsetLocate, cRowsReturned, &phRows);
  7799. if ( cTableRows > cLocateTest2 )
  7800. {
  7801. sc = pRowsetLocate->GetRowsAt(0, hChapt, 1,&bmkLast, -cLocateTest,
  7802. cLocateTest + 1, &cRowsReturned, &phRows);
  7803. if ( FAILED( sc ) )
  7804. {
  7805. LogError("IRowsetLocate->GetRowsAt U (end-%d) returned 0x%x\n", cLocateTest,
  7806. sc );
  7807. fFailed++;
  7808. }
  7809. else if (fBookmarkBound)
  7810. fFailed += GetBookmarks( pRowsetLocate, cRowsReturned, phRows);
  7811. sc = pRowsetLocate->GetRowsAt(0, hChapt, 1,&bmkLast, -cLocateTest2,
  7812. cLocateTest2 + 1, &cRowsReturned2, &phRows2);
  7813. if ( FAILED( sc ) )
  7814. {
  7815. LogError("IRowsetLocate->GetRowsAt(2) V (end-%d) returned 0x%x\n",
  7816. cLocateTest2, sc );
  7817. fFailed++;
  7818. }
  7819. else if ( (cRowsReturned <= cLocateTest && cRowsReturned2 != cRowsReturned) ||
  7820. (cRowsReturned == (cLocateTest+1) && cRowsReturned2 <= cLocateTest) )
  7821. {
  7822. if ( sc != DB_S_ENDOFROWSET )
  7823. {
  7824. LogError("IRowsetLocate->GetRowsAt W (end-%d) returned %d rows\n",
  7825. cLocateTest2, cRowsReturned2 );
  7826. fFailed++;
  7827. }
  7828. }
  7829. else
  7830. {
  7831. fFailed += CheckHrowIdentity( pRowsetIdentity,
  7832. cRowsReturned2 - cRowsReturned,
  7833. cRowsReturned, phRows,
  7834. cRowsReturned2, phRows2);
  7835. }
  7836. FreeHrowsArray( pRowsetLocate, cRowsReturned2, &phRows2);
  7837. FreeHrowsArray( pRowsetLocate, cRowsReturned, &phRows);
  7838. if (fBookmarkBound)
  7839. {
  7840. // Attempt to call GetRowsByBookmark with bookmarks we've collected.
  7841. const unsigned cBybmkTest = cLocateTest + 1 + 5 + 1;
  7842. DBBKMARK rgcbBookmarks[cBybmkTest];
  7843. BYTE* rgpBookmarks[cBybmkTest];
  7844. ULONG cBookmarks = 0;
  7845. for (unsigned i = 0; i<cRowsReturned; i++)
  7846. {
  7847. rgcbBookmarks[cBookmarks] = aBmks[i].cbBmk;
  7848. rgpBookmarks[cBookmarks] = &aBmks[i].abBmk[0];
  7849. cBookmarks++;
  7850. }
  7851. rgcbBookmarks[cBookmarks] = FirstRowBmk.cbBmk;
  7852. rgpBookmarks[cBookmarks++] = &FirstRowBmk.abBmk[0];
  7853. if ( 0 != SecondRowBmk.cbBmk )
  7854. {
  7855. rgcbBookmarks[cBookmarks] = SecondRowBmk.cbBmk;
  7856. rgpBookmarks[cBookmarks++] = &SecondRowBmk.abBmk[0];
  7857. }
  7858. if ( 0 != LastRowBmk.cbBmk )
  7859. {
  7860. rgcbBookmarks[cBookmarks] = LastRowBmk.cbBmk;
  7861. rgpBookmarks[cBookmarks++] = &LastRowBmk.abBmk[0];
  7862. }
  7863. if ( 0 != PenultimateRowBmk.cbBmk )
  7864. {
  7865. rgcbBookmarks[cBookmarks] = PenultimateRowBmk.cbBmk;
  7866. rgpBookmarks[cBookmarks++] = &PenultimateRowBmk.abBmk[0];
  7867. }
  7868. rgcbBookmarks[cBookmarks] = FirstRowBmk.cbBmk;
  7869. rgpBookmarks[cBookmarks++] = &FirstRowBmk.abBmk[0];
  7870. DBROWSTATUS BmkErrors[cBybmkTest];
  7871. HROW hRows[cBybmkTest];
  7872. sc = pRowsetLocate->GetRowsByBookmark( hChapt,
  7873. cBookmarks, rgcbBookmarks,
  7874. (const BYTE **)rgpBookmarks,
  7875. hRows, BmkErrors);
  7876. if ( FAILED( sc ) )
  7877. {
  7878. LogError( "IRowsetLocate->GetRowsByBookmark returned 0x%x\n", sc );
  7879. fFailed++;
  7880. }
  7881. else if ( sc != S_OK )
  7882. {
  7883. LogError( "Not all rows returned from GetRowsByBookmark, sc = 0x%x"
  7884. "\t%d\n", sc, cBookmarks );
  7885. fFailed++;
  7886. }
  7887. else
  7888. {
  7889. fFailed += GetBookmarks( pRowsetLocate, cBookmarks, hRows);
  7890. }
  7891. ReleaseStaticHrows( pRowsetLocate, cBookmarks, hRows);
  7892. //
  7893. // Try with a bad bookmark; check that correct status and
  7894. // HROW are returned. Regression test for #80381.
  7895. //
  7896. unsigned iBadRow = cBookmarks / 2;
  7897. rgcbBookmarks[cBookmarks] = rgcbBookmarks[iBadRow];
  7898. rgpBookmarks[cBookmarks++] = rgpBookmarks[iBadRow];
  7899. rgcbBookmarks[iBadRow] = 1;
  7900. rgpBookmarks[iBadRow] = (BYTE *)&bmkFirst;
  7901. sc = pRowsetLocate->GetRowsByBookmark( hChapt,
  7902. cBookmarks, rgcbBookmarks,
  7903. (const BYTE **)rgpBookmarks,
  7904. hRows, BmkErrors);
  7905. if ( sc != DB_S_ERRORSOCCURRED )
  7906. {
  7907. LogError( "GetRowsByBookmark with special bookmark didn't give error, sc = 0x%x"
  7908. "\t%d\n", sc, cBookmarks );
  7909. fFailed++;
  7910. }
  7911. else if (hRows[iBadRow] != DB_NULL_HROW ||
  7912. BmkErrors[iBadRow] != DBROWSTATUS_E_INVALID)
  7913. {
  7914. LogError( "GetRowsByBookmark with special bookmark didn't give null hrow or correct status, "
  7915. "hrow = 0x%x\trs = 0x%x\n", hRows[iBadRow], BmkErrors[iBadRow] );
  7916. fFailed++;
  7917. }
  7918. ReleaseStaticHrows( pRowsetLocate, cBookmarks, hRows);
  7919. }
  7920. }
  7921. //-------------------------
  7922. //
  7923. // IRowsetScroll tests
  7924. //
  7925. //-------------------------
  7926. IRowsetScroll * pRowsetScroll;
  7927. sc = pRowset->QueryInterface(IID_IRowsetScroll,
  7928. (void **)&pRowsetScroll);
  7929. BOOL fScroll = SUCCEEDED(sc);
  7930. if (fScroll)
  7931. {
  7932. if (hChapt == DB_NULL_HCHAPTER)
  7933. LogProgress( " IRowsetScroll test\n" );
  7934. DBCOUNTITEM ulNum = 1, cRows = 0;
  7935. BookmarkBinding HalfRowBmk;
  7936. /***
  7937. Additional Scroll tests to be coded up:
  7938. Scroll to 10%, 20%, 30%..., GetBookmark, GetPosition and check
  7939. Try bad fractions, 0/0, 101/100, fffffffe/ffffffff, etc.
  7940. ***/
  7941. //
  7942. // Try a simple scroll
  7943. //
  7944. cRowsRequested = 20;
  7945. sc = pRowsetScroll->GetRowsAtRatio(0, hChapt, 50, 100,
  7946. cRowsRequested, &cRowsReturned, &phRows);
  7947. if ( FAILED( sc ) )
  7948. {
  7949. LogError( "IRowset->GetRowsAtRatio returned 0x%x\n", sc );
  7950. fFailed++;
  7951. }
  7952. else if (sc != DB_S_ENDOFROWSET &&
  7953. cRowsReturned != (DBCOUNTITEM) cRowsRequested)
  7954. {
  7955. LogError( "IRowset->GetRowsAtRatio returned %d of %d rows\n",
  7956. cRowsReturned,
  7957. cRowsRequested);
  7958. fFailed++;
  7959. }
  7960. else if (fBookmarkBound)
  7961. {
  7962. fFailed += GetBookmarks(pRowsetScroll, cRowsReturned, phRows);
  7963. HalfRowBmk = aBmks[0];
  7964. sc = pRowsetScroll->GetApproximatePosition(hChapt,
  7965. HalfRowBmk.cbBmk, HalfRowBmk.abBmk,
  7966. &ulNum, &cRows);
  7967. if ( FAILED( sc ) )
  7968. {
  7969. LogError( "IRowset->GetApproximatePosition returned 0x%x\n", sc );
  7970. fFailed++;
  7971. }
  7972. else if (cRows == 0 ||
  7973. (ulNum-1 < ((cRows-1)*40)/100 || ulNum-1 > (cRows*60)/100))
  7974. {
  7975. LogError( "Scroll 50%%/GetApproximatePosition returned %d, %d\n",
  7976. ulNum, cRows );
  7977. fFailed++;
  7978. }
  7979. }
  7980. cRowsRequested = 10;
  7981. sc = pRowsetScroll->GetRowsAtRatio(0, hChapt, 14, 27,
  7982. cRowsRequested, &cRowsReturned2, &phRows2);
  7983. if ( FAILED( sc ) )
  7984. {
  7985. LogError( "IRowset->GetRowsAtRation 14/27 returned 0x%x\n", sc );
  7986. fFailed++;
  7987. }
  7988. else if (fBookmarkBound)
  7989. {
  7990. DBCOUNTITEM ulNum2 = 0;
  7991. fFailed += GetBookmarks(pRowsetScroll, cRowsReturned2, phRows2);
  7992. sc = pRowsetScroll->GetApproximatePosition( hChapt,
  7993. aBmks[0].cbBmk, aBmks[0].abBmk,
  7994. &ulNum2, &cRows);
  7995. if ( FAILED( sc ) )
  7996. {
  7997. LogError( "IRowset->GetApproximatePosition 14/27 returned 0x%x\n", sc );
  7998. fFailed++;
  7999. }
  8000. else if (cRows == 0 || ulNum > ulNum2)
  8001. {
  8002. LogError( "Scroll 51.8%%/GetApproximatePosition returned %d, %d, %d, total rows: %d\n",
  8003. ulNum, ulNum2, cRows, cTableRows );
  8004. fFailed++;
  8005. }
  8006. else if (ulNum != ulNum2)
  8007. {
  8008. sc = pRowsetLocate->Compare(hChapt,
  8009. HalfRowBmk.cbBmk, HalfRowBmk.abBmk,
  8010. aBmks[0].cbBmk, aBmks[0].abBmk,
  8011. &dwCompare);
  8012. if ( FAILED( sc ) )
  8013. {
  8014. LogError( "IRowsetLocate->Compare returned 0x%x\n", sc );
  8015. fFailed++;
  8016. }
  8017. else if ((fCompareOrdered && dwCompare != DBCOMPARE_LT) ||
  8018. (! fCompareOrdered && dwCompare != DBCOMPARE_NE))
  8019. {
  8020. LogError( "Compare of 50%% and 51.8%% returned bookmarks not "
  8021. "%s (%d)\n",
  8022. fCompareOrdered? "less than" : "not equal",
  8023. dwCompare );
  8024. fFailed++;
  8025. }
  8026. }
  8027. if ( ( ulNum2 - ulNum ) < (DBCOUNTITEM) cRowsRequested)
  8028. {
  8029. DBCOUNTITEM oRowDiff = ulNum - ulNum2;
  8030. fFailed += CheckHrowIdentity( pRowsetIdentity, oRowDiff,
  8031. cRowsReturned, phRows,
  8032. cRowsReturned2, phRows2);
  8033. }
  8034. }
  8035. FreeHrowsArray(pRowsetScroll, cRowsReturned2, &phRows2);
  8036. FreeHrowsArray(pRowsetScroll, cRowsReturned, &phRows);
  8037. static cTimesBadRatioTested = 0;
  8038. if ( cTimesBadRatioTested < 10 )
  8039. {
  8040. // limited to 10 tests of this because it causes an exception
  8041. // internally which slows the drt down unnecessarily
  8042. cTimesBadRatioTested++;
  8043. sc = pRowsetScroll->GetRowsAtRatio(0, hChapt, 14, 13,
  8044. cRowsRequested, &cRowsReturned, &phRows);
  8045. if ( sc != DB_E_BADRATIO )
  8046. {
  8047. LogError( "IRowset->GetRowsAtRatio returned 0x%x for invalid fraction\n",
  8048. sc );
  8049. fFailed++;
  8050. }
  8051. FreeHrowsArray(pRowsetScroll, cRowsReturned, &phRows);
  8052. }
  8053. sc = pRowsetScroll->GetRowsAtRatio(0, hChapt, 0, 100,
  8054. cRowsRequested, &cRowsReturned, &phRows);
  8055. if ( FAILED( sc ) )
  8056. {
  8057. LogError( "IRowset->GetRowsAtRatio, 0%% returned 0x%x\n", sc );
  8058. fFailed++;
  8059. }
  8060. else if (fBookmarkBound)
  8061. fFailed += GetBookmarks( pRowsetScroll, cRowsReturned, phRows);
  8062. FreeHrowsArray(pRowsetScroll, cRowsReturned, &phRows);
  8063. if (fBookmarkBound)
  8064. {
  8065. sc = pRowsetScroll->GetApproximatePosition( hChapt,
  8066. aBmks[0].cbBmk, aBmks[0].abBmk,
  8067. &ulNum, &cRows);
  8068. if ( FAILED( sc ) )
  8069. {
  8070. LogError( "IRowset->GetApproximatePosition 0%% returned 0x%x\n", sc );
  8071. fFailed++;
  8072. }
  8073. else if (cRows == 0 || ulNum != 1)
  8074. {
  8075. LogError( "GetApproximatePosition, first row returned %d, %d\n",
  8076. ulNum, cRows );
  8077. fFailed++;
  8078. }
  8079. }
  8080. if ( 0 == hChapt )
  8081. {
  8082. sc = pRowsetScroll->GetRowsAtRatio(0, hChapt, 100, 100,
  8083. cRowsRequested, &cRowsReturned, &phRows);
  8084. // if ( FAILED(sc) )
  8085. if (cRowsReturned != 0 || sc != DB_S_ENDOFROWSET)
  8086. {
  8087. LogError( "IRowsetScroll->GetRowsAtRatio 100%% returned sc: 0x%x, cRowsReturned: 0x%x\n",
  8088. sc, cRowsReturned );
  8089. fFailed++;
  8090. }
  8091. FreeHrowsArray(pRowsetScroll, cRowsReturned, &phRows);
  8092. }
  8093. sc = pRowsetScroll->GetApproximatePosition( hChapt,
  8094. 1, &bmkLast,
  8095. &ulNum, &cRows);
  8096. if ( FAILED( sc ) )
  8097. {
  8098. LogError( "IRowset->GetApproximatePosition DBBMK_LAST returned 0x%x\n", sc );
  8099. fFailed++;
  8100. }
  8101. else if (ulNum != cRows)
  8102. {
  8103. LogError( "GetApproximatePosition, last row returned %d, %d\n",
  8104. ulNum, cRows );
  8105. fFailed++;
  8106. }
  8107. pRowsetScroll->Release();
  8108. } // end if (fScroll)
  8109. cFailures += fFailed;
  8110. pRowsetLocate->Release();
  8111. if (fBookmarkBound)
  8112. ReleaseAccessor( pRowset, hBmkAccessor);
  8113. if (0 != pRowsetIdentity)
  8114. pRowsetIdentity->Release();
  8115. #if !defined(UNIT_TEST)
  8116. // if (fFailed) {
  8117. // pRowset->Release();
  8118. // Fail();
  8119. // }
  8120. #endif // !UNIT_TEST
  8121. return;
  8122. } //MoveTest
  8123. //+-------------------------------------------------------------------------
  8124. //
  8125. // Function: DeleteTest, public
  8126. //
  8127. // Synopsis: Check that row delete works correctly
  8128. //
  8129. // Returns: Nothing
  8130. //
  8131. // Notes: Duplication scenario for bug# 12282
  8132. //
  8133. // History: 18 May 1995 AlanW Created
  8134. //
  8135. //--------------------------------------------------------------------------
  8136. struct SDeleteTest
  8137. {
  8138. DBLENGTH cbName;
  8139. DBLENGTH cbPath;
  8140. DBROWSTATUS sName;
  8141. DBROWSTATUS sPath;
  8142. WCHAR awcName[40];
  8143. WCHAR awcPath[MAX_PATH+1];
  8144. };
  8145. DBBINDING aDeleteTestCols[] =
  8146. {
  8147. // the iOrdinal field is filled out after the cursor is created
  8148. { 0,
  8149. offsetof(SDeleteTest,awcName),
  8150. offsetof(SDeleteTest,cbName),
  8151. offsetof(SDeleteTest,sName),
  8152. 0,0,0,
  8153. ALLPARTS,
  8154. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  8155. 40 * sizeof (WCHAR),
  8156. 0, DBTYPE_WSTR,
  8157. 0,0,
  8158. },
  8159. { 0,
  8160. offsetof(SDeleteTest,awcPath),
  8161. offsetof(SDeleteTest,cbPath),
  8162. offsetof(SDeleteTest,sPath),
  8163. 0,0,0,
  8164. ALLPARTS,
  8165. DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM,
  8166. cbRowName,
  8167. 0, DBTYPE_WSTR,
  8168. 0,0,
  8169. },
  8170. };
  8171. const ULONG cDeleteTestCols = sizeof aDeleteTestCols / sizeof aDeleteTestCols[0];
  8172. void DeleteTest(BOOL fSequential)
  8173. {
  8174. LogProgress( "Delete function test with %s rowset\n",
  8175. fSequential ? "sequential" : "movable" );
  8176. WCHAR wcsTestSubDir[MAX_PATH];
  8177. wcscpy( wcsTestSubDir, wcsTestPath );
  8178. wcscat( wcsTestSubDir, L"\\DeleteTest." );
  8179. wcscat( wcsTestSubDir, fSequential ? L"1" : L"2" );
  8180. unsigned cchTestSubDir = wcslen(wcsTestSubDir);
  8181. //
  8182. // Get name, size and class id for *.*
  8183. //
  8184. CDbColumns cols(2);
  8185. cols.Add( psName, 0 );
  8186. cols.Add( psPath, 1 );
  8187. CDbSortSet ss(1);
  8188. if (! fSequential )
  8189. ss.Add(psName, QUERY_SORTASCEND, 0);
  8190. CDbCmdTreeNode * pCmdTree = FormQueryTree( 0, cols, &ss );
  8191. IRowset * pRowset = InstantiateRowset(
  8192. 0,
  8193. QUERY_DEEP, // Depth
  8194. wcsTestPath, // Scope
  8195. pCmdTree, // DBCOMMANDTREE
  8196. IID_IRowsetScroll); // IID of i/f to return
  8197. //
  8198. // Verify columns
  8199. //
  8200. CheckColumns( pRowset, cols );
  8201. if ( !WaitForCompletion( pRowset ) )
  8202. {
  8203. LogError( "DeleteTest query unsuccessful.\n" );
  8204. pRowset->Release();
  8205. Fail();
  8206. }
  8207. int fFailed = 0;
  8208. //
  8209. // Get an IRowsetScroll if possible.
  8210. //
  8211. DBCOUNTITEM cRows = 0;
  8212. IRowsetScroll * pIRowsetScroll = 0;
  8213. SCODE sc = pRowset->QueryInterface(IID_IRowsetScroll,(void **) &pIRowsetScroll );
  8214. if ( FAILED( sc ) && sc != E_NOINTERFACE )
  8215. {
  8216. LogError( "IRowset::qi for IRowsetScroll failed, 0x%x\n", sc );
  8217. cFailures++;
  8218. }
  8219. if (0 == pIRowsetScroll )
  8220. {
  8221. if (! fSequential)
  8222. {
  8223. LogError( "Non-sequential cursor does not support IRowsetScroll\n" );
  8224. cFailures++;
  8225. }
  8226. }
  8227. else
  8228. {
  8229. sc = pIRowsetScroll->GetApproximatePosition(0, 0,0, 0, &cRows);
  8230. if ( FAILED( sc ) )
  8231. {
  8232. LogError( "IRowset->GetApproximatePosition returned 0x%lx\n", sc );
  8233. cFailures++;
  8234. }
  8235. if ( cRows == 0 )
  8236. {
  8237. LogError( "Query failed to return data\n" );
  8238. pIRowsetScroll->Release();
  8239. pRowset->Release();
  8240. Fail();
  8241. }
  8242. }
  8243. //
  8244. // Patch the column index numbers with true numbers
  8245. //
  8246. DBID aDbCols[cDeleteTestCols];
  8247. aDbCols[0] = psName;
  8248. aDbCols[1] = psPath;
  8249. HACCESSOR hAccessor = MapColumns(pRowset, cDeleteTestCols, aDeleteTestCols, aDbCols);
  8250. DBCOUNTITEM totalRowsFetched = 0;
  8251. DBCOUNTITEM cRowsReturned = 0;
  8252. HROW ahRows[10];
  8253. HROW* phRows = ahRows;
  8254. BOOL fDidDelete = FALSE;
  8255. BOOL fDidDirDelete = FALSE;
  8256. do
  8257. {
  8258. sc = pRowset->GetNextRows(0, 0, 1, &cRowsReturned, &phRows);
  8259. if ( FAILED( sc ) )
  8260. {
  8261. LogError( "IRowset->GetNextRows returned 0x%x\n", sc );
  8262. pRowset->Release();
  8263. Fail();
  8264. }
  8265. if (sc != DB_S_ENDOFROWSET &&
  8266. cRowsReturned != 1)
  8267. {
  8268. LogError( "IRowset->GetNextRows returned %d of %d rows,"
  8269. " status (%x) != DB_S_ENDOFROWSET\n",
  8270. cRowsReturned, 1,
  8271. sc);
  8272. #if defined (UNIT_TEST)
  8273. cFailures++;
  8274. #else // defined(UNIT_TEST)
  8275. pRowset->Release();
  8276. Fail();
  8277. #endif // defined(UNIT_TEST)
  8278. }
  8279. totalRowsFetched += cRowsReturned;
  8280. if ( (0 != pIRowsetScroll ) &&
  8281. (totalRowsFetched > cRows) )
  8282. {
  8283. //
  8284. // check that no more rows have been added while we were
  8285. // fetching.
  8286. //
  8287. LogProgress("Checking for expansion of result set\n");
  8288. SCODE sc1 = pIRowsetScroll->GetApproximatePosition(0,
  8289. 0,0, 0, &cRows);
  8290. if ( totalRowsFetched > cRows )
  8291. {
  8292. LogError("Fetched more rows than exist in the result set, %d %d\n",
  8293. totalRowsFetched, cRows);
  8294. cFailures++;
  8295. }
  8296. }
  8297. //
  8298. // When the retrieved row is the file name "F0005.txt" in the
  8299. // test directory, delete that file and
  8300. // continue the enumeration. We expect that GetNextRows can
  8301. // deal with the deletion.
  8302. //
  8303. // When the retrieved row is the file name "F0009.txt" in the
  8304. // test directory, delete the entire test directory and
  8305. // continue the enumeration. We expect that GetNextRows can
  8306. // deal with this deletion also.
  8307. //
  8308. unsigned i;
  8309. for (i = 0; i < cRowsReturned; i++)
  8310. {
  8311. SDeleteTest Row;
  8312. SCODE sc1 = pRowset->GetData(ahRows[i],hAccessor,&Row);
  8313. if ( FAILED( sc1 ) )
  8314. {
  8315. LogError( "IRowset->GetData returned 0x%x\n", sc1 );
  8316. pRowset->Release();
  8317. Fail();
  8318. }
  8319. if ( Row.sName == DBSTATUS_S_OK &&
  8320. Row.cbName != (wcslen(Row.awcName) * sizeof (WCHAR)) )
  8321. LogFail( "length of name column 0x%x not consistent with data 0x%x\n",
  8322. Row.cbName,
  8323. wcslen(Row.awcName) * sizeof WCHAR );
  8324. if ( Row.sPath == DBSTATUS_S_OK &&
  8325. Row.cbPath != (wcslen(Row.awcPath) * sizeof (WCHAR)) )
  8326. LogFail("length of path column not consistent with data\n");
  8327. if ( _wcsicmp( Row.awcName, L"F0005.txt" ) == 0 &&
  8328. _wcsnicmp( Row.awcPath, wcsTestSubDir, cchTestSubDir) == 0)
  8329. {
  8330. fDidDelete = DeleteFile(Row.awcPath);
  8331. if (!fDidDelete)
  8332. {
  8333. if (fDidDirDelete && fSequential)
  8334. {
  8335. // Already did the delnode; we expect the delete to fail
  8336. fDidDelete = TRUE;
  8337. }
  8338. else
  8339. {
  8340. LogError( "Delete of %ws failed\n", Row.awcPath );
  8341. }
  8342. }
  8343. Sleep(2000); // Give time for delete to be processed
  8344. }
  8345. if ( _wcsicmp( Row.awcName, L"F0009.txt" ) == 0 &&
  8346. _wcsnicmp( Row.awcPath, wcsTestSubDir, cchTestSubDir) == 0)
  8347. {
  8348. fDidDirDelete = TRUE;
  8349. if ( Delnode(wcsTestSubDir) != NO_ERROR )
  8350. LogError( "Delnode of %ws failed\n", wcsTestSubDir );
  8351. Sleep(2000); // Give time for delete to be processed
  8352. }
  8353. }
  8354. if (0 != cRowsReturned)
  8355. {
  8356. SCODE sc1 = pRowset->ReleaseRows(cRowsReturned, ahRows, 0, 0, 0);
  8357. if ( FAILED( sc1 ) )
  8358. {
  8359. LogError( "IRowset->ReleaseRows returned 0x%x\n", sc1 );
  8360. pRowset->Release();
  8361. Fail();
  8362. }
  8363. cRowsReturned = 0;
  8364. }
  8365. } while (SUCCEEDED(sc) && sc != DB_S_ENDOFROWSET);
  8366. if (0 != cRowsReturned)
  8367. {
  8368. SCODE sc1 = pRowset->ReleaseRows(cRowsReturned, ahRows, 0, 0, 0);
  8369. if ( FAILED( sc1 ) )
  8370. {
  8371. LogError( "IRowset->ReleaseRows returned 0x%x\n", sc1 );
  8372. pRowset->Release();
  8373. Fail();
  8374. }
  8375. }
  8376. if (!fDidDirDelete)
  8377. {
  8378. LogFail("Couldn't find file to trigger directory delete\n");
  8379. }
  8380. if (!fDidDelete)
  8381. {
  8382. // NOTE: if F0009.txt is found before F0005.txt, this could
  8383. // occur, but we don't expect that with OFS's normal
  8384. // directory order.
  8385. LogFail("Couldn't find file to delete\n");
  8386. }
  8387. if (totalRowsFetched < 10)
  8388. {
  8389. LogFail("Unexpectedly small number of files found in delete test, %d\n",
  8390. totalRowsFetched);
  8391. }
  8392. ReleaseAccessor( pRowset, hAccessor);
  8393. if ( (0 != pIRowsetScroll ) &&
  8394. (totalRowsFetched != cRows) )
  8395. {
  8396. //
  8397. // check that no more rows have been added while we were
  8398. // fetching.
  8399. //
  8400. LogError("Wrong number of rows returned. Exp %d, got %d\n",
  8401. cRows, totalRowsFetched);
  8402. cFailures++;
  8403. }
  8404. if (0 != pIRowsetScroll )
  8405. {
  8406. pIRowsetScroll->Release();
  8407. pIRowsetScroll = 0;
  8408. }
  8409. #if !defined(UNIT_TEST)
  8410. if (cFailures) {
  8411. pRowset->Release();
  8412. Fail();
  8413. }
  8414. #endif // !UNIT_TEST
  8415. pRowset->Release();
  8416. } //DeleteTest
  8417. //+-------------------------------------------------------------------------
  8418. //
  8419. // Function: GiveAccess
  8420. //
  8421. // Synopsis: Gives access to the system or current user
  8422. //
  8423. //--------------------------------------------------------------------------
  8424. BOOL GiveAccess(
  8425. WCHAR * pwcFile,
  8426. BOOL fCurrUser,
  8427. DWORD accessMask )
  8428. {
  8429. PACL pACLNew;
  8430. DWORD cbACL = 1024;
  8431. DWORD cbSID = 1024;
  8432. DWORD cchDomainName = 80;
  8433. PSID pSID;
  8434. PSID_NAME_USE psnuType;
  8435. WCHAR * pwcDomain;
  8436. WCHAR awcUser[100];
  8437. // setup username -- current user or system
  8438. if ( fCurrUser )
  8439. {
  8440. DWORD cwc = sizeof awcUser / sizeof WCHAR;
  8441. if ( !GetUserName( awcUser, &cwc ) )
  8442. LogFail("Couldn't get user name\n");
  8443. }
  8444. else
  8445. {
  8446. wcscpy( awcUser, L"SYSTEM" );
  8447. }
  8448. // Initialize a new security descriptor.
  8449. PSECURITY_DESCRIPTOR pSD = (PSECURITY_DESCRIPTOR)
  8450. LocalAlloc( LPTR,
  8451. SECURITY_DESCRIPTOR_MIN_LENGTH );
  8452. if (pSD == NULL)
  8453. LogFail("Couldn't alloc security descriptor\n");
  8454. if ( !InitializeSecurityDescriptor( pSD,
  8455. SECURITY_DESCRIPTOR_REVISION ) )
  8456. LogFail("Couldn't init security descriptor\n");
  8457. // Initialize a new ACL.
  8458. pACLNew = (PACL) LocalAlloc(LPTR, cbACL);
  8459. if (pACLNew == NULL)
  8460. LogFail("Couldn't alloc acl\n");
  8461. if (!InitializeAcl(pACLNew, cbACL, ACL_REVISION2))
  8462. LogFail("Couldn't init acl\n");
  8463. // Retrieve the SID for user
  8464. pSID = (PSID) LocalAlloc(LPTR, cbSID);
  8465. psnuType = (PSID_NAME_USE) LocalAlloc(LPTR, 1024);
  8466. pwcDomain = (WCHAR *) LocalAlloc(LPTR, cchDomainName);
  8467. if (pSID == NULL || psnuType == NULL ||
  8468. pwcDomain == NULL)
  8469. LogFail("Couldn't alloc security data\n");
  8470. if ( !LookupAccountName( (WCHAR *) NULL,
  8471. awcUser,
  8472. pSID,
  8473. &cbSID,
  8474. pwcDomain,
  8475. &cchDomainName,
  8476. psnuType ) )
  8477. LogFail("Couldn't lookup account '%ws'\n", awcUser );
  8478. // Allow write but not read access to the file.
  8479. if ( !AddAccessAllowedAce( pACLNew,
  8480. ACL_REVISION2,
  8481. accessMask,
  8482. pSID ))
  8483. LogFail("Couldn't AddAccessAllowedAce\n");
  8484. // Add a new ACL to the security descriptor.
  8485. if ( !SetSecurityDescriptorDacl( pSD,
  8486. TRUE, // fDaclPresent flag
  8487. pACLNew,
  8488. FALSE ) ) // not a default disc. ACL
  8489. LogFail("Couldn't SetSecurityDescriptorDacl\n");
  8490. // Apply the new security descriptor to the file.
  8491. if ( !SetFileSecurity( pwcFile,
  8492. DACL_SECURITY_INFORMATION,
  8493. pSD))
  8494. LogFail("Couldn't SetFileSecurity\n");
  8495. LogProgress( "set security '%ws' user '%ws' domain '%ws' to %x\n",
  8496. pwcFile, awcUser, pwcDomain, accessMask );
  8497. FreeSid(pSID);
  8498. LocalFree((HLOCAL) pSD);
  8499. LocalFree((HLOCAL) pACLNew);
  8500. LocalFree((HLOCAL) psnuType);
  8501. LocalFree((HLOCAL) pwcDomain);
  8502. return TRUE;
  8503. } //GiveAccess
  8504. //+-------------------------------------------------------------------------
  8505. //
  8506. // Function: DenyAllAccess
  8507. //
  8508. // Synopsis: Deniess all access to a file
  8509. //
  8510. //--------------------------------------------------------------------------
  8511. BOOL DenyAllAccess( WCHAR *pwcFile )
  8512. {
  8513. // Initialize a security descriptor.
  8514. PSECURITY_DESCRIPTOR pSD = (PSECURITY_DESCRIPTOR)
  8515. LocalAlloc( LPTR,
  8516. SECURITY_DESCRIPTOR_MIN_LENGTH );
  8517. if (pSD == NULL)
  8518. LogFail("Couldn't alloc security descriptor\n");
  8519. if ( !InitializeSecurityDescriptor( pSD,
  8520. SECURITY_DESCRIPTOR_REVISION ) )
  8521. LogFail("Couldn't InitializeSecurityDescriptor\n");
  8522. // Initialize a DACL.
  8523. DWORD cbACL;
  8524. cbACL = 1024;
  8525. PACL pACL;
  8526. pACL = (PACL) LocalAlloc(LPTR, cbACL);
  8527. if (pACL == NULL)
  8528. LogFail("Couldn't allocate acl\n");
  8529. if (!InitializeAcl(pACL, cbACL, ACL_REVISION2))
  8530. LogFail("Couldn't init acl\n");
  8531. // Add an empty ACL to the SD to deny access.
  8532. if ( !SetSecurityDescriptorDacl( pSD,
  8533. TRUE, // fDaclPresent flag
  8534. pACL,
  8535. FALSE ) ) // not a default acl
  8536. LogFail("Couldn't SetSecurityDescriptorDacl\n");
  8537. // Use the new SD as the file's security info.
  8538. if ( !SetFileSecurity( pwcFile,
  8539. DACL_SECURITY_INFORMATION,
  8540. pSD ) )
  8541. LogFail("Couldn't SetFileSecurity\n");
  8542. if(pSD != NULL)
  8543. LocalFree((HLOCAL) pSD);
  8544. if(pACL != NULL)
  8545. LocalFree((HLOCAL) pACL);
  8546. return TRUE;
  8547. } //DenyAllAccess
  8548. void AddSafeArrays( IPropertySetStorage * ppsstg )
  8549. {
  8550. // aI4 (DBTYPE_I4, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 2
  8551. // aBstr (DBTYPE_BSTR, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 3
  8552. // aVariant (DBTYPE_I4, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 4
  8553. // aR8 (DBTYPE_R8, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 5
  8554. // aDate (DBTYPE_DATE, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 6
  8555. // aBool (DBTYPE_BOOL, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 7
  8556. // aDecimal (DBTYPE_R8, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 8
  8557. // aI1 (DBTYPE_I1, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 9
  8558. // aR4 (DBTYPE_R4, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 10
  8559. // aCy (DBTYPE_R8, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 11
  8560. // aUINT (DBTYPE_UI4, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 12
  8561. // aINT (DBTYPE_I4, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 13
  8562. // aError (DBTYPE_I4, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 14
  8563. IPropertyStorage * ppstg;
  8564. ULONG ulMode = STGM_DIRECT | STGM_SHARE_EXCLUSIVE;
  8565. SCODE sc = ppsstg->Create( guidArray, // property set guid
  8566. 0,
  8567. PROPSETFLAG_DEFAULT,
  8568. ulMode | STGM_READWRITE, // Open mode
  8569. &ppstg ); // IProperty
  8570. if ( FAILED(sc) )
  8571. LogFail( "SA: can't create ps %#x\n", sc );
  8572. // VT_ARRAY | VT_I4
  8573. {
  8574. SAFEARRAYBOUND saBounds[3];
  8575. saBounds[0].lLbound = 1;
  8576. saBounds[0].cElements = 3;
  8577. saBounds[1].lLbound = 1;
  8578. saBounds[1].cElements = 4;
  8579. saBounds[2].lLbound = 1;
  8580. saBounds[2].cElements = 2;
  8581. SAFEARRAY * psa = SafeArrayCreateEx( VT_I4, 3, saBounds, 0 );
  8582. if ( 0 == psa )
  8583. LogFail( "SA: can't create sa I4: %#x\n", sc );
  8584. vaI4.vt = VT_I4 | VT_ARRAY;
  8585. vaI4.parray = psa;
  8586. for ( int x = 1; x <= 3; x++ )
  8587. for ( int y = 1; y <= 4; y++ )
  8588. for ( int z = 1; z <= 2; z++ )
  8589. {
  8590. LONG *pl;
  8591. LONG aDim[3];
  8592. aDim[0] = x;
  8593. aDim[1] = y;
  8594. aDim[2] = z;
  8595. HRESULT hr = SafeArrayPtrOfIndex( psa, aDim, (void **) &pl );
  8596. *pl = (x-1) * 8 + (y-1) * 2 + (z-1);
  8597. }
  8598. sc = ppstg->WriteMultiple( 1,
  8599. &psSA_I4,
  8600. &vaI4,
  8601. 0x1000 );
  8602. if ( FAILED( sc ) )
  8603. LogFail( "SA: can't writemultiple VT_I4 %#x\n", sc );
  8604. }
  8605. // VT_ARRAY | VT_BSTR
  8606. {
  8607. SAFEARRAYBOUND saBounds[3];
  8608. saBounds[0].lLbound = -1;
  8609. saBounds[0].cElements = 2;
  8610. saBounds[1].lLbound = 0;
  8611. saBounds[1].cElements = 3;
  8612. saBounds[2].lLbound = 49;
  8613. saBounds[2].cElements = 2;
  8614. SAFEARRAY * psa = SafeArrayCreateEx( VT_BSTR, 3, saBounds, 0 );
  8615. if ( 0 == psa )
  8616. LogFail( "SA: can't create sa I4\n" );
  8617. vaBSTR.vt = VT_BSTR | VT_ARRAY;
  8618. vaBSTR.parray = psa;
  8619. int i = 0;
  8620. for ( int x = -1; x <= 0; x++ )
  8621. for ( int y = 0; y <= 2; y++ )
  8622. for ( int z = 49; z <= 50; z++ )
  8623. {
  8624. void * pv;
  8625. LONG aDim[3];
  8626. aDim[0] = x;
  8627. aDim[1] = y;
  8628. aDim[2] = z;
  8629. HRESULT hr = SafeArrayPtrOfIndex( psa, aDim, &pv );
  8630. WCHAR awc[20];
  8631. swprintf( awc, L"%db", i );
  8632. BSTR bstr = SysAllocString( awc );
  8633. * (BSTR *) pv = bstr;
  8634. i++;
  8635. }
  8636. sc = ppstg->WriteMultiple( 1,
  8637. &psSA_BSTR,
  8638. &vaBSTR,
  8639. 0x1000 );
  8640. if ( FAILED( sc ) )
  8641. LogFail( "SA: can't writemultiple VT_BSTR %#x\n", sc );
  8642. }
  8643. // VT_ARRAY | VT_VARIANT
  8644. {
  8645. SAFEARRAYBOUND saBounds[3];
  8646. saBounds[0].lLbound = 0;
  8647. saBounds[0].cElements = 2;
  8648. saBounds[1].lLbound = -3;
  8649. saBounds[1].cElements = 2;
  8650. saBounds[2].lLbound = 20;
  8651. saBounds[2].cElements = 4;
  8652. SAFEARRAY * psa = SafeArrayCreateEx( VT_VARIANT, 3, saBounds, 0 );
  8653. if ( 0 == psa )
  8654. LogFail( "SA: can't create sa VARIANT\n" );
  8655. vaVARIANT.vt = VT_VARIANT | VT_ARRAY;
  8656. vaVARIANT.parray = psa;
  8657. int i = 0;
  8658. for ( int x = 0; x <= 1; x++ )
  8659. for ( int y = -3; y <= -2; y++ )
  8660. for ( int z = 20; z <= 23; z++ )
  8661. {
  8662. LONG aDim[3];
  8663. aDim[0] = x;
  8664. aDim[1] = y;
  8665. aDim[2] = z;
  8666. PROPVARIANT * pVar;
  8667. HRESULT hr = SafeArrayPtrOfIndex( psa,
  8668. aDim,
  8669. (void **) &pVar );
  8670. if ( 20 == z )
  8671. {
  8672. pVar->lVal = i;
  8673. pVar->vt = VT_I4;
  8674. }
  8675. else if ( 21 == z )
  8676. {
  8677. WCHAR awc[20];
  8678. swprintf( awc, L"%db", i );
  8679. pVar->bstrVal = SysAllocString( awc );
  8680. pVar->vt = VT_BSTR;
  8681. }
  8682. #if 0 // in 1829, the OLE group removed support for this!
  8683. else if ( 22 == z )
  8684. {
  8685. *pVar = vaI4;
  8686. }
  8687. else if ( 23 == z )
  8688. {
  8689. *pVar = vaBSTR;
  8690. }
  8691. #endif
  8692. else
  8693. {
  8694. pVar->fltVal = (float) i;
  8695. pVar->vt = VT_R4;
  8696. }
  8697. i++;
  8698. }
  8699. sc = ppstg->WriteMultiple( 1,
  8700. &psSA_VARIANT,
  8701. &vaVARIANT,
  8702. 0x1000 );
  8703. if ( FAILED( sc ) )
  8704. LogFail( "SA: can't writemultiple VT_VARIANT %#x\n", sc );
  8705. }
  8706. // VT_ARRAY | VT_R8
  8707. {
  8708. SAFEARRAYBOUND saBounds[2];
  8709. saBounds[0].lLbound = 100;
  8710. saBounds[0].cElements = 3;
  8711. saBounds[1].lLbound = -100;
  8712. saBounds[1].cElements = 4;
  8713. SAFEARRAY * psa = SafeArrayCreateEx( VT_R8, 2, saBounds, 0 );
  8714. if ( 0 == psa )
  8715. LogFail( "SA: can't create sa r8\n" );
  8716. vaR8.vt = VT_R8 | VT_ARRAY;
  8717. vaR8.parray = psa;
  8718. double d = 0.0l;
  8719. for ( int x = 100; x <= 102; x++ )
  8720. for ( int y = -100; y <= -97; y++ )
  8721. {
  8722. double * pd;
  8723. LONG aDim[2];
  8724. aDim[0] = x;
  8725. aDim[1] = y;
  8726. HRESULT hr = SafeArrayPtrOfIndex( psa, aDim, (void **) &pd );
  8727. *pd = d;
  8728. d = d + 2.0l;
  8729. }
  8730. sc = ppstg->WriteMultiple( 1,
  8731. &psSA_R8,
  8732. &vaR8,
  8733. 0x1000 );
  8734. if ( FAILED( sc ) )
  8735. LogFail( "SA: can't writemultiple VT_r8 %#x\n", sc );
  8736. }
  8737. // VT_ARRAY | VT_DATE
  8738. {
  8739. SAFEARRAYBOUND saBounds[2];
  8740. saBounds[0].lLbound = 1;
  8741. saBounds[0].cElements = 2;
  8742. saBounds[1].lLbound = 1;
  8743. saBounds[1].cElements = 3;
  8744. SAFEARRAY * psa = SafeArrayCreateEx( VT_DATE, 2, saBounds, 0 );
  8745. if ( 0 == psa )
  8746. LogFail( "can't create safearray of VT_DATE\n" );
  8747. vaDATE.vt = VT_DATE | VT_ARRAY;
  8748. vaDATE.parray = psa;
  8749. int i = 0;
  8750. for ( int x = 1; x <= 2; x++ )
  8751. for ( int y = 1; y <= 3; y++ )
  8752. {
  8753. LONG aDim[2];
  8754. aDim[0] = x;
  8755. aDim[1] = y;
  8756. DATE *pdate;
  8757. HRESULT hr = SafeArrayPtrOfIndex( psa, aDim, (void **) &pdate );
  8758. // round the seconds and milliseconds to 0 since the
  8759. // property set API often is off by as much as 4 seconds
  8760. // when you marshall and unmarshall the value.
  8761. SYSTEMTIME st;
  8762. GetSystemTime( &st );
  8763. st.wSecond = 0;
  8764. st.wMilliseconds = 0;
  8765. st.wYear += (USHORT) i;
  8766. SystemTimeToVariantTime( &st, pdate );
  8767. i++;
  8768. }
  8769. sc = ppstg->WriteMultiple( 1,
  8770. &psSA_DATE,
  8771. &vaDATE,
  8772. 0x1000 );
  8773. if ( FAILED( sc ) )
  8774. LogFail( "can't writemultiple date %#x\n", sc );
  8775. }
  8776. // VT_ARRAY | VT_BOOL
  8777. {
  8778. SAFEARRAYBOUND saBounds[2];
  8779. saBounds[0].lLbound = 1;
  8780. saBounds[0].cElements = 2;
  8781. saBounds[1].lLbound = 1;
  8782. saBounds[1].cElements = 3;
  8783. SAFEARRAY * psa = SafeArrayCreateEx( VT_BOOL, 2, saBounds, 0 );
  8784. if ( 0 == psa )
  8785. LogFail( "can't create safearray of VT_BOOL\n" );
  8786. vaBOOL.vt = VT_BOOL | VT_ARRAY;
  8787. vaBOOL.parray = psa;
  8788. int i = 0;
  8789. GUID guid = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  8790. for ( int x = 1; x <= 2; x++ )
  8791. for ( int y = 1; y <= 3; y++ )
  8792. {
  8793. LONG aDim[2];
  8794. aDim[0] = x;
  8795. aDim[1] = y;
  8796. VARIANT_BOOL *pB;
  8797. HRESULT hr = SafeArrayPtrOfIndex( psa, aDim, (void **) &pB );
  8798. *pB = (i & 1) ? VARIANT_TRUE : VARIANT_FALSE;
  8799. i++;
  8800. }
  8801. sc = ppstg->WriteMultiple( 1,
  8802. &psSA_BOOL,
  8803. &vaBOOL,
  8804. 0x1000 );
  8805. if ( FAILED( sc ) )
  8806. LogFail( "can't writemultiple bool %#x\n", sc );
  8807. }
  8808. // VT_ARRAY | VT_DECIMAL
  8809. {
  8810. SAFEARRAYBOUND saBounds[2];
  8811. saBounds[0].lLbound = 1;
  8812. saBounds[0].cElements = 2;
  8813. saBounds[1].lLbound = 1;
  8814. saBounds[1].cElements = 3;
  8815. SAFEARRAY * psa = SafeArrayCreateEx( VT_DECIMAL, 2, saBounds, 0 );
  8816. if ( 0 == psa )
  8817. LogFail( "can't create safearray of VT_DECIMAL\n" );
  8818. vaDECIMAL.vt = VT_DECIMAL | VT_ARRAY;
  8819. vaDECIMAL.parray = psa;
  8820. int i = 0;
  8821. for ( int x = 1; x <= 2; x++ )
  8822. for ( int y = 1; y <= 3; y++ )
  8823. {
  8824. LONG aDim[2];
  8825. aDim[0] = x;
  8826. aDim[1] = y;
  8827. DECIMAL *pd;
  8828. HRESULT hr = SafeArrayPtrOfIndex( psa, aDim, (void **) &pd );
  8829. if ( FAILED( hr ) )
  8830. LogFail( "can't get ptr of index for DECIMAL %#x", hr );
  8831. double d = i;
  8832. VarDecFromR8( d, pd );
  8833. i++;
  8834. }
  8835. sc = ppstg->WriteMultiple( 1,
  8836. &psSA_DECIMAL,
  8837. &vaDECIMAL,
  8838. 0x1000 );
  8839. if ( FAILED( sc ) )
  8840. LogFail( "can't writemultiple decimal %#x\n", sc );
  8841. }
  8842. // VT_ARRAY | VT_I4
  8843. {
  8844. SAFEARRAYBOUND saBounds[3];
  8845. saBounds[0].lLbound = 1;
  8846. saBounds[0].cElements = 3;
  8847. saBounds[1].lLbound = 1;
  8848. saBounds[1].cElements = 4;
  8849. saBounds[2].lLbound = 1;
  8850. saBounds[2].cElements = 2;
  8851. SAFEARRAY * psa = SafeArrayCreateEx( VT_I1, 3, saBounds, 0 );
  8852. vaI1.vt = VT_I1 | VT_ARRAY;
  8853. vaI1.parray = psa;
  8854. for ( int x = 1; x <= 3; x++ )
  8855. for ( int y = 1; y <= 4; y++ )
  8856. for ( int z = 1; z <= 2; z++ )
  8857. {
  8858. BYTE *pb;
  8859. LONG aDim[3];
  8860. aDim[0] = x;
  8861. aDim[1] = y;
  8862. aDim[2] = z;
  8863. HRESULT hr = SafeArrayPtrOfIndex( psa, aDim, (void **) &pb );
  8864. *pb = (x-1) * 8 + (y-1) * 2 + (z-1);
  8865. }
  8866. sc = ppstg->WriteMultiple( 1,
  8867. &psSA_I1,
  8868. &vaI1,
  8869. 0x1000 );
  8870. if ( FAILED( sc ) )
  8871. LogFail( "can't writemultiple i1 %#x\n", sc );
  8872. }
  8873. // VT_ARRAY | VT_R4
  8874. {
  8875. SAFEARRAYBOUND saBounds[2];
  8876. saBounds[0].lLbound = 100;
  8877. saBounds[0].cElements = 3;
  8878. saBounds[1].lLbound = -100;
  8879. saBounds[1].cElements = 4;
  8880. SAFEARRAY * psa = SafeArrayCreateEx( VT_R4, 2, saBounds, 0 );
  8881. vaR4.vt = VT_R4 | VT_ARRAY;
  8882. vaR4.parray = psa;
  8883. float f = 0.0;
  8884. for ( int x = 100; x <= 102; x++ )
  8885. for ( int y = -100; y <= -97; y++ )
  8886. {
  8887. float * pf;
  8888. LONG aDim[2];
  8889. aDim[0] = x;
  8890. aDim[1] = y;
  8891. HRESULT hr = SafeArrayPtrOfIndex( psa, aDim, (void **) &pf );
  8892. RtlCopyMemory( pf, &f, sizeof f );
  8893. f = (float) ( f + (float) 3.0 );
  8894. }
  8895. sc = ppstg->WriteMultiple( 1,
  8896. &psSA_R4,
  8897. &vaR4,
  8898. 0x1000 );
  8899. if ( FAILED( sc ) )
  8900. LogFail( "can't writemultiple r4 %#x\n", sc );
  8901. }
  8902. // VT_ARRAY | VT_CY
  8903. {
  8904. SAFEARRAYBOUND saBounds[2];
  8905. saBounds[0].lLbound = 100;
  8906. saBounds[0].cElements = 3;
  8907. saBounds[1].lLbound = -100;
  8908. saBounds[1].cElements = 4;
  8909. SAFEARRAY * psa = SafeArrayCreateEx( VT_CY, 2, saBounds, 0 );
  8910. vaCY.vt = VT_CY | VT_ARRAY;
  8911. vaCY.parray = psa;
  8912. double d = 0.0l;
  8913. for ( int x = 100; x <= 102; x++ )
  8914. for ( int y = -100; y <= -97; y++ )
  8915. {
  8916. CY *pcy;
  8917. LONG aDim[2];
  8918. aDim[0] = x;
  8919. aDim[1] = y;
  8920. HRESULT hr = SafeArrayPtrOfIndex( psa, aDim, (void **) &pcy );
  8921. CY cy;
  8922. VarCyFromR8( d, &cy );
  8923. *pcy = cy;
  8924. d = d + 4.0l;
  8925. }
  8926. sc = ppstg->WriteMultiple( 1,
  8927. &psSA_CY,
  8928. &vaCY,
  8929. 0x1000 );
  8930. if ( FAILED( sc ) )
  8931. LogFail( "can't writemultiple cy %#x\n", sc );
  8932. }
  8933. // VT_ARRAY | VT_UINT
  8934. {
  8935. SAFEARRAYBOUND saBounds[3];
  8936. saBounds[0].lLbound = 1;
  8937. saBounds[0].cElements = 3;
  8938. saBounds[1].lLbound = 1;
  8939. saBounds[1].cElements = 4;
  8940. saBounds[2].lLbound = 1;
  8941. saBounds[2].cElements = 2;
  8942. SAFEARRAY * psa = SafeArrayCreateEx( VT_UINT, 3, saBounds, 0 );
  8943. if ( 0 == psa )
  8944. LogFail( "can't create safearray of uint\n" );
  8945. vaUINT.vt = VT_UINT | VT_ARRAY;
  8946. vaUINT.parray = psa;
  8947. for ( int x = 1; x <= 3; x++ )
  8948. for ( int y = 1; y <= 4; y++ )
  8949. for ( int z = 1; z <= 2; z++ )
  8950. {
  8951. unsigned *p;
  8952. LONG aDim[3];
  8953. aDim[0] = x;
  8954. aDim[1] = y;
  8955. aDim[2] = z;
  8956. HRESULT hr = SafeArrayPtrOfIndex( psa, aDim, (void **) &p );
  8957. *p = (unsigned) ( (x-1) * 8 + (y-1) * 2 + (z-1) );
  8958. }
  8959. sc = ppstg->WriteMultiple( 1,
  8960. &psSA_UINT,
  8961. &vaUINT,
  8962. 0x1000 );
  8963. if ( FAILED( sc ) )
  8964. LogFail( "can't writemultiple uint %#x\n", sc );
  8965. }
  8966. // VT_ARRAY | VT_INT
  8967. {
  8968. SAFEARRAYBOUND saBounds[3];
  8969. saBounds[0].lLbound = 1;
  8970. saBounds[0].cElements = 3;
  8971. saBounds[1].lLbound = 1;
  8972. saBounds[1].cElements = 4;
  8973. saBounds[2].lLbound = 1;
  8974. saBounds[2].cElements = 2;
  8975. SAFEARRAY * psa = SafeArrayCreateEx( VT_INT, 3, saBounds, 0 );
  8976. if ( 0 == psa )
  8977. LogFail( "can't create safearray of int\n" );
  8978. vaINT.vt = VT_INT | VT_ARRAY;
  8979. vaINT.parray = psa;
  8980. for ( int x = 1; x <= 3; x++ )
  8981. for ( int y = 1; y <= 4; y++ )
  8982. for ( int z = 1; z <= 2; z++ )
  8983. {
  8984. int *p;
  8985. LONG aDim[3];
  8986. aDim[0] = x;
  8987. aDim[1] = y;
  8988. aDim[2] = z;
  8989. HRESULT hr = SafeArrayPtrOfIndex( psa, aDim, (void **) &p );
  8990. *p = (x-1) * 8 + (y-1) * 2 + (z-1);
  8991. }
  8992. sc = ppstg->WriteMultiple( 1,
  8993. &psSA_INT,
  8994. &vaINT,
  8995. 0x1000 );
  8996. if ( FAILED( sc ) )
  8997. LogFail( "can't writemultiple int %#x\n", sc );
  8998. }
  8999. // VT_ARRAY | VT_ERROR
  9000. {
  9001. SAFEARRAYBOUND saBounds[3];
  9002. saBounds[0].lLbound = 1;
  9003. saBounds[0].cElements = 3;
  9004. saBounds[1].lLbound = 1;
  9005. saBounds[1].cElements = 4;
  9006. saBounds[2].lLbound = 1;
  9007. saBounds[2].cElements = 2;
  9008. SAFEARRAY * psa = SafeArrayCreateEx( VT_ERROR, 3, saBounds, 0 );
  9009. if ( 0 == psa )
  9010. LogFail( "can't create safearray of error\n" );
  9011. vaERROR.vt = VT_ERROR | VT_ARRAY;
  9012. vaERROR.parray = psa;
  9013. for ( int x = 1; x <= 3; x++ )
  9014. for ( int y = 1; y <= 4; y++ )
  9015. for ( int z = 1; z <= 2; z++ )
  9016. {
  9017. HRESULT *p;
  9018. LONG aDim[3];
  9019. aDim[0] = x;
  9020. aDim[1] = y;
  9021. aDim[2] = z;
  9022. HRESULT hr = SafeArrayPtrOfIndex( psa, aDim, (void **) &p );
  9023. *p = 0x80070000 + ( (x-1) * 8 + (y-1) * 2 + (z-1) );
  9024. }
  9025. sc = ppstg->WriteMultiple( 1,
  9026. &psSA_ERROR,
  9027. &vaERROR,
  9028. 0x1000 );
  9029. if ( FAILED( sc ) )
  9030. LogFail( "can't writemultiple error %#x\n", sc );
  9031. }
  9032. ppstg->Release();
  9033. } //AddSafeArrays
  9034. //+-------------------------------------------------------------------------
  9035. //
  9036. // Function: AddPropsToStorage, public
  9037. //
  9038. // Synopsis: Add several props to a file
  9039. //
  9040. // Arguments: [fAlternate] -- TRUE to open alternate file
  9041. //
  9042. //--------------------------------------------------------------------------
  9043. typedef HRESULT (STDAPICALLTYPE * tdStgCreateStorage)
  9044. ( const OLECHAR FAR* pwcsName,
  9045. DWORD grfMode,
  9046. DWORD dwStgFmt,
  9047. LPSECURITY_ATTRIBUTES pssSecurity,
  9048. IStorage FAR * FAR *ppstg);
  9049. tdStgCreateStorage pStgCreateStorage = 0;
  9050. static int fDidInitOfVariants = 0;
  9051. void AddPropsToStorage( BOOL fAlternate )
  9052. {
  9053. SCODE sc;
  9054. if (! fDidInitOfVariants)
  9055. {
  9056. //
  9057. // Create a multi-dimensional safearray for an alternate value for
  9058. // property 8.
  9059. //
  9060. SAFEARRAYBOUND saBounds[3];
  9061. saBounds[0].lLbound = 1;
  9062. saBounds[0].cElements = 50;
  9063. saBounds[1].lLbound = 1;
  9064. saBounds[1].cElements = 10;
  9065. saBounds[2].lLbound = 1;
  9066. saBounds[2].cElements = 10;
  9067. SAFEARRAY * psa = SafeArrayCreateEx( VT_I4, 3, saBounds, 0 );
  9068. LONG * plData;
  9069. sc = SafeArrayAccessData( psa, (void **)&plData );
  9070. if ( FAILED(sc) )
  9071. {
  9072. LogError( "SafeArrayAccessData returned 0x%x\n", sc );
  9073. CantRun();
  9074. }
  9075. memcpy( plData, alProp8, sizeof alProp8 );
  9076. sc = SafeArrayUnaccessData( psa );
  9077. varProp8A.vt = VT_I4 | VT_ARRAY;
  9078. varProp8A.parray = psa;
  9079. varProp11.vt = PROP11_TYPE;
  9080. varProp11.bstrVal = SysAllocString( PROP11_VAL );
  9081. const unsigned cchProp11A = sizeof PROP11_LONGVAL/sizeof PROP11_LONGVAL[0];
  9082. for (unsigned i = 0; i + 25 + 25 < cchProp11A; i += 25)
  9083. wcsncpy(&PROP11_LONGVAL[i+25], &PROP11_LONGVAL[i], 25);
  9084. varProp11A.vt = PROP11_TYPE;
  9085. varProp11A.bstrVal = SysAllocStringLen( PROP11_LONGVAL, wcslen(PROP11_LONGVAL) );
  9086. varProp12.vt = PROP12_TYPE;
  9087. varProp12.cabstr.pElems = (BSTR *)CoTaskMemAlloc( PROP4_VAL.cElems * sizeof (BSTR) );
  9088. varProp12.cabstr.cElems = PROP4_VAL.cElems;
  9089. for (i=0; i < PROP4_VAL.cElems; i++)
  9090. varProp12.cabstr.pElems[i] = SysAllocString( PROP4_VAL.pElems[i] );
  9091. fDidInitOfVariants++;
  9092. }
  9093. // Create a storage
  9094. IStorage * pstg;
  9095. ULONG ulMode = STGM_DIRECT | STGM_SHARE_EXCLUSIVE;
  9096. sc = StgCreateDocfile( wcsTestPath, // Name
  9097. ulMode | STGM_READWRITE | STGM_CREATE,
  9098. 0, // reserved
  9099. &pstg ); // Result
  9100. if ( FAILED(sc) )
  9101. {
  9102. LogError( "StgCreateDocfile %ws returned 0x%x\n", wcsTestPath, sc );
  9103. CantRun();
  9104. }
  9105. // Create a property set
  9106. IPropertySetStorage * ppsstg;
  9107. sc = pstg->QueryInterface( IID_IPropertySetStorage, (void **)&ppsstg );
  9108. pstg->Release();
  9109. if ( FAILED(sc) )
  9110. {
  9111. LogError( "QueryInterface(IPropertySetStorage) returned 0x%lx\n", sc );
  9112. CantRun();
  9113. }
  9114. AddSafeArrays( ppsstg );
  9115. IPropertyStorage * ppstg;
  9116. sc = ppsstg->Create( guidMyPropSet, // Property set GUID
  9117. 0,
  9118. PROPSETFLAG_DEFAULT,
  9119. ulMode | STGM_READWRITE, // Open mode
  9120. &ppstg ); // IProperty
  9121. if ( FAILED(sc) )
  9122. {
  9123. LogError( "IPropertySetStorage::Create returned 0x%lx\n", sc );
  9124. CantRun();
  9125. }
  9126. // Add property values
  9127. PROPID pid=0x1000;
  9128. varProp1.vt = PROP1_TYPE;
  9129. varProp1.lVal = fAlternate ? PROP1_VAL_Alternate : PROP1_VAL;
  9130. sc = ppstg->WriteMultiple( 1, // Count
  9131. &psTestProperty1.GetPropSpec(), // Property
  9132. &varProp1, // Value
  9133. pid ); // Propid
  9134. if ( FAILED(sc) )
  9135. {
  9136. LogError( "IPropertyStorage::WriteMultiple 1 returned 0x%lx\n", sc );
  9137. CantRun();
  9138. }
  9139. varProp2.vt = PROP2_TYPE;
  9140. varProp2.pwszVal = (WCHAR *)PROP2_VAL;
  9141. sc = ppstg->WriteMultiple( 1, // Count
  9142. &psTestProperty2.GetPropSpec(), // Property
  9143. &varProp2, // Value
  9144. pid ); // Propid
  9145. if ( FAILED(sc) )
  9146. {
  9147. LogError( "IPropertyStorage::WriteMultiple 2 returned 0x%lx\n", sc );
  9148. CantRun();
  9149. }
  9150. varProp10.vt = PROP10_TYPE;
  9151. varProp10.pwszVal = (WCHAR *)PROP10_VAL;
  9152. sc = ppstg->WriteMultiple( 1, // Count
  9153. &psTestProperty10.GetPropSpec(), // Property
  9154. &varProp10, // Value
  9155. pid ); // Propid
  9156. if ( FAILED(sc) )
  9157. {
  9158. LogError( "IPropertyStorage::WriteMultiple 10 returned 0x%lx\n", sc );
  9159. CantRun();
  9160. }
  9161. sc = ppstg->WriteMultiple( 1, // Count
  9162. &psTestProperty11.GetPropSpec(), // Property
  9163. fAlternate ? &varProp11A :
  9164. &varProp11, // Value
  9165. pid ); // Propid
  9166. if ( FAILED(sc) )
  9167. {
  9168. LogError( "IPropertyStorage::WriteMultiple 11 returned 0x%lx\n", sc );
  9169. CantRun();
  9170. }
  9171. sc = ppstg->WriteMultiple( 1, // Count
  9172. &psTestProperty12.GetPropSpec(), // Property
  9173. &varProp12, // Value
  9174. pid ); // Propid
  9175. if ( FAILED(sc) )
  9176. {
  9177. LogError( "IPropertyStorage::WriteMultiple 12 returned 0x%lx\n", sc );
  9178. CantRun();
  9179. }
  9180. varProp5.vt = PROP5_TYPE;
  9181. varProp5.cal = PROP5_VAL;
  9182. sc = ppstg->WriteMultiple( 1, // Count
  9183. &psRelevantWords.GetPropSpec(), // Property
  9184. &varProp5, // Value
  9185. pid ); // Propid
  9186. if ( FAILED(sc) )
  9187. {
  9188. LogError( "IPropertyStorage::WriteMultiple 5 returned 0x%lx\n", sc );
  9189. CantRun();
  9190. }
  9191. varProp6.vt = PROP6_TYPE;
  9192. varProp6.blob = PROP6_VAL;
  9193. sc = ppstg->WriteMultiple( 1, // Count
  9194. &psBlobTest.GetPropSpec(), // Property
  9195. &varProp6, // Value
  9196. pid ); // Propid
  9197. if ( FAILED(sc) )
  9198. {
  9199. LogError( "IPropertyStorage::WriteMultiple 6 returned 0x%lx\n", sc );
  9200. CantRun();
  9201. }
  9202. varProp7.vt = PROP7_TYPE;
  9203. varProp7.puuid = &PROP7_VAL;
  9204. sc = ppstg->WriteMultiple( 1, // Count
  9205. &psGuidTest.GetPropSpec(), // Property
  9206. &varProp7, // Value
  9207. pid ); // Propid
  9208. if ( FAILED(sc) )
  9209. {
  9210. LogError( "IPropertyStorage::WriteMultiple 7 returned 0x%lx\n", sc );
  9211. CantRun();
  9212. }
  9213. varProp8.vt = PROP8_TYPE;
  9214. varProp8.cal = PROP8_VAL;
  9215. sc = ppstg->WriteMultiple( 1, // Count
  9216. &psManyRW.GetPropSpec(), // Property
  9217. fAlternate ? &varProp8A :
  9218. &varProp8, // Value
  9219. pid ); // Propid
  9220. if ( FAILED(sc) )
  9221. {
  9222. LogError( "IPropertyStorage::WriteMultiple 8 returned 0x%lx\n", sc );
  9223. CantRun();
  9224. }
  9225. varProp13.vt = PROP13_TYPE;
  9226. varProp13.bVal = PROP13_VAL;
  9227. sc = ppstg->WriteMultiple( 1, // Count
  9228. &psTestProperty13.GetPropSpec(), // Property
  9229. &varProp13, // Value
  9230. pid ); // Propid
  9231. if ( FAILED(sc) )
  9232. {
  9233. LogError( "IPropertyStorage::WriteMultiple 13 returned 0x%lx\n", sc );
  9234. CantRun();
  9235. }
  9236. varProp14.vt = PROP14_TYPE;
  9237. varProp14.iVal = PROP14_VAL;
  9238. sc = ppstg->WriteMultiple( 1, // Count
  9239. &psTestProperty14.GetPropSpec(), // Property
  9240. &varProp14, // Value
  9241. pid ); // Propid
  9242. if ( FAILED(sc) )
  9243. {
  9244. LogError( "IPropertyStorage::WriteMultiple 14 returned 0x%lx\n", sc );
  9245. CantRun();
  9246. }
  9247. varProp15.vt = PROP15_TYPE;
  9248. varProp15.uiVal = PROP15_VAL;
  9249. sc = ppstg->WriteMultiple( 1, // Count
  9250. &psTestProperty15.GetPropSpec(), // Property
  9251. &varProp15, // Value
  9252. pid ); // Propid
  9253. if ( FAILED(sc) )
  9254. {
  9255. LogError( "IPropertyStorage::WriteMultiple 13 returned 0x%lx\n", sc );
  9256. CantRun();
  9257. }
  9258. varProp16.vt = PROP16_TYPE;
  9259. varProp16.lVal = PROP16_VAL;
  9260. sc = ppstg->WriteMultiple( 1, // Count
  9261. &psTestProperty16.GetPropSpec(), // Property
  9262. &varProp16, // Value
  9263. pid ); // Propid
  9264. if ( FAILED(sc) )
  9265. {
  9266. LogError( "IPropertyStorage::WriteMultiple 16 returned 0x%lx\n", sc );
  9267. CantRun();
  9268. }
  9269. varProp17.vt = PROP17_TYPE;
  9270. varProp17.fltVal = PROP17_VAL;
  9271. sc = ppstg->WriteMultiple( 1, // Count
  9272. &psTestProperty17.GetPropSpec(), // Property
  9273. &varProp17, // Value
  9274. pid ); // Propid
  9275. if ( FAILED(sc) )
  9276. {
  9277. LogError( "IPropertyStorage::WriteMultiple 17 returned 0x%lx\n", sc );
  9278. CantRun();
  9279. }
  9280. if (fAlternate)
  9281. {
  9282. varProp18A.decVal.sign = 0;
  9283. varProp18A.decVal.Hi32 = 0;
  9284. varProp18A.decVal.Lo64 = 123412345678i64;
  9285. varProp18A.decVal.scale = 8;
  9286. varProp18A.vt = VT_DECIMAL;
  9287. //double dbl = 0.;
  9288. //VarR8FromDec( &varProp18A.decVal, &dbl );
  9289. //LogError("\tvarProp18A.decVal = %.8f\n", dbl );
  9290. }
  9291. else
  9292. {
  9293. varProp18.vt = PROP18_TYPE;
  9294. varProp18.dblVal = PROP18_VAL;
  9295. }
  9296. sc = ppstg->WriteMultiple( 1, // Count
  9297. &psTestProperty18.GetPropSpec(), // Property
  9298. fAlternate ? &varProp18A :
  9299. &varProp18, // Value
  9300. pid ); // Propid
  9301. if ( FAILED(sc) )
  9302. {
  9303. LogError( "IPropertyStorage::WriteMultiple 18 returned 0x%lx\n", sc );
  9304. CantRun();
  9305. }
  9306. varProp19.vt = PROP19_TYPE;
  9307. varProp19.boolVal = PROP19_VAL;
  9308. sc = ppstg->WriteMultiple( 1, // Count
  9309. &psTestProperty19.GetPropSpec(), // Property
  9310. &varProp19, // Value
  9311. pid ); // Propid
  9312. if ( FAILED(sc) )
  9313. {
  9314. LogError( "IPropertyStorage::WriteMultiple 19 returned 0x%lx\n", sc );
  9315. CantRun();
  9316. }
  9317. varProp20.vt = PROP20_TYPE;
  9318. varProp20.pszVal = PROP20_VAL;
  9319. sc = ppstg->WriteMultiple( 1, // Count
  9320. &psTestProperty20.GetPropSpec(), // Property
  9321. &varProp20, // Value
  9322. pid ); // Propid
  9323. if ( FAILED(sc) )
  9324. {
  9325. LogError( "IPropertyStorage::WriteMultiple 20 returned 0x%lx\n", sc );
  9326. CantRun();
  9327. }
  9328. varProp21.vt = PROP21_TYPE;
  9329. varProp21.pclipdata = PROP21_VAL;
  9330. sc = ppstg->WriteMultiple( 1, // Count
  9331. &psTestProperty21.GetPropSpec(), // Property
  9332. &varProp21, // Value
  9333. pid ); // Propid
  9334. if ( FAILED(sc) )
  9335. {
  9336. LogError( "IPropertyStorage::WriteMultiple 21 returned 0x%lx\n", sc );
  9337. CantRun();
  9338. }
  9339. varProp22.vt = PROP22_TYPE;
  9340. varProp22.caclipdata.pElems = PROP22_VAL;
  9341. varProp22.caclipdata.cElems = PROP22_CVALS;
  9342. sc = ppstg->WriteMultiple( 1, // Count
  9343. &psTestProperty22.GetPropSpec(), // Property
  9344. &varProp22, // Value
  9345. pid ); // Propid
  9346. if ( FAILED(sc) )
  9347. {
  9348. LogError( "IPropertyStorage::WriteMultiple 22 returned 0x%lx\n", sc );
  9349. CantRun();
  9350. }
  9351. ppstg->Release();
  9352. // PROP3 and PROP4 are in a different propertyset!
  9353. sc = ppsstg->Create( guidDocument, // Property set GUID
  9354. 0,
  9355. PROPSETFLAG_DEFAULT,
  9356. ulMode | STGM_READWRITE, // Open mode
  9357. &ppstg ); // IProperty
  9358. if ( FAILED(sc) )
  9359. {
  9360. LogError( "IPropertySetStorage::Create returned 0x%lx\n", sc );
  9361. CantRun();
  9362. }
  9363. varProp3.vt = PROP3_TYPE;
  9364. varProp3.pwszVal = (WCHAR *)PROP3_VAL;
  9365. sc = ppstg->WriteMultiple( 1, // Count
  9366. &psAuthor.GetPropSpec(), // Property
  9367. &varProp3, // Value
  9368. pid ); // Propid
  9369. if ( FAILED(sc) )
  9370. {
  9371. LogError( "IPropertyStorage::WriteMultiple 3 returned 0x%lx\n", sc );
  9372. CantRun();
  9373. }
  9374. varProp4.vt = PROP4_TYPE;
  9375. varProp4.calpwstr = PROP4_VAL;
  9376. sc = ppstg->WriteMultiple( 1, // Count
  9377. &psKeywords.GetPropSpec(), // Property
  9378. &varProp4, // Value
  9379. pid ); // Propid
  9380. if ( FAILED(sc) )
  9381. {
  9382. LogError( "IPropertyStorage::WriteMultiple 4 returned 0x%lx\n", sc );
  9383. CantRun();
  9384. }
  9385. ppstg->Release();
  9386. /////////////////////// the secure prop plan 9
  9387. sc = ppsstg->Create( guidSecurityTest,
  9388. 0,
  9389. PROPSETFLAG_DEFAULT,
  9390. ulMode | STGM_READWRITE, // Open mode
  9391. &ppstg ); // IProperty
  9392. if ( FAILED(sc) )
  9393. LogFail( "IPropertySetStorage::Create (security2) returned 0x%lx\n", sc );
  9394. // this value will be invisible to queries due to permissions...
  9395. varProp9.vt = VT_EMPTY;
  9396. varProp9.lVal = 0;
  9397. ppstg->Release();
  9398. ppsstg->Release();
  9399. } //AddPropsToStorage
  9400. //+-------------------------------------------------------------------------
  9401. //
  9402. // Function: AddFiles, public
  9403. //
  9404. // Synopsis: Add several files to a directory.
  9405. //
  9406. // Arguments: [wszPath] - path name where files should be added
  9407. // [cFiles] - number of files to create
  9408. // [wszPattern] - wsprintf string to create file name
  9409. //
  9410. // History: 18 May 1995 AlanW Created
  9411. //
  9412. //--------------------------------------------------------------------------
  9413. void AddFiles( const WCHAR *wszPath, unsigned cFiles, const WCHAR *wszPattern)
  9414. {
  9415. WCHAR wszFileName[MAX_PATH];
  9416. const unsigned owcFile = wcslen( wszPath );
  9417. for (unsigned i=0; i < cFiles; i++)
  9418. {
  9419. wcscpy( wszFileName, wszPath );
  9420. swprintf( &wszFileName[ owcFile ], wszPattern, i );
  9421. BuildFile( wszFileName, szOFSFileData, strlen( szOFSFileData ) );
  9422. }
  9423. }
  9424. //+-------------------------------------------------------------------------
  9425. //
  9426. // Function: Setup, public
  9427. //
  9428. // Synopsis: Clean up and initialize state
  9429. //
  9430. // History: 13-May-93 KyleP Created
  9431. //
  9432. //--------------------------------------------------------------------------
  9433. void Setup()
  9434. {
  9435. if ( 0 == wcsTestCatalog[0] )
  9436. wcscpy( wcsTestCatalog, wcsDefaultTestCatalog );
  9437. if ( GetEnvironmentVariable( L"TEMP",
  9438. wcsTestPath,
  9439. sizeof(wcsTestPath) / sizeof(wcsTestPath[0]) ) == 0 )
  9440. {
  9441. LogError( "Unable to find test directory. Set TEMP variable.\n" );
  9442. CantRun();
  9443. }
  9444. wcscat( wcsTestPath, L"\\" );
  9445. int ccPath = wcslen( wcsTestPath );
  9446. wcscat( wcsTestPath, wcsTestDir );
  9447. if (Delnode( wcsTestPath ))
  9448. {
  9449. LogError("Delnode %ws failed\n", wcsTestPath);
  9450. CantRun();
  9451. }
  9452. //
  9453. // Create test directory.
  9454. //
  9455. if ( !CreateDirectory( (WCHAR *)wcsTestPath, 0 ) )
  9456. {
  9457. LogError( "Error 0x%lx creating directory %ws\n",
  9458. GetLastError(), wcsTestPath );
  9459. CantRun();
  9460. }
  9461. //
  9462. // Add property file + properties
  9463. //
  9464. wcscpy( wcsTestPath + ccPath, wcsTestDir );
  9465. wcscat( wcsTestPath, L"\\" );
  9466. wcscat( wcsTestPath, wcsPropFile );
  9467. AddPropsToStorage( FALSE );
  9468. //
  9469. // Make a second (similar) file
  9470. //
  9471. wcscpy( wcsTestPath + ccPath, wcsTestDir );
  9472. wcscat( wcsTestPath, L"\\" );
  9473. wcscat( wcsTestPath, wcsPropFile2 );
  9474. AddPropsToStorage( TRUE );
  9475. wcscpy( wcsTestPath + ccPath, wcsTestDir );
  9476. //
  9477. // Add more files for the delete tests
  9478. //
  9479. wcscpy( wcsTestPath + ccPath, wcsTestDir );
  9480. wcscat( wcsTestPath, L"\\DeleteTest.1" );
  9481. if ( !CreateDirectory( (WCHAR *)wcsTestPath, 0 ) )
  9482. {
  9483. LogError( "Error 0x%lx creating directory %ws\n",
  9484. GetLastError(), wcsTestPath );
  9485. CantRun();
  9486. }
  9487. AddFiles( wcsTestPath, 20, L"\\\\F%04d.txt" );
  9488. wcscpy( wcsTestPath + ccPath, wcsTestDir );
  9489. wcscat( wcsTestPath, L"\\DeleteTest.2" );
  9490. if ( !CreateDirectory( (WCHAR *)wcsTestPath, 0 ) )
  9491. {
  9492. LogError( "Error 0x%lx creating directory %ws\n",
  9493. GetLastError(), wcsTestPath );
  9494. CantRun();
  9495. }
  9496. AddFiles( wcsTestPath, 20, L"\\\\F%04d.txt" );
  9497. //
  9498. // Add three files for content query tests
  9499. //
  9500. wcscpy( wcsTestPath + ccPath, wcsTestDir );
  9501. wcscat( wcsTestPath, L"\\" );
  9502. wcscat( wcsTestPath, wcsTestCiFile1 );
  9503. BuildFile( wcsTestPath, szCIFileData1, strlen( szCIFileData1 ) );
  9504. wcscpy( wcsTestPath + ccPath, wcsTestDir );
  9505. wcscat( wcsTestPath, L"\\" );
  9506. wcscat( wcsTestPath, wcsTestCiFile2 );
  9507. BuildFile( wcsTestPath, szCIFileData2, strlen( szCIFileData2 ) );
  9508. // make file 2 visible to both filter daemon and current user.
  9509. // (it was already, but this verifies the file3 code below really works)
  9510. #ifdef CAIRO_SECURITY_WORKS
  9511. DenyAllAccess( wcsTestPath );
  9512. GiveAccess( wcsTestPath, TRUE, GENERIC_READ );
  9513. GiveAccess( wcsTestPath, FALSE, GENERIC_READ );
  9514. #endif
  9515. //
  9516. // make a file that should show up in content queries.
  9517. // give it write access to current user, read access to filter daemon
  9518. // => in the content index, but the current user can't see hit
  9519. //
  9520. wcscpy( wcsTestPath + ccPath, wcsTestDir );
  9521. wcscat( wcsTestPath, L"\\" );
  9522. wcscat( wcsTestPath, wcsTestCiFile3 );
  9523. BuildFile( wcsTestPath, szCIFileData2, strlen( szCIFileData2 ) );
  9524. DenyAllAccess( wcsTestPath );
  9525. #ifdef CAIRO_SECURITY_WORKS
  9526. GiveAccess( wcsTestPath, TRUE, GENERIC_WRITE ); // just for kicks
  9527. GiveAccess( wcsTestPath, FALSE, GENERIC_READ );
  9528. #endif
  9529. //
  9530. // Back to just directory
  9531. //
  9532. wcscpy( wcsTestPath + ccPath, wcsTestDir );
  9533. } //Setup
  9534. //+-------------------------------------------------------------------------
  9535. //
  9536. // Function: Cleanup, public
  9537. //
  9538. // Synopsis: Clean up and initialize state
  9539. //
  9540. // History: 13-May-93 KyleP Created
  9541. //
  9542. //--------------------------------------------------------------------------
  9543. void Cleanup()
  9544. {
  9545. if (Delnode( wcsTestPath ))
  9546. {
  9547. LogError("Delnode %ws failed\n", wcsTestPath);
  9548. CantRun();
  9549. }
  9550. if ( fDidInitOfVariants )
  9551. {
  9552. PropVariantClear( &varProp8A );
  9553. PropVariantClear( &varProp11 );
  9554. PropVariantClear( &varProp11A );
  9555. PropVariantClear( &varProp12 );
  9556. }
  9557. char acSysDir[MAX_PATH];
  9558. if( !GetSystemDirectoryA( acSysDir, sizeof(acSysDir) ) )
  9559. {
  9560. LogFail( "Unable to determine system directory.\n" );
  9561. }
  9562. #if defined( DO_NOTIFICATION )
  9563. char acCmd[MAX_PATH];
  9564. sprintf(acCmd,"del %s\\*.zzz",acSysDir);
  9565. system(acCmd);
  9566. #endif // DO_NOTIFICATION
  9567. } //Cleanup
  9568. //+---------------------------------------------------------------------------
  9569. //
  9570. // Function: FormQueryTree
  9571. //
  9572. // Synopsis: Forms a query tree consisting of the projection nodes,
  9573. // sort node(s), selection node and the restriction tree.
  9574. //
  9575. // Arguments: [pRst] - pointer to Restriction tree describing the query
  9576. // [Cols] - Columns in the resulting table
  9577. // [pSort] - pointer to sort set; may be null
  9578. // [aColNames] - pointer to column names; may be null
  9579. //
  9580. // Returns: A pointer to the query tree. It is the responsibility of
  9581. // the caller to later free it.
  9582. //
  9583. // History: 06 July 1995 AlanW Created
  9584. //
  9585. // Notes:
  9586. //
  9587. //----------------------------------------------------------------------------
  9588. CDbCmdTreeNode * FormQueryTree( CDbCmdTreeNode * pRst,
  9589. CDbColumns & Cols,
  9590. CDbSortSet * pSort,
  9591. LPWSTR * aColNames )
  9592. {
  9593. CDbCmdTreeNode * pTree = 0; // return value
  9594. if (pRst)
  9595. {
  9596. //
  9597. // First create a selection node and append the restriction tree to it
  9598. //
  9599. CDbSelectNode * pSelect = new CDbSelectNode();
  9600. if ( 0 == pSelect )
  9601. {
  9602. LogFail("FormQueryTree: out of memory 0\n");
  9603. }
  9604. pTree = pSelect;
  9605. if ( !pSelect->IsValid() )
  9606. {
  9607. delete pTree;
  9608. LogFail("FormQueryTree: out of memory 1\n");
  9609. }
  9610. //
  9611. // Clone the restriction and use it.
  9612. //
  9613. CDbCmdTreeNode * pExpr = pRst->Clone();
  9614. if ( 0 == pExpr )
  9615. {
  9616. delete pTree;
  9617. LogFail("FormQueryTree: out of memory 2\n");
  9618. }
  9619. //
  9620. // Now make the restriction a child of the selection node.
  9621. //
  9622. pSelect->AddRestriction( pExpr );
  9623. }
  9624. else
  9625. {
  9626. //
  9627. // No restriction. Just use table ID node as start of tree.
  9628. //
  9629. pTree = new CDbTableId();
  9630. if ( 0 == pTree )
  9631. {
  9632. LogFail("FormQueryTree: out of memory 3\n");
  9633. }
  9634. }
  9635. //
  9636. // Next create the projection nodes
  9637. //
  9638. CDbProjectNode * pProject = new CDbProjectNode();
  9639. if ( 0 == pProject )
  9640. {
  9641. delete pTree;
  9642. LogFail("FormQueryTree: out of memory 4\n");
  9643. }
  9644. //
  9645. // Make the selection a child of the projection node.
  9646. //
  9647. pProject->AddTable( pTree );
  9648. pTree = pProject;
  9649. //
  9650. // Next add all the columns in the state.
  9651. //
  9652. unsigned int cCol = Cols.Count();
  9653. for ( unsigned int i = 0; i < cCol; i++ )
  9654. {
  9655. if ( !pProject->AddProjectColumn( Cols.Get(i),
  9656. aColNames ? aColNames[i] : 0 ))
  9657. {
  9658. delete pTree;
  9659. LogFail("FormQueryTree: out of memory 5\n");
  9660. }
  9661. }
  9662. //
  9663. // Next add a sort node and make the project node a child of the
  9664. // sort node
  9665. //
  9666. if (pSort && pSort->Count())
  9667. {
  9668. unsigned int cSortProp = pSort->Count();
  9669. CDbSortNode * pSortNode = new CDbSortNode();
  9670. if ( 0 == pSortNode )
  9671. {
  9672. delete pTree;
  9673. LogFail("FormQueryTree: out of memory 6\n");
  9674. }
  9675. //
  9676. // Make the project node a child of the sort node.
  9677. //
  9678. pSortNode->AddTable( pTree );
  9679. pTree = pSortNode;
  9680. DWORD sd = QUERY_SORTASCEND;
  9681. LCID lcid = 0;
  9682. for( i = 0; i < cSortProp; i++ )
  9683. {
  9684. //
  9685. // Add the sort column.
  9686. //
  9687. if ( !pSortNode->AddSortColumn(pSort->Get(i)))
  9688. {
  9689. delete pTree;
  9690. LogFail("FormQueryTree: out of memory 7\n");
  9691. }
  9692. }
  9693. }
  9694. return pTree;
  9695. }
  9696. void GetCommandTreeErrors(ICommandTree* pCmdTree)
  9697. {
  9698. DBCOMMANDTREE * pTreeCopy = 0;
  9699. SCODE sc = pCmdTree->GetCommandTree(&pTreeCopy);
  9700. if (FAILED(sc))
  9701. {
  9702. pCmdTree->Release();
  9703. LogFail("GetCommandTree failed, %08x\n", sc);
  9704. }
  9705. ULONG cErrorNodes = 0;
  9706. DBCOMMANDTREE ** rgpErrorNodes = 0;
  9707. sc = pCmdTree->FindErrorNodes(pTreeCopy, &cErrorNodes, &rgpErrorNodes);
  9708. if (FAILED(sc))
  9709. {
  9710. pCmdTree->FreeCommandTree(&pTreeCopy);
  9711. pCmdTree->Release();
  9712. LogFail("FindErrorNodes failed, %08x\n", sc);
  9713. }
  9714. for (unsigned i=0; i<cErrorNodes; i++)
  9715. {
  9716. DBCOMMANDTREE* pNode = rgpErrorNodes[i];
  9717. if (pNode->hrError != S_OK)
  9718. {
  9719. LogError("tree node %08x\top=%d\tOp Error=%x\n",
  9720. pNode, pNode->op, pNode->hrError);
  9721. }
  9722. else
  9723. LogError("tree node %x\top=%d\tNO ERROR!!\n",
  9724. pNode, pNode->op);
  9725. }
  9726. pCmdTree->FreeCommandTree(&pTreeCopy);
  9727. }
  9728. //+---------------------------------------------------------------------------
  9729. //
  9730. // Function: InstantiateRowset
  9731. //
  9732. // Synopsis: Forms a query tree consisting of the projection nodes,
  9733. // sort node(s), selection node and the restriction tree.
  9734. //
  9735. // Arguments: [pQueryIn] - Input ICommand or NULL
  9736. // [dwDepth] - Query depth, one of QUERY_DEEP or QUERY_SHALLOW
  9737. // [pswzScope] - Query scope
  9738. // [pTree] - pointer to DBCOMMANDTREE for the query
  9739. // [riid] - Interface ID of the desired rowset interface
  9740. // [pUnkOuter] - pointer to outer unknown object
  9741. // [ppCmdTree] - if non-zero, ICommandTree will be returned here.
  9742. // [fExtendedTypes] - if TRUE, set property for extended variants
  9743. //
  9744. // Returns: IRowsetScroll* - a pointer to an instantiated rowset
  9745. //
  9746. // History: 22 July 1995 AlanW Created
  9747. // 01 July 1997 EmilyB Added outer unknown support for
  9748. // ICommand only.
  9749. //
  9750. // Notes: Although the returned pointer is to IRowsetScroll, the
  9751. // returned pointer may only support IRowset, depending
  9752. // upon the riid parameter.
  9753. //
  9754. // Ownership of the query tree is given to the ICommandTree
  9755. // object. The caller does not need to delete it.
  9756. //
  9757. // Use InstantiateMultipleRowsets for categorized queries.
  9758. //
  9759. //----------------------------------------------------------------------------
  9760. static g_cLocatable = 0;
  9761. IRowsetScroll * InstantiateRowset(
  9762. ICommand *pQueryIn,
  9763. DWORD dwDepth,
  9764. LPWSTR pwszScope,
  9765. CDbCmdTreeNode * pTree,
  9766. REFIID riid,
  9767. COuterUnk * pobjOuterUnk,
  9768. ICommandTree **ppCmdTree,
  9769. BOOL fExtendedTypes
  9770. ) {
  9771. // run the query
  9772. ICommand * pQuery = 0;
  9773. if ( 0 == pQueryIn )
  9774. {
  9775. IUnknown * pIUnknown;
  9776. SCODE sc = CICreateCommand( &pIUnknown,
  9777. (IUnknown *)pobjOuterUnk,
  9778. IID_IUnknown,
  9779. TEST_CATALOG,
  9780. TEST_MACHINE );
  9781. if ( FAILED( sc ) )
  9782. LogFail( "InstantiateRowset - error 0x%x Unable to create ICommand\n",
  9783. sc );
  9784. if (pobjOuterUnk)
  9785. {
  9786. pobjOuterUnk->Set(pIUnknown);
  9787. }
  9788. if (pobjOuterUnk)
  9789. sc = pobjOuterUnk->QueryInterface(IID_ICommand, (void **) &pQuery );
  9790. else
  9791. sc = pIUnknown->QueryInterface(IID_ICommand, (void **) &pQuery );
  9792. pIUnknown->Release();
  9793. if ( FAILED( sc ) )
  9794. LogFail( "InstantiateRowset - error 0x%x Unable to QI ICommand\n",
  9795. sc );
  9796. if ( 0 == pQuery )
  9797. LogFail( "InstantiateRowset - CICreateCommand succeeded, but returned null pQuery\n" );
  9798. sc = SetScopeProperties( pQuery,
  9799. 1,
  9800. &pwszScope,
  9801. &dwDepth );
  9802. if ( FAILED( sc ) )
  9803. LogFail( "InstantiateRowset - error 0x%x Unable to set scope '%ws'\n",
  9804. sc, pwszScope );
  9805. CheckPropertiesOnCommand( pQuery );
  9806. }
  9807. else
  9808. {
  9809. pQuery = pQueryIn;
  9810. }
  9811. ICommandTree *pCmdTree = 0;
  9812. SCODE sc;
  9813. if (pobjOuterUnk)
  9814. sc = pobjOuterUnk->QueryInterface(IID_ICommandTree, (void **)&pCmdTree);
  9815. else
  9816. sc = pQuery->QueryInterface(IID_ICommandTree, (void **)&pCmdTree);
  9817. if (FAILED (sc) )
  9818. {
  9819. if ( 0 == pQueryIn )
  9820. pQuery->Release();
  9821. LogFail("QI for ICommandTree failed\n");
  9822. }
  9823. DBCOMMANDTREE * pRoot = pTree->CastToStruct();
  9824. sc = pCmdTree->SetCommandTree( &pRoot, 0, FALSE);
  9825. if (FAILED (sc) )
  9826. {
  9827. if ( 0 == pQueryIn )
  9828. pQuery->Release();
  9829. pCmdTree->Release();
  9830. LogFail("SetCommandTree failed, %08x\n", sc);
  9831. }
  9832. if (fExtendedTypes)
  9833. {
  9834. ICommandProperties *pCmdProp = 0;
  9835. if (pobjOuterUnk)
  9836. sc = pobjOuterUnk->QueryInterface(IID_ICommandProperties, (void **)&pCmdProp);
  9837. else
  9838. sc = pQuery->QueryInterface(IID_ICommandProperties, (void **)&pCmdProp);
  9839. if (FAILED (sc) )
  9840. {
  9841. if ( 0 == pQueryIn )
  9842. pQuery->Release();
  9843. LogFail("QI for ICommandProperties failed\n");
  9844. }
  9845. //
  9846. // If we should NOT be using a enumerated query, notify pCommand
  9847. //
  9848. const unsigned MAX_PROPS = 6;
  9849. DBPROPSET aPropSet[MAX_PROPS];
  9850. DBPROP aProp[MAX_PROPS];
  9851. ULONG cProp = 0;
  9852. aProp[cProp].dwPropertyID = DBPROP_USEEXTENDEDDBTYPES;
  9853. aProp[cProp].dwOptions = DBPROPOPTIONS_OPTIONAL;
  9854. aProp[cProp].dwStatus = 0; // Ignored
  9855. aProp[cProp].colid = dbcolNull;
  9856. aProp[cProp].vValue.vt = VT_BOOL;
  9857. aProp[cProp].vValue.boolVal = VARIANT_TRUE;
  9858. aPropSet[cProp].rgProperties = &aProp[cProp];
  9859. aPropSet[cProp].cProperties = 1;
  9860. aPropSet[cProp].guidPropertySet = guidQueryExt;
  9861. cProp++;
  9862. if (riid == IID_IRowsetLocate)
  9863. {
  9864. aProp[cProp].dwPropertyID = DBPROP_IRowsetLocate;
  9865. aProp[cProp].dwOptions = DBPROPOPTIONS_REQUIRED;
  9866. aProp[cProp].dwStatus = 0; // Ignored
  9867. aProp[cProp].colid = dbcolNull;
  9868. aProp[cProp].vValue.vt = VT_BOOL;
  9869. aProp[cProp].vValue.boolVal = VARIANT_TRUE;
  9870. aPropSet[cProp].rgProperties = &aProp[cProp];
  9871. aPropSet[cProp].cProperties = 1;
  9872. aPropSet[cProp].guidPropertySet = DBPROPSET_ROWSET;
  9873. cProp++;
  9874. aProp[cProp].dwPropertyID = DBPROP_BOOKMARKS;
  9875. aProp[cProp].dwOptions = DBPROPOPTIONS_REQUIRED;
  9876. aProp[cProp].dwStatus = 0; // Ignored
  9877. aProp[cProp].colid = dbcolNull;
  9878. aProp[cProp].vValue.vt = VT_BOOL;
  9879. aProp[cProp].vValue.boolVal = VARIANT_TRUE;
  9880. aPropSet[cProp].rgProperties = &aProp[cProp];
  9881. aPropSet[cProp].cProperties = 1;
  9882. aPropSet[cProp].guidPropertySet = DBPROPSET_ROWSET;
  9883. cProp++;
  9884. g_cLocatable++;
  9885. if (g_cLocatable % 2)
  9886. {
  9887. aProp[cProp].dwPropertyID = DBPROP_IDBAsynchStatus;
  9888. aProp[cProp].dwOptions = DBPROPOPTIONS_REQUIRED;
  9889. aProp[cProp].dwStatus = 0; // Ignored
  9890. aProp[cProp].colid = dbcolNull;
  9891. aProp[cProp].vValue.vt = VT_BOOL;
  9892. aProp[cProp].vValue.boolVal = VARIANT_TRUE;
  9893. aPropSet[cProp].rgProperties = &aProp[cProp];
  9894. aPropSet[cProp].cProperties = 1;
  9895. aPropSet[cProp].guidPropertySet = DBPROPSET_ROWSET;
  9896. cProp++;
  9897. }
  9898. if ((g_cLocatable % 4) == 3)
  9899. {
  9900. aProp[cProp].dwPropertyID = DBPROP_IRowsetWatchAll;
  9901. aProp[cProp].dwOptions = DBPROPOPTIONS_REQUIRED;
  9902. aProp[cProp].dwStatus = 0; // Ignored
  9903. aProp[cProp].colid = dbcolNull;
  9904. aProp[cProp].vValue.vt = VT_BOOL;
  9905. aProp[cProp].vValue.boolVal = VARIANT_TRUE;
  9906. aPropSet[cProp].rgProperties = &aProp[cProp];
  9907. aPropSet[cProp].cProperties = 1;
  9908. aPropSet[cProp].guidPropertySet = DBPROPSET_ROWSET;
  9909. cProp++;
  9910. }
  9911. }
  9912. else if (riid == IID_IRowsetScroll)
  9913. {
  9914. aProp[cProp].dwPropertyID = DBPROP_IRowsetScroll;
  9915. aProp[cProp].dwOptions = DBPROPOPTIONS_REQUIRED;
  9916. aProp[cProp].dwStatus = 0; // Ignored
  9917. aProp[cProp].colid = dbcolNull;
  9918. aProp[cProp].vValue.vt = VT_BOOL;
  9919. aProp[cProp].vValue.boolVal = VARIANT_TRUE;
  9920. aPropSet[cProp].rgProperties = &aProp[cProp];
  9921. aPropSet[cProp].cProperties = 1;
  9922. aPropSet[cProp].guidPropertySet = DBPROPSET_ROWSET;
  9923. cProp++;
  9924. g_cLocatable++;
  9925. if (g_cLocatable % 2)
  9926. {
  9927. aProp[cProp].dwPropertyID = DBPROP_ROWSET_ASYNCH;
  9928. aProp[cProp].dwOptions = DBPROPOPTIONS_OPTIONAL;
  9929. aProp[cProp].dwStatus = 0; // Ignored
  9930. aProp[cProp].colid = dbcolNull;
  9931. aProp[cProp].vValue.vt = VT_I4;
  9932. aProp[cProp].vValue.lVal = DBPROPVAL_ASYNCH_RANDOMPOPULATION;
  9933. aPropSet[cProp].rgProperties = &aProp[cProp];
  9934. aPropSet[cProp].cProperties = 1;
  9935. aPropSet[cProp].guidPropertySet = DBPROPSET_ROWSET;
  9936. cProp++;
  9937. }
  9938. if ((g_cLocatable % 4) == 3)
  9939. {
  9940. aProp[cProp].dwPropertyID = DBPROP_IRowsetWatchAll;
  9941. aProp[cProp].dwOptions = DBPROPOPTIONS_REQUIRED;
  9942. aProp[cProp].dwStatus = 0; // Ignored
  9943. aProp[cProp].colid = dbcolNull;
  9944. aProp[cProp].vValue.vt = VT_BOOL;
  9945. aProp[cProp].vValue.boolVal = VARIANT_TRUE;
  9946. aPropSet[cProp].rgProperties = &aProp[cProp];
  9947. aPropSet[cProp].cProperties = 1;
  9948. aPropSet[cProp].guidPropertySet = DBPROPSET_ROWSET;
  9949. cProp++;
  9950. }
  9951. }
  9952. sc = pCmdProp->SetProperties( cProp, aPropSet );
  9953. pCmdProp->Release();
  9954. if ( FAILED(sc) || DB_S_ERRORSOCCURRED == sc )
  9955. {
  9956. if ( 0 == pQueryIn )
  9957. pQuery->Release();
  9958. LogError("ICommandProperties::SetProperties failed\n");
  9959. }
  9960. }
  9961. IRowset * pRowset = 0;
  9962. sc = pQuery->Execute( 0, // no aggr. IUnknown
  9963. (riid != IID_IRowset) ?
  9964. IID_IRowsetIdentity :
  9965. IID_IRowset, // IID for i/f to return
  9966. 0, // disp. params
  9967. 0, // count of rows affected
  9968. (IUnknown **)&pRowset); // Returned interface
  9969. if (SUCCEEDED (sc) && 0 == pRowset )
  9970. {
  9971. LogError("ICommand::Execute returned success(%x), but pRowset is null\n", sc);
  9972. if (DB_S_ERRORSOCCURRED == sc)
  9973. {
  9974. CheckPropertiesInError(pQuery);
  9975. }
  9976. pCmdTree->Release();
  9977. pQuery->Release();
  9978. Fail();
  9979. }
  9980. if ( 0 == pQueryIn )
  9981. pQuery->Release();
  9982. if (FAILED (sc) )
  9983. {
  9984. LogError("ICommand::Execute failed, %08x\n", sc);
  9985. if (DB_E_ERRORSINCOMMAND == sc)
  9986. {
  9987. GetCommandTreeErrors(pCmdTree);
  9988. }
  9989. if (DB_E_ERRORSOCCURRED == sc)
  9990. {
  9991. CheckPropertiesInError(pQuery);
  9992. }
  9993. pCmdTree->Release();
  9994. //
  9995. // This isn't really kosher, but it helps to avoid spurious (client-side) memory leaks.
  9996. //
  9997. pQuery->Release();
  9998. Fail();
  9999. }
  10000. if (riid != IID_IRowset)
  10001. {
  10002. IRowset * pRowset2 = 0;
  10003. sc = pRowset->QueryInterface(riid, (void **)&pRowset2);
  10004. if (FAILED (sc) )
  10005. {
  10006. LogError("InstantiateRowset - QI to riid failed, %08x\n", sc);
  10007. pCmdTree->Release();
  10008. Fail();
  10009. }
  10010. pRowset->Release();
  10011. pRowset = pRowset2;
  10012. }
  10013. if ( 0 == ppCmdTree )
  10014. {
  10015. pCmdTree->Release();
  10016. }
  10017. else
  10018. {
  10019. *ppCmdTree = pCmdTree;
  10020. }
  10021. return (IRowsetScroll *)pRowset;
  10022. }
  10023. //+---------------------------------------------------------------------------
  10024. //
  10025. // Function: InstantiateMultipleRowsets
  10026. //
  10027. // Synopsis: Forms a query tree consisting of the projection nodes,
  10028. // sort node(s), selection node and the restriction tree.
  10029. //
  10030. // Arguments: [dwDepth] - Query depth, one of QUERY_DEEP or QUERY_SHALLOW
  10031. // [pswzScope] - Query scope
  10032. // [pTree] - pointer to DBCOMMANDTREE for the query
  10033. // [riid] - Interface ID of the desired rowset interface
  10034. // [cRowsets] - Number of rowsets to be returned
  10035. // [ppRowsets] - Pointer to location where rowsets are returned
  10036. // [ppCmdTree] - if non-zero, ICommandTree will be returned here.
  10037. //
  10038. // Returns: Nothing
  10039. //
  10040. // History: 22 July 1995 AlanW Created
  10041. //
  10042. // Notes: Ownership of the query tree is given to the ICommandTree
  10043. // object. The caller does not need to delete it.
  10044. //
  10045. //----------------------------------------------------------------------------
  10046. void
  10047. InstantiateMultipleRowsets(
  10048. DWORD dwDepth,
  10049. LPWSTR pwszScope,
  10050. CDbCmdTreeNode * pTree,
  10051. REFIID riid,
  10052. unsigned cRowsets,
  10053. IUnknown **ppRowsets,
  10054. ICommandTree ** ppCmdTree
  10055. ) {
  10056. // run the query
  10057. ICommand * pQuery = 0;
  10058. IUnknown * pIUnknown;
  10059. SCODE scIC = CICreateCommand( &pIUnknown,
  10060. 0,
  10061. IID_IUnknown,
  10062. TEST_CATALOG,
  10063. TEST_MACHINE );
  10064. if (FAILED(scIC))
  10065. LogFail( "InstantiateMultipleRowsets - error 0x%x, Unable to create ICommand\n",
  10066. scIC );
  10067. scIC = pIUnknown->QueryInterface(IID_ICommand, (void **) &pQuery );
  10068. pIUnknown->Release();
  10069. if ( FAILED( scIC ) )
  10070. LogFail( "InstantiateMultipleRowsets - error 0x%x Unable to QI ICommand\n",
  10071. scIC );
  10072. if ( 0 == pQuery )
  10073. LogFail( "InstantiateMultipleRowsets - CICreateCommand succeeded, but returned null pQuery\n" );
  10074. scIC = SetScopeProperties( pQuery,
  10075. 1,
  10076. &pwszScope,
  10077. &dwDepth );
  10078. if ( FAILED( scIC ) )
  10079. LogFail( "InstantiateMultipleRowsets - error 0x%x Unable to set scope '%ws'\n",
  10080. scIC, pwszScope );
  10081. scIC = SetBooleanProperty( pQuery, DBPROP_CANHOLDROWS, VARIANT_TRUE );
  10082. if ( FAILED( scIC ) )
  10083. LogFail( "InstantiateMultipleRowsets - error 0x%x Unable to set HoldRows\n",
  10084. scIC );
  10085. CheckPropertiesOnCommand( pQuery );
  10086. ICommandTree *pCmdTree = 0;
  10087. SCODE sc = pQuery->QueryInterface(IID_ICommandTree, (void **)&pCmdTree);
  10088. if (FAILED (sc) )
  10089. {
  10090. pQuery->Release();
  10091. LogFail("QI for ICommandTree failed\n");
  10092. }
  10093. DBCOMMANDTREE * pRoot = pTree->CastToStruct();
  10094. sc = pCmdTree->SetCommandTree( &pRoot, 0, FALSE);
  10095. if (FAILED (sc) )
  10096. {
  10097. pQuery->Release();
  10098. pCmdTree->Release();
  10099. LogFail("SetCommandTree failed, %08x\n", sc);
  10100. }
  10101. sc = pQuery->Execute( 0, // no aggr. IUnknown
  10102. riid, // IID for i/f to return
  10103. 0, // disp. params
  10104. 0, // count of rows affected
  10105. (IUnknown **)ppRowsets); // Returned interface
  10106. pQuery->Release();
  10107. if (FAILED (sc) )
  10108. {
  10109. LogError("ICommand::Execute failed, %08x\n", sc);
  10110. if (DB_E_ERRORSINCOMMAND == sc)
  10111. {
  10112. GetCommandTreeErrors(pCmdTree);
  10113. }
  10114. pCmdTree->Release();
  10115. Fail();
  10116. }
  10117. // Get rowset pointers for all child rowsets
  10118. for (unsigned i=1; i<cRowsets; i++)
  10119. {
  10120. IUnknown * pRowset = ppRowsets[i-1];
  10121. IColumnsInfo * pColumnsInfo = 0;
  10122. sc = pRowset->QueryInterface(IID_IColumnsInfo, (void **)&pColumnsInfo);
  10123. if (FAILED (sc) )
  10124. {
  10125. pCmdTree->Release();
  10126. LogFail("QI for IColumnsInfo failed\n");
  10127. }
  10128. DBORDINAL iChaptOrdinal = 0;
  10129. sc = pColumnsInfo->MapColumnIDs(1, &psChapt, &iChaptOrdinal);
  10130. pColumnsInfo->Release();
  10131. if (FAILED (sc) )
  10132. {
  10133. pCmdTree->Release();
  10134. LogFail("MapColumnIDs of chapter column failed, %x\n", sc);
  10135. }
  10136. IRowsetInfo * pRowsetInfo = 0;
  10137. sc = pRowset->QueryInterface(IID_IRowsetInfo, (void **)&pRowsetInfo);
  10138. if (FAILED (sc) )
  10139. {
  10140. pCmdTree->Release();
  10141. LogFail("QI for IRowsetInfo failed\n");
  10142. }
  10143. sc = pRowsetInfo->GetReferencedRowset(iChaptOrdinal, riid, &ppRowsets[i]);
  10144. pRowsetInfo->Release();
  10145. if (FAILED (sc) )
  10146. {
  10147. pCmdTree->Release();
  10148. LogFail("GetReferencedRowset failed, %x\n", sc);
  10149. }
  10150. }
  10151. if ( 0 == ppCmdTree )
  10152. {
  10153. pCmdTree->Release();
  10154. }
  10155. else
  10156. {
  10157. *ppCmdTree = pCmdTree;
  10158. }
  10159. return;
  10160. }
  10161. //+-------------------------------------------------------------------------
  10162. //
  10163. // Function: ReleaseStaticHrows, public
  10164. //
  10165. // Synopsis: Release a caller allocated HROW array
  10166. //
  10167. // Arguments: [pRowset] - a pointer to IRowset
  10168. // [cRows] - nuumber of HROWs in the array
  10169. // [phRows] - a pointer to the HROWs array
  10170. //
  10171. // Returns: Nothing
  10172. //
  10173. // History: 03 Oct 1996 AlanW Created
  10174. //
  10175. //--------------------------------------------------------------------------
  10176. const unsigned MAX_ROWSTATUS = 20;
  10177. ULONG aRowRefcount[MAX_ROWSTATUS];
  10178. DBROWSTATUS aRowStatus[MAX_ROWSTATUS];
  10179. void ReleaseStaticHrows( IRowset * pRowset, DBCOUNTITEM cRows, HROW * phRows )
  10180. {
  10181. ULONG *pRefCount = 0;
  10182. DBROWSTATUS *pRowStatus = 0;
  10183. if (cRows <= MAX_ROWSTATUS)
  10184. {
  10185. pRefCount = aRowRefcount;
  10186. pRowStatus = aRowStatus;
  10187. }
  10188. SCODE sc = pRowset->ReleaseRows(cRows, phRows, 0, pRefCount, pRowStatus);
  10189. if (sc != S_OK && sc != DB_S_ERRORSOCCURRED)
  10190. {
  10191. LogError("ReleaseStaticHrows: ReleaseRows failed, sc=%x\n", sc);
  10192. cFailures++;
  10193. }
  10194. else if (cRows <= MAX_ROWSTATUS)
  10195. {
  10196. for (unsigned i=0; i<cRows; i++)
  10197. {
  10198. if ( pRowStatus[i] != DBROWSTATUS_S_OK &&
  10199. ! ( pRowStatus[i] == DBROWSTATUS_E_INVALID &&
  10200. phRows[i] == DB_NULL_HROW ))
  10201. {
  10202. LogError("ReleaseStaticHrows: ReleaseRows row status/refcount, "
  10203. "hrow=%x ref=%d stat=%d\n", phRows[i], pRefCount[i], pRowStatus[i]);
  10204. cFailures++;
  10205. continue;
  10206. }
  10207. if ( pRowStatus[i] != DBROWSTATUS_S_OK &&
  10208. sc != DB_S_ERRORSOCCURRED )
  10209. {
  10210. LogError("ReleaseStaticHrows: bad return status, sc = %x\n", sc);
  10211. cFailures++;
  10212. continue;
  10213. }
  10214. }
  10215. }
  10216. } //ReleaseStaticHrows
  10217. //+-------------------------------------------------------------------------
  10218. //
  10219. // Function: FreeHrowsArray, public
  10220. //
  10221. // Synopsis: Release and free a callee allocated HROW array
  10222. //
  10223. // Effects: Memory is freed; pointer is zeroed
  10224. //
  10225. // Arguments: [pRowset] - a pointer to IRowset
  10226. // [cRows] - nuumber of HROWs in the array
  10227. // [pphRows] - a pointer to pointer to the HROWs array
  10228. //
  10229. // History: 01 Feb 1995 AlanW Created
  10230. //
  10231. //--------------------------------------------------------------------------
  10232. void FreeHrowsArray( IRowset * pRowset, DBCOUNTITEM cRows, HROW ** pphRows )
  10233. {
  10234. if (*pphRows)
  10235. {
  10236. ReleaseStaticHrows(pRowset, cRows, *pphRows);
  10237. CoTaskMemFree(*pphRows);
  10238. *pphRows = 0;
  10239. }
  10240. } //FreeHrowsArray
  10241. //+-------------------------------------------------------------------------
  10242. //
  10243. // Function: MapColumns, public
  10244. //
  10245. // Synopsis: Map column IDs in column bindings. Create an accessor
  10246. // for the binding array.
  10247. //
  10248. // Arguments: [pUnknown] -- Interface capable of returning IColumnsInfo and
  10249. // IAccessor
  10250. // [cCols] -- number of columns in arrays
  10251. // [pBindings] -- column data binding array
  10252. // [pDbCols] -- column IDs array
  10253. // [fByRef] -- true if byref/vector columns should be byref
  10254. //
  10255. // Returns: HACCESSOR - a read accessor for the column bindings.
  10256. //
  10257. // History: 18 May 1995 AlanW Created
  10258. //
  10259. //--------------------------------------------------------------------------
  10260. static DBORDINAL aMappedColumnIDs[20];
  10261. HACCESSOR MapColumns(
  10262. IUnknown * pUnknown,
  10263. DBORDINAL cCols,
  10264. DBBINDING * pBindings,
  10265. const DBID * pDbCols,
  10266. BOOL fByRef )
  10267. {
  10268. IColumnsInfo * pColumnsInfo = 0;
  10269. SCODE sc = pUnknown->QueryInterface( IID_IColumnsInfo, (void **)&pColumnsInfo);
  10270. if ( FAILED( sc ) || pColumnsInfo == 0 )
  10271. {
  10272. LogFail( "IUnknown::QueryInterface for IColumnsInfo returned 0x%lx\n", sc );
  10273. }
  10274. sc = pColumnsInfo->MapColumnIDs(cCols, pDbCols, aMappedColumnIDs);
  10275. pColumnsInfo->Release();
  10276. if (S_OK != sc)
  10277. {
  10278. LogFail( "IColumnsInfo->MapColumnIDs returned 0x%lx\n",sc);
  10279. }
  10280. for (ULONG i = 0; i < cCols; i++)
  10281. {
  10282. pBindings[i].iOrdinal = aMappedColumnIDs[i];
  10283. if ( fByRef &&
  10284. ( (pBindings[i].wType & (DBTYPE_BYREF|DBTYPE_VECTOR)) ||
  10285. pBindings[i].wType == DBTYPE_BSTR ||
  10286. pBindings[i].wType == VT_LPWSTR ||
  10287. pBindings[i].wType == VT_LPSTR ) &&
  10288. pBindings[i].dwMemOwner != DBMEMOWNER_PROVIDEROWNED)
  10289. {
  10290. LogError( "Test error -- MapColumns with fByref, bad accessor %d\n", i);
  10291. }
  10292. if ( ! fByRef &&
  10293. ( (pBindings[i].wType & (DBTYPE_BYREF|DBTYPE_VECTOR)) ||
  10294. pBindings[i].wType == DBTYPE_BSTR ||
  10295. pBindings[i].wType == VT_LPWSTR ||
  10296. pBindings[i].wType == VT_LPSTR ) &&
  10297. pBindings[i].dwMemOwner != DBMEMOWNER_CLIENTOWNED)
  10298. {
  10299. LogError( "Test error -- MapColumns without fByref, bad accessor %d\n", i);
  10300. }
  10301. }
  10302. IAccessor * pIAccessor = 0;
  10303. sc = pUnknown->QueryInterface( IID_IAccessor, (void **)&pIAccessor);
  10304. if ( FAILED( sc ) || pIAccessor == 0 )
  10305. {
  10306. LogFail( "IRowset::QueryInterface for IAccessor returned 0x%lx\n", sc );
  10307. }
  10308. HACCESSOR hAcc;
  10309. sc = pIAccessor->CreateAccessor( DBACCESSOR_ROWDATA, cCols, pBindings,
  10310. 0, &hAcc, 0 );
  10311. pIAccessor->Release();
  10312. if (S_OK != sc)
  10313. {
  10314. LogFail( "IAccessor->CreateAccessor returned 0x%lx\n", sc);
  10315. }
  10316. return hAcc;
  10317. }
  10318. //+-------------------------------------------------------------------------
  10319. //
  10320. // Function: ReleaseAccessor, public
  10321. //
  10322. // Synopsis: Release an accessor obtained from MapColumns
  10323. //
  10324. // Arguments: [pUnknown] -- Something that we can QI the IAccessor on
  10325. // [hAcc] -- Accessor handle to be released.
  10326. //
  10327. // Returns: nothing
  10328. //
  10329. // History: 14 June 1995 AlanW Created
  10330. //
  10331. //--------------------------------------------------------------------------
  10332. void ReleaseAccessor( IUnknown * pUnknown, HACCESSOR hAcc )
  10333. {
  10334. IAccessor * pIAccessor = 0;
  10335. SCODE sc = pUnknown->QueryInterface( IID_IAccessor, (void **)&pIAccessor);
  10336. if ( FAILED( sc ) || pIAccessor == 0 )
  10337. {
  10338. LogFail( "IUnknown::QueryInterface for IAccessor returned 0x%lx\n", sc );
  10339. }
  10340. ULONG cRef;
  10341. sc = pIAccessor->ReleaseAccessor( hAcc, &cRef );
  10342. pIAccessor->Release();
  10343. if (S_OK != sc)
  10344. {
  10345. LogFail( "IAccessor->ReleaseAccessor returned 0x%lx\n", sc);
  10346. }
  10347. if (0 != cRef)
  10348. {
  10349. LogFail( "IAccessor->ReleaseAccessor not last ref: %d\n", cRef);
  10350. }
  10351. }
  10352. #if defined( DO_NOTIFICATION )
  10353. class CNotifyAsynch : public IDBAsynchNotify
  10354. {
  10355. public:
  10356. CNotifyAsynch() :
  10357. _fChecking(FALSE),
  10358. _fComplete(FALSE),
  10359. _cRef(1)
  10360. {}
  10361. ~CNotifyAsynch()
  10362. {
  10363. if (_fChecking)
  10364. {
  10365. if (1 != _cRef) // NOTE: notify objects are static allocated
  10366. {
  10367. LogError( "Bad refcount on CNotifyAsynch.\n" );
  10368. }
  10369. }
  10370. }
  10371. void DoChecking(BOOL fChecking)
  10372. {
  10373. _fChecking = fChecking;
  10374. }
  10375. //
  10376. // IUnknown methods.
  10377. //
  10378. STDMETHOD(QueryInterface) (THIS_ REFIID riid,LPVOID *ppiuk)
  10379. {
  10380. *ppiuk = (void **) this; // hold our breath and jump
  10381. AddRef();
  10382. return S_OK;
  10383. }
  10384. STDMETHOD_(ULONG, AddRef) (THIS)
  10385. { return ++_cRef; }
  10386. STDMETHOD_(ULONG, Release) (THIS)
  10387. { return --_cRef; }
  10388. //
  10389. // IDBAsynchNotify methods
  10390. //
  10391. STDMETHOD(OnLowResource) (THIS_ DB_DWRESERVE dwReserved)
  10392. {
  10393. return S_OK;
  10394. }
  10395. STDMETHOD(OnProgress) (THIS_ HCHAPTER hChap, DBASYNCHOP ulOp,
  10396. DBCOUNTITEM ulProg, DBCOUNTITEM ulProgMax,
  10397. DBASYNCHPHASE ulStat, LPOLESTR pwszStatus )
  10398. {
  10399. if (ulProg == ulProgMax)
  10400. _fComplete = TRUE;
  10401. return S_OK;
  10402. }
  10403. STDMETHOD(OnStop) (THIS_ HCHAPTER hChap, ULONG ulOp,
  10404. HRESULT hrStat, LPOLESTR pwszStatus )
  10405. {
  10406. return S_OK;
  10407. }
  10408. BOOL IsComplete(void)
  10409. { return _fComplete; }
  10410. private:
  10411. ULONG _cRef;
  10412. BOOL _fChecking;
  10413. BOOL _fComplete;
  10414. };
  10415. #endif //defined( DO_NOTIFICATION )
  10416. //+-------------------------------------------------------------------------
  10417. //
  10418. // Function: WaitForCompletion, public
  10419. //
  10420. // Synopsis: Loops until query is finished
  10421. //
  10422. // Arguments: [pRowset] -- Table cursor to wait for
  10423. //
  10424. // Returns: TRUE if successful
  10425. //
  10426. // History: 30 Jun 94 AlanW Created
  10427. //
  10428. //--------------------------------------------------------------------------
  10429. int WaitForCompletion( IRowset *pRowset, BOOL fQuiet )
  10430. {
  10431. IDBAsynchStatus * pRowsetAsynch = 0;
  10432. SCODE sc = pRowset->QueryInterface( IID_IDBAsynchStatus,
  10433. (void **)&pRowsetAsynch);
  10434. if ( sc == E_NOINTERFACE )
  10435. return TRUE;
  10436. if ( FAILED( sc ) || pRowsetAsynch == 0 )
  10437. {
  10438. LogError( "IRowset::QueryInterface for IDBAsynchStatus returned 0x%lx\n", sc );
  10439. return( FALSE );
  10440. }
  10441. if (! fQuiet)
  10442. LogProgress( " Waiting for query to complete" );
  10443. time( &tstart );
  10444. ULONG ulSleep = 25;
  10445. BOOL fDone = FALSE;
  10446. #if defined( DO_NOTIFICATION )
  10447. IConnectionPoint *pConnectionPoint = 0;
  10448. DWORD dwAdviseID = 0;
  10449. CNotifyAsynch Notify;
  10450. Notify.DoChecking(TRUE);
  10451. //
  10452. // Get the connection point container
  10453. //
  10454. IConnectionPointContainer *pConnectionPointContainer = 0;
  10455. sc = pRowset->QueryInterface(IID_IConnectionPointContainer,
  10456. (void **) &pConnectionPointContainer);
  10457. if (FAILED(sc))
  10458. {
  10459. LogError( "IRowset->QI for IConnectionPointContainer failed: 0x%x\n",
  10460. sc );
  10461. pRowset->Release();
  10462. Fail();
  10463. }
  10464. //
  10465. // Make a connection point from the connection point container
  10466. //
  10467. sc = pConnectionPointContainer->FindConnectionPoint(
  10468. IID_IDBAsynchNotify,
  10469. &pConnectionPoint);
  10470. if (FAILED(sc) && CONNECT_E_NOCONNECTION != sc )
  10471. {
  10472. LogError( "FindConnectionPoint failed: 0x%x\n",sc );
  10473. pRowset->Release();
  10474. Fail();
  10475. }
  10476. pConnectionPointContainer->Release();
  10477. if (0 != pConnectionPoint)
  10478. {
  10479. //
  10480. // Give a callback object to the connection point
  10481. //
  10482. sc = pConnectionPoint->Advise((IUnknown *) &Notify,
  10483. &dwAdviseID);
  10484. if (FAILED(sc))
  10485. {
  10486. LogError( "IConnectionPoint->Advise failed: 0x%x\n",sc );
  10487. pConnectionPoint->Release();
  10488. pRowset->Release();
  10489. Fail();
  10490. }
  10491. }
  10492. #endif // DO_NOTIFICATION
  10493. do
  10494. {
  10495. #if defined( DO_NOTIFICATION )
  10496. fDone = Notify.IsComplete( );
  10497. #else // ! defined( DO_NOTIFICATION )
  10498. ULONG ulDen,ulNum,ulPhase;
  10499. sc = pRowsetAsynch->GetStatus( DB_NULL_HCHAPTER, DBASYNCHOP_OPEN,
  10500. &ulNum, &ulDen, &ulPhase, 0 );
  10501. if ( FAILED( sc ) )
  10502. {
  10503. LogError( "IDBAsynchStatus::GetStatus returned 0x%lx\n", sc );
  10504. break;
  10505. }
  10506. fDone = (ulDen == ulNum);
  10507. if ( fDone && ulPhase != DBASYNCHPHASE_COMPLETE ||
  10508. ! fDone && ulPhase != DBASYNCHPHASE_POPULATION )
  10509. {
  10510. LogError( "IDBAsynchStatus::GetStatus returned invalid ulPhase %d\n", ulPhase );
  10511. break;
  10512. }
  10513. #endif // DO_NOTIFICATION
  10514. if (fDone)
  10515. break;
  10516. if ( !CheckTime() )
  10517. {
  10518. LogError( "\nQuery took too long to complete.\n" );
  10519. break;
  10520. }
  10521. if (! fQuiet)
  10522. LogProgress( "." );
  10523. Sleep( ulSleep );
  10524. #if 1
  10525. ulSleep *= 2;
  10526. if (ulSleep > MAXWAITTIME * 1000)
  10527. ulSleep = MAXWAITTIME * 1000;
  10528. #else
  10529. ulSleep = 500;
  10530. #endif
  10531. } while ( ! fDone );
  10532. #if defined( DO_NOTIFICATION )
  10533. if ( 0 != pConnectionPoint )
  10534. {
  10535. //
  10536. // Clean up notification stuff
  10537. //
  10538. sc = pConnectionPoint->Unadvise(dwAdviseID);
  10539. if (S_OK != sc)
  10540. {
  10541. LogError( "IConnectionPoint->Unadvise returned 0x%lx\n",sc);
  10542. pRowset->Release();
  10543. Fail();
  10544. }
  10545. pConnectionPoint->Release();
  10546. //Notify.Release();
  10547. }
  10548. #endif // DO_NOTIFICATION
  10549. pRowsetAsynch->Release();
  10550. if (fVerbose && !fQuiet)
  10551. {
  10552. //
  10553. // Was it a long-running query? If so, report how long.
  10554. //
  10555. time_t tend;
  10556. time( &tend );
  10557. if ( difftime( tend, tstart ) >= MINREPORTTIME )
  10558. LogProgress( "Query took %d seconds to complete.",
  10559. (LONG)difftime(tend, tstart) );
  10560. LogProgress("\n");
  10561. }
  10562. return fDone;
  10563. } //WaitForCompletion
  10564. //+-------------------------------------------------------------------------
  10565. //
  10566. // Function: Delnode, private
  10567. //
  10568. // Synopsis: Deletes a directory recursively.
  10569. //
  10570. // Arguments: [wcsDir] -- Directory to kill
  10571. //
  10572. // Returns: ULONG - error code if failure
  10573. //
  10574. // History: 22-Jul-92 KyleP Created
  10575. // 06 May 1995 AlanW Made recursive, and more tolerant of
  10576. // errors in case of interactions with
  10577. // CI filtering.
  10578. //
  10579. //--------------------------------------------------------------------------
  10580. ULONG Delnode( WCHAR const * wcsDir )
  10581. {
  10582. WIN32_FIND_DATA finddata;
  10583. WCHAR wcsBuffer[MAX_PATH];
  10584. wcscpy( wcsBuffer, wcsDir );
  10585. wcscat( wcsBuffer, L"\\*.*" );
  10586. HANDLE hFindFirst = FindFirstFile( wcsBuffer, &finddata );
  10587. while( hFindFirst != INVALID_HANDLE_VALUE )
  10588. {
  10589. //
  10590. // Look for . and ..
  10591. //
  10592. if ( ! (finddata.cFileName[0] == '.' &&
  10593. (finddata.cFileName[1] == 0 ||
  10594. (finddata.cFileName[1] == '.' &&
  10595. finddata.cFileName[2] == 0 ) ) ) )
  10596. {
  10597. wcscpy( wcsBuffer, wcsDir );
  10598. wcscat( wcsBuffer, L"\\");
  10599. wcscat( wcsBuffer, finddata.cFileName );
  10600. if ( finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  10601. Delnode( wcsBuffer);
  10602. else if ( !DeleteFile( wcsBuffer ) )
  10603. {
  10604. ULONG ulFailure = GetLastError();
  10605. LogError("Error 0x%lx deleting %ws\n", ulFailure, wcsBuffer);
  10606. return (ulFailure == 0) ? 0xFFFFFFFF : ulFailure;
  10607. }
  10608. }
  10609. if ( !FindNextFile( hFindFirst, &finddata ) )
  10610. {
  10611. FindClose( hFindFirst );
  10612. break;
  10613. }
  10614. }
  10615. RemoveDirectory( (WCHAR *)wcsDir );
  10616. // if racing with CI Filtering, retry after a short time
  10617. if (GetLastError() == ERROR_DIR_NOT_EMPTY)
  10618. {
  10619. Sleep(2 * 1000);
  10620. RemoveDirectory( (WCHAR *)wcsDir );
  10621. }
  10622. //
  10623. // Make sure it's removed.
  10624. //
  10625. if ( FindFirstFile( (WCHAR *)wcsDir, &finddata ) != INVALID_HANDLE_VALUE )
  10626. {
  10627. ULONG ulFailure = GetLastError();
  10628. LogError("Error 0x%lx removing directory %ws\n", ulFailure, wcsDir);
  10629. return (ulFailure == 0) ? 0xFFFFFFFF : ulFailure;
  10630. }
  10631. return 0;
  10632. } //Delnode
  10633. //+-------------------------------------------------------------------------
  10634. //
  10635. // Function: BuildFile, private
  10636. //
  10637. // Synopsis: Creates a file and fills it with data.
  10638. //
  10639. // Arguments: [wcsFile] -- Path to file.
  10640. // [data] -- Contents of file.
  10641. // [cb] -- Size in bytes of [data]
  10642. //
  10643. // History: 22-Jul-92 KyleP Created
  10644. //
  10645. //--------------------------------------------------------------------------
  10646. void BuildFile( WCHAR const * wcsFile, char const * data, ULONG cb )
  10647. {
  10648. ULONG mode = CREATE_NEW;
  10649. HANDLE hFile = CreateFile( (WCHAR *)wcsFile,
  10650. GENERIC_WRITE,
  10651. 0,
  10652. 0,
  10653. mode,
  10654. 0,
  10655. 0 );
  10656. if ( hFile == INVALID_HANDLE_VALUE )
  10657. {
  10658. LogError( "Error 0x%lx opening file %ws\n", GetLastError(), wcsFile );
  10659. CantRun();
  10660. }
  10661. ULONG ulWritten;
  10662. if ( !WriteFile( hFile, data, cb, &ulWritten, 0 ) ||
  10663. ulWritten != cb )
  10664. {
  10665. LogError( "Error 0x%lx writing file %ws\n", GetLastError(), wcsFile );
  10666. CantRun();
  10667. }
  10668. if ( !CloseHandle( hFile ) )
  10669. {
  10670. LogError( "Error 0x%lx closing file %ws\n", GetLastError(), wcsFile );
  10671. CantRun();
  10672. }
  10673. } //BuildFile
  10674. //+-------------------------------------------------------------------------
  10675. //
  10676. // Function: CantRun, private
  10677. //
  10678. // Synopsis: Prints a "Can't Run" message and exits.
  10679. //
  10680. // History: 09 Oct 1995 Alanw Created
  10681. //
  10682. //--------------------------------------------------------------------------
  10683. void CantRun()
  10684. {
  10685. printf( "%s: CAN'T RUN\n", ProgName );
  10686. if (! _isatty(_fileno(stdout)) )
  10687. fprintf( stderr, "%s: CAN'T RUN\n", ProgName );
  10688. // CIShutdown();
  10689. CoUninitialize();
  10690. exit( 2 );
  10691. } //Fail
  10692. //+-------------------------------------------------------------------------
  10693. //
  10694. // Function: Fail, private
  10695. //
  10696. // Synopsis: Prints a failure message and exits.
  10697. //
  10698. // History: 22-Jul-92 KyleP Created
  10699. //
  10700. //--------------------------------------------------------------------------
  10701. void Fail()
  10702. {
  10703. printf( "%s: FAILED\n", ProgName );
  10704. if (! _isatty(_fileno(stdout)) )
  10705. fprintf( stderr, "%s: FAILED\n", ProgName );
  10706. // CIShutdown();
  10707. CoUninitialize();
  10708. exit( 1 );
  10709. } //Fail
  10710. //+-------------------------------------------------------------------------
  10711. //
  10712. // Function: LogProgress, public
  10713. //
  10714. // Synopsis: Prints a verbose-mode message.
  10715. //
  10716. // Arguments: [pszfmt] -- Format string
  10717. //
  10718. // History: 13-Jul-93 KyleP Created
  10719. //
  10720. //--------------------------------------------------------------------------
  10721. void LogProgress( char const * pszfmt, ... )
  10722. {
  10723. if ( fVerbose )
  10724. {
  10725. va_list pargs;
  10726. va_start(pargs, pszfmt);
  10727. vprintf( pszfmt, pargs );
  10728. va_end(pargs);
  10729. }
  10730. } //LogProgress
  10731. //+-------------------------------------------------------------------------
  10732. //
  10733. // Function: LogError, public
  10734. //
  10735. // Synopsis: Prints a verbose-mode message.
  10736. //
  10737. // Arguments: [pszfmt] -- Format string
  10738. //
  10739. // History: 13-Jul-93 KyleP Created
  10740. //
  10741. //--------------------------------------------------------------------------
  10742. static fLogError = TRUE;
  10743. void LogError( char const * pszfmt, ... )
  10744. {
  10745. if ( fVerbose || fLogError )
  10746. {
  10747. fLogError = FALSE; // print only first error if non-verbose
  10748. va_list pargs;
  10749. va_start(pargs, pszfmt);
  10750. vprintf( pszfmt, pargs );
  10751. va_end(pargs);
  10752. }
  10753. } //LogError
  10754. //+-------------------------------------------------------------------------
  10755. //
  10756. // Function: LogFail, public
  10757. //
  10758. // Synopsis: Prints a verbose-mode message and fails the drt
  10759. //
  10760. // Arguments: [pszfmt] -- Format string
  10761. //
  10762. // History: 3-Apr-95 dlee Created
  10763. //
  10764. //--------------------------------------------------------------------------
  10765. void LogFail( char const * pszfmt, ... )
  10766. {
  10767. if ( fVerbose || fLogError )
  10768. {
  10769. va_list pargs;
  10770. va_start(pargs, pszfmt);
  10771. vprintf( pszfmt, pargs );
  10772. va_end(pargs);
  10773. }
  10774. Fail();
  10775. } //LogFail
  10776. //+-------------------------------------------------------------------------
  10777. //
  10778. // Function: FormatGuid, public
  10779. //
  10780. // Synopsis: Formats a guid in standard form
  10781. //
  10782. // Arguments: [pszfmt] -- Format string
  10783. //
  10784. // Returns: PWSTR - pointer to formatted guid
  10785. //
  10786. // Notes: Return value points to static memory.
  10787. //
  10788. // History: 12 Sep 1997 AlanW Created
  10789. //
  10790. //--------------------------------------------------------------------------
  10791. WCHAR * FormatGuid( GUID const & guid )
  10792. {
  10793. static WCHAR awchGuid[40];
  10794. StringFromGUID2( guid, awchGuid, sizeof awchGuid / sizeof WCHAR );
  10795. return awchGuid;
  10796. } //FormatGuid
  10797. BOOL CheckTime()
  10798. {
  10799. if ( fTimeout )
  10800. {
  10801. time_t tend;
  10802. //
  10803. // Did we run out of time?
  10804. //
  10805. time( &tend );
  10806. return ( difftime( tend, tstart ) <= MAXTIME );
  10807. }
  10808. else
  10809. {
  10810. return( TRUE );
  10811. }
  10812. } //CheckTime
  10813. /////////////////////////////////////////////////////////////////////////
  10814. /////////////////////////////////////////////////////////////////////////
  10815. /////////////////////////////////////////////////////////////////////////
  10816. /////////////////////////////////////////////////////////////////////////
  10817. /////////////////////////////////////////////////////////////////////////
  10818. /////////////////////////////////////////////////////////////////////////
  10819. /////////////////////////////////////////////////////////////////////////
  10820. #if defined(UNIT_TEST)
  10821. //+-------------------------------------------------------------------------
  10822. //
  10823. // Class: CCompareDBValues
  10824. //
  10825. // Purpose: Compares oledb values.
  10826. //
  10827. // History: 25-May-95 dlee Created
  10828. //
  10829. //--------------------------------------------------------------------------
  10830. class CCompareDBValues : INHERIT_UNWIND
  10831. {
  10832. INLINE_UNWIND( CCompareDBValues )
  10833. public:
  10834. CCompareDBValues() : _aColComp( 0 ), _cColComp( 0 )
  10835. { END_CONSTRUCTION( CCompareDBValues ); }
  10836. ~CCompareDBValues() { delete _aColComp; }
  10837. void Init( int cCols,
  10838. CSortSet const * psort,
  10839. DBTYPEENUM * aTypes );
  10840. inline BOOL IsEmpty() { return( _aColComp == 0 ); }
  10841. BOOL IsLT( BYTE ** rows1, ULONG *acb1, BYTE **rows2, ULONG *acb2 );
  10842. BOOL IsGT( BYTE ** rows1, ULONG *acb1, BYTE **rows2, ULONG *acb2 );
  10843. BOOL IsEQ( BYTE ** rows1, ULONG *acb1, BYTE **rows2, ULONG *acb2 );
  10844. private:
  10845. struct SColCompare
  10846. {
  10847. ULONG _dir; // Direction
  10848. ULONG _pt; // Property type (matches fns below)
  10849. //
  10850. // LE/GE are a bit of a misnomer. If the sort order for a column
  10851. // is reversed ( large to small ) then LE is really GE and
  10852. // vice-versa.
  10853. //
  10854. FDBCmp _comp;
  10855. int _DirMult; // -1 if directions reversed.
  10856. };
  10857. UINT _cColComp;
  10858. SColCompare * _aColComp;
  10859. };
  10860. //+-------------------------------------------------------------------------
  10861. //
  10862. // Member: CCompareDBValues::Init, public
  10863. //
  10864. // Synopsis: [Re] Initializes property comparator to use a different
  10865. // sort order.
  10866. //
  10867. // Arguments: [cCols] -- Count of columns
  10868. // [pSort] -- Sort keys
  10869. // [aTypes] -- Data types of each column to be compared
  10870. //
  10871. // History: 25-May-95 dlee Created
  10872. //
  10873. //--------------------------------------------------------------------------
  10874. void CCompareDBValues::Init( int cCols,
  10875. CSortSet const * pSort,
  10876. DBTYPEENUM * aTypes )
  10877. {
  10878. delete _aColComp;
  10879. _aColComp = 0;
  10880. if ( cCols > 0 )
  10881. {
  10882. _cColComp = cCols;
  10883. _aColComp = new SColCompare[ _cColComp ];
  10884. for ( unsigned i = 0; i < _cColComp; i++ )
  10885. {
  10886. _aColComp[i]._dir = pSort->Get(i).dwOrder;
  10887. _aColComp[i]._DirMult =
  10888. ( ( _aColComp[i]._dir & QUERY_SORTDESCEND ) != 0 ) ? -1 : 1;
  10889. _aColComp[i]._pt = aTypes[i];
  10890. _aColComp[i]._comp = VariantCompare.GetDBComparator( aTypes[i] );
  10891. }
  10892. }
  10893. } //Init
  10894. //+-------------------------------------------------------------------------
  10895. //
  10896. // Member: CCompareDBValues::IsLT, public
  10897. //
  10898. // Synopsis: Compares two rows (property sets).
  10899. //
  10900. // Arguments: [row1] -- First row.
  10901. // [row2] -- Second row.
  10902. //
  10903. // Returns: TRUE if [row1] < [row2].
  10904. //
  10905. // History: 25-May-95 dlee Created
  10906. //
  10907. //--------------------------------------------------------------------------
  10908. BOOL CCompareDBValues::IsLT(
  10909. BYTE ** row1,
  10910. ULONG * acb1,
  10911. BYTE ** row2,
  10912. ULONG * acb2 )
  10913. {
  10914. //Win4Assert( !IsEmpty() );
  10915. int iLT = 0;
  10916. for ( unsigned i = 0; 0 == iLT && i < _cColComp; i++ )
  10917. {
  10918. if ( 0 != _aColComp[i]._comp )
  10919. iLT = _aColComp[i]._comp( row1[i],
  10920. acb1[i],
  10921. row2[i],
  10922. acb2[i] ) *
  10923. _aColComp[i]._DirMult;
  10924. else
  10925. LogFail("islt has no comparator!\n");
  10926. }
  10927. return ( iLT < 0 );
  10928. } //IsLT
  10929. //+-------------------------------------------------------------------------
  10930. //
  10931. // Member: CCompareDBValues::IsGT, public
  10932. //
  10933. // Synopsis: Compares two rows (property sets).
  10934. //
  10935. // Arguments: [row1] -- First row.
  10936. // [row2] -- Second row.
  10937. //
  10938. // Returns: TRUE if [row1] > [row2].
  10939. //
  10940. // History: 25-May-95 dlee Created
  10941. //
  10942. //--------------------------------------------------------------------------
  10943. BOOL CCompareDBValues::IsGT(
  10944. BYTE ** row1,
  10945. ULONG * acb1,
  10946. BYTE ** row2,
  10947. ULONG * acb2 )
  10948. {
  10949. //Win4Assert( !IsEmpty() );
  10950. int iGT = 0;
  10951. for ( unsigned i = 0; 0 == iGT && i < _cColComp; i++ )
  10952. {
  10953. if ( 0 != _aColComp[i]._comp )
  10954. iGT = _aColComp[i]._comp( row1[i],
  10955. acb1[i],
  10956. row2[i],
  10957. acb2[i] ) *
  10958. _aColComp[i]._DirMult;
  10959. }
  10960. return ( iGT > 0 );
  10961. } //IsGT
  10962. //+-------------------------------------------------------------------------
  10963. //
  10964. // Member: CCompareDBValues::IsEQ, public
  10965. //
  10966. // Synopsis: Compares two rows (property sets).
  10967. //
  10968. // Arguments: [row1] -- First row.
  10969. // [row2] -- Second row.
  10970. //
  10971. // Returns: TRUE if [row1] == [row2].
  10972. //
  10973. // History: 25-May-95 dlee Created
  10974. //
  10975. //--------------------------------------------------------------------------
  10976. BOOL CCompareDBValues::IsEQ(
  10977. BYTE ** row1,
  10978. ULONG * acb1,
  10979. BYTE ** row2,
  10980. ULONG * acb2 )
  10981. {
  10982. //Win4Assert( !IsEmpty() );
  10983. int iEQ = 0;
  10984. for ( unsigned i = 0; 0 == iEQ && i < _cColComp; i++ )
  10985. {
  10986. if ( 0 != _aColComp[i]._comp )
  10987. iEQ = _aColComp[i]._comp( row1[i],
  10988. acb1[i],
  10989. row2[i],
  10990. acb2[i] );
  10991. }
  10992. return ( iEQ == 0 );
  10993. } //IsEQ
  10994. struct SSortTestRow
  10995. {
  10996. PROPVARIANT vI4; // variant: i4
  10997. PROPVARIANT vV_I4; // variant: i4 vector
  10998. DBVECTOR aI4; // dbvector: i4
  10999. WCHAR aWSTR[20]; // inline: wstr
  11000. WCHAR * pWSTR; // inline: byref wstr
  11001. PROPVARIANT vLPWSTR; // variant: lpwstr
  11002. PROPVARIANT vV_LPWSTR; // variant: lpwstr vector
  11003. DBVECTOR aLPWSTR; // dbvector: byref wstr
  11004. int i; // inline: i4
  11005. };
  11006. long ai4[] = { 3, 7, 9 };
  11007. LPWSTR alpwstr[] = { L"one", L"two", L"three" };
  11008. void InitTest( SSortTestRow &s )
  11009. {
  11010. s.vI4.vt = VT_I4;
  11011. s.vI4.lVal = 4;
  11012. s.vV_I4.vt = VT_VECTOR | VT_I4;
  11013. s.vV_I4.cal.cElems = 3;
  11014. s.vV_I4.cal.pElems = ai4;
  11015. s.aI4.size = 3;
  11016. s.aI4.ptr = ai4;
  11017. s.aWSTR[0] = L'h';
  11018. s.aWSTR[1] = L'e';
  11019. s.aWSTR[2] = L'l';
  11020. s.pWSTR = L"yello";
  11021. s.vLPWSTR.vt = VT_LPWSTR;
  11022. s.vLPWSTR.pwszVal = L"green";
  11023. s.vV_LPWSTR.vt = VT_VECTOR | VT_LPWSTR;
  11024. s.vV_LPWSTR.calpwstr.cElems = 3;
  11025. s.vV_LPWSTR.calpwstr.pElems = alpwstr;
  11026. s.aLPWSTR.size = 3;
  11027. s.aLPWSTR.ptr = alpwstr;
  11028. } //InitTest
  11029. SSortTestRow sr1,sr2,sr3;
  11030. BYTE * apr1[] =
  11031. {
  11032. { (BYTE *) & sr1.vI4 },
  11033. { (BYTE *) & sr1.vV_I4 },
  11034. { (BYTE *) & sr1.aI4 },
  11035. { (BYTE *) & sr1.aWSTR },
  11036. { (BYTE *) & sr1.pWSTR },
  11037. { (BYTE *) & sr1.vLPWSTR },
  11038. { (BYTE *) & sr1.vV_LPWSTR },
  11039. { (BYTE *) & sr1.aLPWSTR },
  11040. { (BYTE *) & sr1.i },
  11041. };
  11042. BYTE * apr2[] =
  11043. {
  11044. { (BYTE *) & sr2.vI4 },
  11045. { (BYTE *) & sr2.vV_I4 },
  11046. { (BYTE *) & sr2.aI4 },
  11047. { (BYTE *) & sr2.aWSTR },
  11048. { (BYTE *) & sr2.pWSTR },
  11049. { (BYTE *) & sr2.vLPWSTR },
  11050. { (BYTE *) & sr2.vV_LPWSTR },
  11051. { (BYTE *) & sr2.aLPWSTR },
  11052. { (BYTE *) & sr2.i },
  11053. };
  11054. BYTE * apr3[] =
  11055. {
  11056. { (BYTE *) & sr3.vI4 },
  11057. { (BYTE *) & sr3.vV_I4 },
  11058. { (BYTE *) & sr3.aI4 },
  11059. { (BYTE *) & sr3.aWSTR },
  11060. { (BYTE *) & sr3.pWSTR },
  11061. { (BYTE *) & sr3.vLPWSTR },
  11062. { (BYTE *) & sr3.vV_LPWSTR },
  11063. { (BYTE *) & sr3.aLPWSTR },
  11064. { (BYTE *) & sr3.i },
  11065. };
  11066. DBTYPEENUM aEnum[] =
  11067. {
  11068. { DBTYPE_VARIANT },
  11069. { DBTYPE_VARIANT },
  11070. { (DBTYPEENUM) (DBTYPE_VECTOR | DBTYPE_I4) },
  11071. { DBTYPE_WSTR },
  11072. { (DBTYPEENUM) (DBTYPE_BYREF | DBTYPE_WSTR) },
  11073. { DBTYPE_VARIANT },
  11074. { DBTYPE_VARIANT },
  11075. { (DBTYPEENUM) (DBTYPE_VECTOR | DBTYPE_BYREF | DBTYPE_WSTR) },
  11076. { DBTYPE_I4 },
  11077. };
  11078. ULONG aLen[] =
  11079. {
  11080. 0,
  11081. 0,
  11082. 0,
  11083. 6,
  11084. 0,
  11085. 0,
  11086. 0,
  11087. 0,
  11088. };
  11089. const ULONG cArray = sizeof aEnum / sizeof DBTYPEENUM;
  11090. void DBSortTest()
  11091. {
  11092. InitTest( sr1 );
  11093. sr1.i = 1;
  11094. InitTest( sr2 );
  11095. sr2.i = 2;
  11096. InitTest( sr3 );
  11097. sr3.i = 3;
  11098. CSortSet ss( cArray );
  11099. SSortKey sk = { 0, 0, 0 };
  11100. for (unsigned x = 0; x < cArray; x++)
  11101. ss.Add( sk, x );
  11102. CCompareDBValues c;
  11103. c.Init( cArray, &ss, aEnum );
  11104. BOOL fLT = c.IsLT( apr1, aLen, apr2, aLen );
  11105. if (!fLT)
  11106. LogFail("compare test 1 failed\n");
  11107. fLT = c.IsLT( apr2, aLen, apr1, aLen );
  11108. if (fLT)
  11109. LogFail("compare test 2 failed\n");
  11110. } //DBSortTest
  11111. #endif // UNIT_TEST
  11112. BOOL SetBooleanProperty ( ICommand * pCmd, DBPROPID dbprop, VARIANT_BOOL f )
  11113. {
  11114. ICommandProperties * pCmdProp;
  11115. SCODE sc = pCmd->QueryInterface( IID_ICommandProperties, (void **) &pCmdProp );
  11116. if ( FAILED( sc ) )
  11117. {
  11118. LogError( "Error 0x%x from QI for ICommandProperties\n", sc );
  11119. return sc;
  11120. }
  11121. DBPROPSET aPropSet[1];
  11122. DBPROP aProp[1];
  11123. aProp[0].dwPropertyID = dbprop;
  11124. aProp[0].dwOptions = DBPROPOPTIONS_REQUIRED;
  11125. aProp[0].dwStatus = 0; // Ignored
  11126. aProp[0].colid = dbcolNull;
  11127. aProp[0].vValue.vt = VT_BOOL;
  11128. aProp[0].vValue.boolVal = f;
  11129. aPropSet[0].rgProperties = &aProp[0];
  11130. aPropSet[0].cProperties = 1;
  11131. aPropSet[0].guidPropertySet = DBPROPSET_ROWSET;
  11132. sc = pCmdProp->SetProperties( 1, aPropSet );
  11133. pCmdProp->Release();
  11134. if ( FAILED(sc) )
  11135. LogError( "ICommandProperties::SetProperties returned 0x%x\n", sc );
  11136. return sc;
  11137. }
  11138. SCODE SetScopeProperties( ICommand * pCmd,
  11139. unsigned cDirs,
  11140. WCHAR const * const * apDirs,
  11141. ULONG const * aulFlags,
  11142. WCHAR const * const * apCats,
  11143. WCHAR const * const * apMachines )
  11144. {
  11145. ICommandProperties * pCmdProp;
  11146. SCODE sc = pCmd->QueryInterface( IID_ICommandProperties, (void **) &pCmdProp );
  11147. if ( FAILED( sc ) )
  11148. {
  11149. LogError( "Error 0x%x from QI for ICommandProperties\n", sc );
  11150. return sc;
  11151. }
  11152. BSTR abDirs[10];
  11153. if ( 0 != apDirs )
  11154. for ( unsigned i = 0; i < cDirs; i++ )
  11155. abDirs[i] = SysAllocString( apDirs[i] );
  11156. BSTR abCats[10];
  11157. if ( 0 != apCats )
  11158. for ( unsigned i = 0; i < cDirs; i++ )
  11159. abCats[i] = SysAllocString( apCats[i] );
  11160. BSTR abMachines[10];
  11161. if ( 0 != apMachines )
  11162. for ( unsigned i = 0; i < cDirs; i++ )
  11163. abMachines[i] = SysAllocString( apMachines[i] );
  11164. //
  11165. // Cheating here. Big time. These aren't really BSTRs, but I also know the
  11166. // size before the string won't be referenced. By ::SetProperties.
  11167. //
  11168. SAFEARRAY saScope = { 1, // Dimension
  11169. FADF_AUTO | FADF_BSTR, // Flags: on stack, contains BSTRs
  11170. sizeof(BSTR), // Size of an element
  11171. 1, // Lock count. 1 for safety.
  11172. (void *)abDirs, // The data
  11173. { cDirs, 0 } }; // Bounds (element count, low bound)
  11174. SAFEARRAY saDepth = { 1, // Dimension
  11175. FADF_AUTO, // Flags: on stack
  11176. sizeof(LONG), // Size of an element
  11177. 1, // Lock count. 1 for safety.
  11178. (void *)aulFlags, // The data
  11179. { cDirs, 0 } }; // Bounds (element count, low bound)
  11180. SAFEARRAY saCatalog = { 1, // Dimension
  11181. FADF_AUTO | FADF_BSTR,// Flags: on stack, contains BSTRs
  11182. sizeof(BSTR), // Size of an element
  11183. 1, // Lock count. 1 for safety.
  11184. (void *)abCats, // The data
  11185. { cDirs, 0 } }; // Bounds (element count, low bound)
  11186. SAFEARRAY saMachine = { 1, // Dimension
  11187. FADF_AUTO | FADF_BSTR,// Flags: on stack, contains BSTRs
  11188. sizeof(BSTR), // Size of an element
  11189. 1, // Lock count. 1 for safety.
  11190. (void *)abMachines, // The data
  11191. { cDirs, 0 } }; // Bounds (element count, low bound)
  11192. DBPROP aQueryPropsScopeOnly[2] = { { DBPROP_CI_INCLUDE_SCOPES, 0, DBPROPSTATUS_OK, {0, 0, 0}, { VT_BSTR | VT_ARRAY, 0, 0, 0, (LONG_PTR)&saScope } },
  11193. { DBPROP_CI_DEPTHS , 0, DBPROPSTATUS_OK, {0, 0, 0}, { VT_I4 | VT_ARRAY, 0, 0, 0, (LONG_PTR)&saDepth } } };
  11194. DBPROPSET QueryPropsetScopeOnly = { aQueryPropsScopeOnly, 2, DBPROPSET_FSCIFRMWRK_EXT };
  11195. DBPROP aQueryProps[3] = { { DBPROP_CI_INCLUDE_SCOPES , 0, DBPROPSTATUS_OK, {0, 0, 0}, { VT_BSTR | VT_ARRAY, 0, 0, 0, (LONG_PTR)&saScope } },
  11196. { DBPROP_CI_DEPTHS , 0, DBPROPSTATUS_OK, {0, 0, 0}, { VT_I4 | VT_ARRAY, 0, 0, 0, (LONG_PTR)&saDepth } },
  11197. { DBPROP_CI_CATALOG_NAME , 0, DBPROPSTATUS_OK, {0, 0, 0}, { VT_BSTR | VT_ARRAY, 0, 0, 0, (LONG_PTR)&saCatalog } } };
  11198. DBPROP aCoreProps[1] = { { DBPROP_MACHINE , 0, DBPROPSTATUS_OK, {0, 0, 0}, { VT_BSTR | VT_ARRAY, 0, 0, 0, (LONG_PTR)&saMachine } } };
  11199. DBPROPSET aAllPropsets[2] = { {aQueryProps, 3, DBPROPSET_FSCIFRMWRK_EXT } ,
  11200. {aCoreProps , 1, DBPROPSET_CIFRMWRKCORE_EXT } };
  11201. if ( 0 == apCats || 0 == apMachines )
  11202. sc = pCmdProp->SetProperties( 1, &QueryPropsetScopeOnly );
  11203. else
  11204. sc = pCmdProp->SetProperties( 2, aAllPropsets );
  11205. if ( 0 != apMachines )
  11206. for ( unsigned i = 0; i < cDirs; i++ )
  11207. SysFreeString( abMachines[i] );
  11208. if ( 0 != apCats )
  11209. for ( unsigned i = 0; i < cDirs; i++ )
  11210. SysFreeString( abCats[i] );
  11211. if ( 0 != apDirs )
  11212. for ( unsigned i = 0; i < cDirs; i++ )
  11213. SysFreeString( abDirs[i] );
  11214. pCmdProp->Release();
  11215. if ( FAILED(sc) )
  11216. LogError( "ICommandProperties::SetProperties returned 0x%x\n", sc );
  11217. return sc;
  11218. }