|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2001.
//
// File: tdbv1.CXX
//
// Contents: Test program for OLE-DB phase 3 interface classes.
//
// TODO:
// Large result sets
//
// History: 30 June 1994 Alanw Created (from cidrt)
// 10 Nov. 1994 Alanw Converted for OLE-DB phase 3 interfaces
// 01 Oct. 1996 Alanw Converted for OLE-DB V1.0 interfaces
//
//--------------------------------------------------------------------------
#define DO_NOTIFICATION
#define DO_CATEG_TESTS
#define DO_CONTENT_TESTS
#define DO_MULTI_LEVEL_CATEG_TEST
extern "C" { #include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <olectl.h>
}
#include <windows.h>
#if !defined(UNIT_TEST)
#define DBINITCONSTANTS
#if !defined(OLEDBVER)
#define OLEDBVER 0x0250
#endif // !OLEDBVER
#endif // !UNIT_TEST
#include <oledb.h>
#include <oledberr.h>
#include <ntquery.h>
#include <query.h>
#include <ciintf.h>
#include <cierror.h>
#include <stgprop.h>
#include <vquery.hxx>
#include <dbcmdtre.hxx>
#include <crt\io.h>
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <time.h>
#include <process.h>
#include <propapi.h>
#include <propvar.h>
#include <oleext.h>
#include <initguid.h>
#include <srvprvdr.h>
#if defined(UNIT_TEST)
#define PROG_NAME "tdbv1"
//#include "tabledbg.hxx"
#else // !UNIT_TEST
#define PROG_NAME "fsdbdrt"
#endif // UNIT_TEST
#if defined(UNIT_TEST)
#include <compare.hxx>
#include <coldesc.hxx>
#endif
WCHAR *pwcThisMachine = L"."; #define TEST_MACHINE ( pwcThisMachine )
WCHAR const wcsDefaultTestCatalog[] = L"::_noindex_::"; #define TEST_CATALOG ( wcsTestCatalog )
WCHAR const wcsDefaultContentCatalog[] = L"system"; #define CONTENT_CATALOG ( wcsDefaultContentCatalog )
BOOL isEven(unsigned n) { return !(n & 0x1); }
//
// Maximum time for test to complete.
//
int const MAXTIME = 120; int const MINREPORTTIME = 5; int const MAXWAITTIME = 10;
int const MAXCOLUMNS = 20;
const int cbPV = sizeof PROPVARIANT; const int cbPPV = sizeof( PROPVARIANT * );
const HCHAPTER DBCHP_FIRST = 1;
time_t tstart; BOOL CheckTime();
//
// Test files
//
WCHAR const wcsTestDir[] = L"QueryTest"; WCHAR const wcsTestFile[] = L"Test file for OFS Query";
WCHAR const wcsPropFile[] = L"Test file for Property Query.txt"; WCHAR const wcsPropFile2[] = L"Test file for Property Query2.txt";
WCHAR const wcsTestCiFile1[] = L"Test file for OFS Content Query1.txt"; WCHAR const wcsTestCiFile2[] = L"Test file for OFS Content Query2.txt"; WCHAR const wcsTestCiFile3[] = L"Test file for OFS Content Query3.txt";
DBOBJECT dbPersistObject;
// For testing safearrays of various types.
GUID const guidArray = { 0x92452ac2, 0xfcbb, 0x11d1, 0xb7, 0xca, 0x00, 0xa0, 0xc9, 0x06, 0xb2, 0x39 };
//
// Storage Properties
//
#define PSID_PSSecurityTest { 0xa56168e0, \
0x0ef3, 0x11cf, \ 0xbb, 0x01, 0x00, 0x00, 0x4c, 0x75, 0x2a, 0x9a }
#define PSID_PSMyPropSet { 0x49691CF4, \
0x7E17, 0x101A, \ 0xA9, 0x1C, 0x08, 0x00, 0x2B, 0x2E, 0xCD, 0xA9 }
#define guidZero { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
GUID const guidMyPropSet = PSID_PSMyPropSet; GUID const guidSecurityTest = PSID_PSSecurityTest;
const DBID dbcolNull = { {0,0,0,{0,0,0,0,0,0,0,0}},DBKIND_GUID_PROPID,0}; const GUID guidQueryExt = DBPROPSET_QUERYEXT;
const GUID guidFsCiFrmwrkExt = DBPROPSET_FSCIFRMWRK_EXT;
const GUID guidCiFrmwrkExt = DBPROPSET_CIFRMWRKCORE_EXT;
const GUID guidMsidxsExt = DBPROPSET_MSIDXS_ROWSETEXT;
CDbColId const psSecurityTest = CDbColId( guidSecurityTest, 2 );
CDbColId const psTestProperty1 = CDbColId( guidMyPropSet, 2 ); CDbColId const psTestProperty2 = CDbColId( guidMyPropSet, L"A Property" ); CDbColId const psTestProperty10 = CDbColId( guidMyPropSet, L"An Empty Property" ); CDbColId const psTestProperty11 = CDbColId( guidMyPropSet, L"A Bstr Property" ); CDbColId const psTestProperty12 = CDbColId( guidMyPropSet, L"A Bstr Vector Property" ); CDbColId const psBlobTest = CDbColId( guidMyPropSet, L"BlobTest" ); CDbColId const psGuidTest = CDbColId( guidMyPropSet, L"GuidTest" );
CDbColId const psTestProperty13 = CDbColId( guidMyPropSet, 13 ); CDbColId const psTestProperty14 = CDbColId( guidMyPropSet, 14 ); CDbColId const psTestProperty15 = CDbColId( guidMyPropSet, 15 ); CDbColId const psTestProperty16 = CDbColId( guidMyPropSet, 16 ); CDbColId const psTestProperty17 = CDbColId( guidMyPropSet, 17 ); CDbColId const psTestProperty18 = CDbColId( guidMyPropSet, 18 ); CDbColId const psTestProperty19 = CDbColId( guidMyPropSet, 19 ); CDbColId const psTestProperty20 = CDbColId( guidMyPropSet, 20 );
CDbColId const psTestProperty21 = CDbColId( guidMyPropSet, 21 ); CDbColId const psTestProperty22 = CDbColId( guidMyPropSet, 22 );
#ifndef PROPID_PSDocument
//#include <winole.h>
#define PSID_PSDocument { \
0xF29F85E0, \ 0x4FF9, 0x1068, \ 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9 \ } #define PROPID_PSDocument_Author 4
#define PROPID_PSDocument_Keywords 5
#endif // PROPID_PSDocument
static GUID guidDocument = PSID_PSDocument;
CDbColId const psAuthor = CDbColId( guidDocument, PROPID_PSDocument_Author ); CDbColId const psKeywords = CDbColId( guidDocument, PROPID_PSDocument_Keywords );
CDbColId const psRelevantWords = CDbColId( guidMyPropSet, L"RelevantWords" );
CDbColId const psManyRW = CDbColId( guidMyPropSet, L"ManyRW" );
PROPVARIANT varProp1; PROPVARIANT varProp2; PROPVARIANT varProp3; PROPVARIANT varProp4; PROPVARIANT varProp5; PROPVARIANT varProp6; PROPVARIANT varProp7; PROPVARIANT varProp8, varProp8A; PROPVARIANT varProp9; PROPVARIANT varProp10; PROPVARIANT varProp11, varProp11A; PROPVARIANT varProp12; // for coercion test
PROPVARIANT varProp13; PROPVARIANT varProp14; PROPVARIANT varProp15; PROPVARIANT varProp16; PROPVARIANT varProp17; PROPVARIANT varProp18, varProp18A; PROPVARIANT varProp19; PROPVARIANT varProp20; PROPVARIANT varProp21; PROPVARIANT varProp22;
VARTYPE const PROP1_TYPE = VT_I4; VARTYPE const PROP2_TYPE = VT_LPWSTR; VARTYPE const PROP3_TYPE = VT_LPWSTR; VARTYPE const PROP4_TYPE = (VT_VECTOR|VT_LPWSTR); VARTYPE const PROP5_TYPE = (VT_VECTOR|VT_I4); VARTYPE const PROP6_TYPE = VT_BLOB; VARTYPE const PROP7_TYPE = VT_CLSID; VARTYPE const PROP8_TYPE = (VT_VECTOR|VT_I4); VARTYPE const PROP9_TYPE = VT_I4; VARTYPE const PROP10_TYPE = VT_LPWSTR; VARTYPE const PROP11_TYPE = VT_BSTR; VARTYPE const PROP12_TYPE = (VT_VECTOR|VT_BSTR); // for coercion test
VARTYPE const PROP13_TYPE = VT_UI1; VARTYPE const PROP14_TYPE = VT_I2; VARTYPE const PROP15_TYPE = VT_UI2; VARTYPE const PROP16_TYPE = VT_I4; VARTYPE const PROP17_TYPE = VT_R4; VARTYPE const PROP18_TYPE = VT_R8; VARTYPE const PROP19_TYPE = VT_BOOL; VARTYPE const PROP20_TYPE = VT_LPSTR; VARTYPE const PROP21_TYPE = VT_CF; VARTYPE const PROP22_TYPE = VT_CF | VT_VECTOR;
const long PROP1_VAL = 1234; #define PROP1_cb ( sizeof ULONG )
const long PROP1_VAL_Alternate = 123;
const WCHAR * PROP2_VAL = L"Wow! In a property."; #define PROP2_cb ( ( sizeof WCHAR ) * ( wcslen(PROP2_VAL) ) )
const WCHAR * PROP3_VAL = L"AlanW"; #define PROP3_cb ( ( sizeof WCHAR ) * ( wcslen(PROP3_VAL) ) )
const WCHAR * alpwstrProp4[] = { L"This", L"is", L"a", L"Vector", L"Property", }; const int clpwstrProp4 = (sizeof alpwstrProp4 / sizeof (WCHAR *)); const CALPWSTR PROP4_VAL = { clpwstrProp4, (WCHAR * *) alpwstrProp4 }; #define PROP4_cb 0
const LONG SecondRelevantWord = 0x23;
LONG alProp5[] = { 0x12, SecondRelevantWord, 0x35, 0x47, 0x59 }; const int clProp5 = (sizeof alProp5 / sizeof (LONG)); CAL PROP5_VAL = { clProp5, &alProp5[0] };
LONG alProp5Less[] = { alProp5[0]-1, alProp5[1]-1, alProp5[2]-1, alProp5[3]-1, alProp5[4]-1 }; const int clProp5Less = (sizeof alProp5Less / sizeof (LONG)); CAL PROP5_VAL_LESS = { clProp5Less, &alProp5Less[0] };
LONG alProp5More[] = { alProp5[0]+1, alProp5[1]+1, alProp5[2]+1, alProp5[3]+1, alProp5[4]+1 }; const int clProp5More = (sizeof alProp5More / sizeof (LONG)); CAL PROP5_VAL_MORE = { clProp5More, &alProp5More[0] };
LONG alProp5AllLess[] = { 1, 2, 3, 4, 5 }; const int clProp5AllLess = (sizeof alProp5AllLess / sizeof (LONG)); CAL PROP5_VAL_ALLLESS = { clProp5AllLess, &alProp5AllLess[0] };
LONG alProp5AllMore[] = { 0xffff, 0xfffe, 0xfffd, 0xfffc, 0xfffb }; const int clProp5AllMore = (sizeof alProp5AllMore / sizeof (LONG)); CAL PROP5_VAL_ALLMORE = { clProp5AllMore, &alProp5AllMore[0] };
LONG alProp5Jumble[] = { alProp5[4], alProp5[3], alProp5[1], alProp5[2], alProp5[0] }; const int clProp5Jumble = (sizeof alProp5Jumble / sizeof (LONG)); CAL PROP5_VAL_JUMBLE = { clProp5Jumble, &alProp5Jumble[0] };
LONG alProp5Like[] = { 0x1, 0x1, 0x2, 0x3, SecondRelevantWord }; const int clProp5Like = (sizeof alProp5Like / sizeof (LONG)); CAL PROP5_VAL_LIKE = { clProp5Like, &alProp5Like[0] };
LONG alProp5None[] = { 0x1, 0x1, 0x2, 0x3, 0x4 }; const int clProp5None = (sizeof alProp5None / sizeof (LONG)); CAL PROP5_VAL_NONE = { clProp5None, &alProp5None[0] }; #define PROP5_cb 0
BLOB PROP6_VAL = { sizeof alProp5, (BYTE*) &alProp5[0] }; #define PROP6_cb ( sizeof PROPVARIANT )
GUID PROP7_VAL = guidMyPropSet; #define PROP7_cb ( sizeof GUID )
#define PROP7_STR_VAL "{49691CF4-7E17-101A-A91C-08002B2ECDA9}"
// note: loading the value of prop8 will be deferred
LONG alProp8[5000]; const int clProp8 = (sizeof alProp8 / sizeof (LONG)); CAL PROP8_VAL = { clProp8, &alProp8[0] }; #define PROP8_cb 0
const long PROP9_VAL = 4321; #define PROP9_cb ( sizeof ULONG )
const WCHAR * PROP10_VAL = L""; // an empty string
#define PROP10_cb ( ( sizeof WCHAR ) * (wcslen(PROP10_VAL) ) )
const WCHAR * PROP11_VAL = L"This is a BSTR"; // string for a BSTR prop
WCHAR PROP11_LONGVAL[5000] = L"This is a large BSTR "; // string for a BSTR prop
const char PROP13_VAL = 65; #define PROP13_cb ( sizeof char )
#define PROP13_STR_VAL "65"
const short PROP14_VAL = -1234; #define PROP14_cb ( sizeof short )
#define PROP14_STR_VAL "-1234"
const unsigned short PROP15_VAL = 1234; #define PROP15_cb ( sizeof (unsigned short) )
#define PROP15_STR_VAL "1234"
const int PROP16_VAL = -1234; #define PROP16_cb ( sizeof int )
#define PROP16_STR_VAL "-1234"
const float PROP17_VAL = 1234.5678F; #define PROP17_cb ( sizeof (float) )
// This would get truncated in result as we supply a smaller buffer
#define PROP17_STR_VAL "123"
const double PROP18_VAL = 1234.12345678; #define PROP18_cb ( sizeof double )
#define PROP18_STR_VAL "1234.12345678"
const WORD PROP19_VAL = 0; #define PROP19_cb ( sizeof WORD )
#define PROP19_STR_VAL "False"
const LPSTR PROP20_VAL = "1245.5678"; #define PROP20_cb ( strlen( PROP20_VAL ) )
#define PROP20_DBL_VAL 1245.5678
// note: not all the data in the CF is used, just the # of bytes specified
CLIPDATA aClipData[3] = { { 20, 3, (BYTE *) "abcdefghijklmnopqrstuvwxyz" }, { 16, 5, (BYTE *) "zyxwvutsrqponmlkjihgfedcba" }, { 24, 7, (BYTE *) "01234567abcdefghijklmnopqrstuvwxyz" }, };
#define PROP21_cb (sizeof( void *) )
#define PROP21_VAL &aClipData[0]
#define PROP22_cb 0
#define PROP22_VAL aClipData
#define PROP22_CVALS ( sizeof aClipData / sizeof aClipData[0] )
// safearray propvariants:
PROPVARIANT vaI4; PROPSPEC psSA_I4 = { PRSPEC_PROPID, 2 }; CDbColId const colSA_I4 = CDbColId( guidArray, 2 ); PROPVARIANT vaBSTR; PROPSPEC psSA_BSTR = { PRSPEC_PROPID, 3 }; CDbColId const colSA_BSTR = CDbColId( guidArray, 3 ); PROPVARIANT vaVARIANT; PROPSPEC psSA_VARIANT = { PRSPEC_PROPID, 4 }; CDbColId const colSA_VARIANT = CDbColId( guidArray, 4 ); PROPVARIANT vaR8; PROPSPEC psSA_R8 = { PRSPEC_PROPID, 5 }; CDbColId const colSA_R8 = CDbColId( guidArray, 5 ); PROPVARIANT vaDATE; PROPSPEC psSA_DATE = { PRSPEC_PROPID, 6 }; CDbColId const colSA_DATE = CDbColId( guidArray, 6 ); PROPVARIANT vaBOOL; PROPSPEC psSA_BOOL = { PRSPEC_PROPID, 7 }; CDbColId const colSA_BOOL = CDbColId( guidArray, 7 ); PROPVARIANT vaDECIMAL; PROPSPEC psSA_DECIMAL = { PRSPEC_PROPID, 8 }; CDbColId const colSA_DECIMAL = CDbColId( guidArray, 8 ); PROPVARIANT vaI1; PROPSPEC psSA_I1 = { PRSPEC_PROPID, 9 }; CDbColId const colSA_I1 = CDbColId( guidArray, 9 ); PROPVARIANT vaR4; PROPSPEC psSA_R4 = { PRSPEC_PROPID, 10 }; CDbColId const colSA_R4 = CDbColId( guidArray, 10 ); PROPVARIANT vaCY; PROPSPEC psSA_CY = { PRSPEC_PROPID, 11 }; CDbColId const colSA_CY = CDbColId( guidArray, 11 ); PROPVARIANT vaUINT; PROPSPEC psSA_UINT = { PRSPEC_PROPID, 12 }; CDbColId const colSA_UINT = CDbColId( guidArray, 12 ); PROPVARIANT vaINT; PROPSPEC psSA_INT = { PRSPEC_PROPID, 13 }; CDbColId const colSA_INT = CDbColId( guidArray, 13 ); PROPVARIANT vaERROR; PROPSPEC psSA_ERROR = { PRSPEC_PROPID, 14 }; CDbColId const colSA_ERROR = CDbColId( guidArray, 14 );
//
// Desired output columns (as both CDbColId and DBCOMUNID)
//
static GUID guidSystem = PSGUID_STORAGE; static GUID guidQuery = PSGUID_QUERY; static GUID guidBmk = DBBMKGUID; static GUID guidSelf = DBCOL_SELFCOLUMNS;
static CDbColId psName( guidSystem, PID_STG_NAME ); static CDbColId psPath( guidSystem, PID_STG_PATH ); static CDbColId psAttr( guidSystem, PID_STG_ATTRIBUTES ); static CDbColId psSize( guidSystem, PID_STG_SIZE ); static CDbColId psWriteTime( guidSystem, PID_STG_WRITETIME ); static CDbColId psClassid( guidSystem, PID_STG_CLASSID ); static CDbColId psContents( guidSystem, PID_STG_CONTENTS );
static CDbColId psRank( guidQuery, DISPID_QUERY_RANK ); static CDbColId psWorkid( guidQuery, DISPID_QUERY_WORKID ); static CDbColId psBookmark( guidBmk, PROPID_DBBMK_BOOKMARK ); static CDbColId psSelf( guidSelf, PROPID_DBSELF_SELF ); static CDbColId psChapt( guidBmk, PROPID_DBBMK_CHAPTER );
static CDbSortKey sortSize( psSize, QUERY_SORTDESCEND ); static CDbSortKey sortClassid( psClassid, QUERY_SORTDESCEND ); static CDbSortKey sortWriteTime( psWriteTime, QUERY_SORTASCEND ); static CDbSortKey sortName( psName, QUERY_SORTDESCEND ); static CDbSortKey sortAttr( psName, QUERY_SORTASCEND );
CDbSortKey aSortCols[] = { sortSize, sortClassid, sortWriteTime, sortName, };
CDbSortKey aCatSortCols[] = { sortSize, sortWriteTime, };
CDbSortKey aMultiCatSortCols[] = { sortAttr, sortSize, };
static CDbSortKey sortKeywords( psKeywords, QUERY_SORTASCEND ); static CDbSortKey sortRelevantWords( psRelevantWords, QUERY_SORTASCEND ); static CDbSortKey sortTestProperty1( psTestProperty1, QUERY_SORTASCEND );
CDbSortKey aPropSortCols[] = { sortKeywords, sortRelevantWords, sortTestProperty1 };
const int cSortColumns = (sizeof aSortCols) / (sizeof aSortCols[0]); const int cCatSortColumns = (sizeof aCatSortCols) / (sizeof aCatSortCols[0]); const int cMultiCatSortColumns = (sizeof aMultiCatSortCols) / (sizeof aMultiCatSortCols[0]); const int cPropSortColumns = (sizeof aPropSortCols) / (sizeof aPropSortCols[0]);
const BYTE bmkFirst = (BYTE) DBBMK_FIRST; const BYTE bmkLast = (BYTE) DBBMK_LAST;
//
// Text in content index files
//
char const szCIFileData1[] = " The content index was created by Kyle Peltonen and Bartosz Milewski\n" "with help from Amy Arlin, Wade Richards, Mike Hewitt and a host of others.\n" " \"To be or not to be\" is most likely a noise phrase. \"To be or\n" "not to be, that is the question\" contains at least one non-noise\n" "word.\n" "Now is the time for all good men to come to the aid of their country.\n" "The content index is a superb piece of engineering. ;-)\n";
char const szCIFileData2[] = "\"Anybody can be good in the country. " "There are no temptations there.\"\n" "\n" "Oscar Wilde (1854-1900), Anglo-Irish playwright, author.\n" "Lord Henry, in The Picture of Dorian Gray, ch. 19 (1891).\n";
char const szOFSFileData[] = "PLEASE DELETE ME!\n";
WCHAR wcsTestPath[MAX_PATH]; WCHAR wcsTestCatalog[MAX_PATH];
struct SBasicTest { // field lengths
DBLENGTH cbClsid; DBLENGTH cbSize; DBLENGTH cbWriteTime; DBLENGTH cbAttr; DBLENGTH cbName; DBLENGTH cbPath;
// field status
ULONG sClsid; ULONG sSize; ULONG sWriteTime; ULONG sIPSStorage; ULONG sAttr; ULONG sName; ULONG sPath;
// field data
CLSID clsid; _int64 size; _int64 writeTime; unsigned attr; WCHAR awcName[MAX_PATH + 1]; WCHAR *pwcPath; IUnknown *pIPSStorage; };
struct SBasicAltTest { // field lengths
DBLENGTH cbSize; DBLENGTH cbWriteTime1; DBLENGTH cbWriteTime2; DBLENGTH cbWriteTime3;
// field status
ULONG sSize; ULONG sWriteTime1; ULONG sWriteTime2; ULONG sWriteTime3;
// field data
LONG Size; DBDATE writeTime1; DBTIME writeTime2; DBTIMESTAMP writeTime3; };
const ULONG cbRowName = sizeof WCHAR * (MAX_PATH + 1);
#define ALLPARTS ( DBPART_VALUE|DBPART_LENGTH|DBPART_STATUS )
DBBINDING aBasicTestCols[] = { // the iOrdinal field is filled in after the cursor is created
{ 0, offsetof(SBasicTest,clsid), offsetof(SBasicTest,cbClsid), offsetof(SBasicTest,sClsid), 0,0,0, ALLPARTS, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, sizeof CLSID, 0, DBTYPE_GUID, 0, 0 }, { 0, offsetof(SBasicTest,size), offsetof(SBasicTest,cbSize), offsetof(SBasicTest,sSize), 0,0,0, ALLPARTS, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, sizeof LONGLONG, 0, DBTYPE_UI8, 0, 0 }, { 0, offsetof(SBasicTest,writeTime), offsetof(SBasicTest,cbWriteTime), offsetof(SBasicTest,sWriteTime), 0,0,0, ALLPARTS, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, sizeof LONGLONG, 0, VT_FILETIME, 0, 0 }, { 0, offsetof(SBasicTest,attr), offsetof(SBasicTest,cbAttr), offsetof(SBasicTest,sAttr), 0,0,0, ALLPARTS, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, 3, // 3 for cb is ok: fixed len field so ignored
0, DBTYPE_I4, 0, 0 }, { 0, offsetof(SBasicTest,awcName), offsetof(SBasicTest,cbName), offsetof(SBasicTest,sName), 0,0,0, ALLPARTS, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbRowName, 0, DBTYPE_WSTR, 0, 0 }, { 0, offsetof(SBasicTest,pwcPath), offsetof(SBasicTest,cbPath), offsetof(SBasicTest,sPath), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, 0, 0, DBTYPE_WSTR|DBTYPE_BYREF, 0, 0 }, { 0, offsetof(SBasicTest,pIPSStorage), 0, offsetof(SBasicTest,sIPSStorage), 0, // pTypeInfo
&dbPersistObject, // pObject
0, // pBindExt
DBPART_VALUE|DBPART_STATUS, // dwPart
DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, // dwMemOwner
0, // cbMaxLen
0, // dwFlags
DBTYPE_IUNKNOWN, // wType
0, 0 }, // bPrecision, bScale
};
const ULONG cBasicTestCols = sizeof aBasicTestCols / sizeof aBasicTestCols[0];
DBBINDING aBasicAltCols[] = { // the iOrdinal field is filled in after the cursor is created
{ 0, offsetof(SBasicAltTest,Size), offsetof(SBasicAltTest,cbSize), offsetof(SBasicAltTest,sSize), 0,0,0, ALLPARTS, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, 3, // 3 for cb is ok: fixed len field so ignored
0, DBTYPE_I4, 0, 0 }, { 0, offsetof(SBasicAltTest,writeTime1), offsetof(SBasicAltTest,cbWriteTime1), offsetof(SBasicAltTest,sWriteTime1), 0,0,0, ALLPARTS, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, sizeof DBDATE, 0, DBTYPE_DBDATE, 0, 0 }, { 0, offsetof(SBasicAltTest,writeTime2), offsetof(SBasicAltTest,cbWriteTime2), offsetof(SBasicAltTest,sWriteTime2), 0,0,0, ALLPARTS, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, sizeof DBTIME, 0, DBTYPE_DBTIME, 0, 0 }, { 0, offsetof(SBasicAltTest,writeTime3), offsetof(SBasicAltTest,cbWriteTime3), offsetof(SBasicAltTest,sWriteTime3), 0,0,0, ALLPARTS, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, sizeof DBTIMESTAMP, 0, DBTYPE_DBTIMESTAMP, 0, 0 }, };
const ULONG cBasicAltCols = sizeof aBasicAltCols / sizeof aBasicAltCols[0];
int fTimeout = 1; // non-zero if query times out
int fVerbose = 0; // non-zero if verbose mode
int cFailures = 0; // count of failures in test (unit test only)
// Class to be used as an outer unknown. All QIs are simply
// passed on to inner unknown.
class COuterUnk: public IUnknown { public:
//
// IUnknown methods.
//
STDMETHOD(QueryInterface) ( THIS_ REFIID riid, LPVOID *ppiuk ) { // do blindly delegate for purpose of test
// don't AddRef as the inner unk will do it
return _pInnerUnk->QueryInterface(riid,ppiuk); } STDMETHOD_(ULONG, AddRef) (THIS) { InterlockedIncrement( (long *)&_ref ); return( _ref ); }
STDMETHOD_(ULONG, Release) (THIS) { if ( InterlockedDecrement( (long *)&_ref ) <= 0 ) { InterlockedIncrement( (long *)&_ref ); // artificial ref count for aggr
delete this; return 0; } return ( _ref ); } void Set(IUnknown *pInnerUnk) {_pInnerUnk = pInnerUnk; _pInnerUnk->AddRef();}
COuterUnk() : _ref(1), _pInnerUnk(NULL) {}; ~COuterUnk() { if (_pInnerUnk) { _pInnerUnk->Release(); _pInnerUnk = 0; } };
private: long _ref; // OLE reference count
IUnknown * _pInnerUnk; };
void DownlevelTest(BOOL fSequential); void SingleLevelCategTest(); void MultiLevelCategTest(); void CategTest( HCHAPTER hUpperChapt, IRowset *pRowsetCateg, IRowset *pRowset, unsigned cCols );
void RunPropTest( ); void RunSafeArrayTest( ); void RunDistribQueryTest( BOOL fDoContentTest ); void DeleteTest(BOOL fSequential); void ContentTest(void);
void ConflictingPropsTest( LPWSTR pwszScope, CDbCmdTreeNode * pTree, COuterUnk * pobjOuterUnk, ICommandTree **ppCmdTree );
void CheckColumns( IUnknown* pRowset, CDbColumns& rColumns, BOOL fQuiet = FALSE ); void CheckPropertiesInError( ICommand* pCmd, BOOL fQuiet = FALSE ); void CheckPropertiesOnCommand( ICommand* pCmd, BOOL fQuiet = FALSE ); void BasicTest( IRowset* pRowset, BOOL fSequential, HCHAPTER hChapt, unsigned cCols, BOOL fByRef, ICommandTree * pCmdTree = 0 ); void BackwardsFetchTest( IRowset* pRowset ); void FetchTest(IRowset* pRowset); void BindingTest(IUnknown* pRowset, BOOL fICommand = FALSE, BOOL fSequential = FALSE ); void MoveTest(IRowset* pRowset, HCHAPTER hChapt = DB_NULL_HCHAPTER);
int CheckHrowIdentity( IRowsetIdentity * pRowsetIdentity, DBROWCOUNT lOffset, DBCOUNTITEM cRows1, HROW * phRows1, DBCOUNTITEM cRows2, HROW * phRows2 );
void TestIAccessorOnCommand( ICommandTree * pCmdTree );
void CheckPropertyValue( PROPVARIANT const & varntPropRet, PROPVARIANT const & varntPropExp);
BOOL GetBooleanProperty ( IRowset * pRowset, DBPROPID dbprop ); BOOL SetBooleanProperty ( ICommand * pCmd, DBPROPID dbprop, VARIANT_BOOL f );
CDbCmdTreeNode * FormQueryTree( CDbCmdTreeNode * pRst, CDbColumns & Cols, CDbSortSet * pSort, LPWSTR * aColNames = 0 );
void GetCommandTreeErrors(ICommandTree* pCmdTree);
IRowsetScroll * InstantiateRowset( ICommand *pQueryIn, DWORD dwDepth, LPWSTR pwszScope, CDbCmdTreeNode * pTree, REFIID riid, COuterUnk *pobjOuterUnk = 0, ICommandTree ** ppCmdTree = 0, BOOL fExtendedTypes = TRUE );
void InstantiateMultipleRowsets( DWORD dwDepth, LPWSTR pwszScope, CDbCmdTreeNode * pTree, REFIID riid, unsigned cRowsets, IUnknown ** aRowsets, ICommandTree ** ppCmdTree = 0 );
void ReleaseStaticHrows( IRowset * pRowset, DBCOUNTITEM cRows, HROW * phRows ); void FreeHrowsArray( IRowset * pRowset, DBCOUNTITEM cRows, HROW ** pphRows );
HACCESSOR MapColumns( IUnknown * pUnknown, DBORDINAL cCols, DBBINDING * pBindings, const DBID * pColIds, BOOL fByRef = FALSE ); void ReleaseAccessor( IUnknown * pUnknown, HACCESSOR hAcc );
int WaitForCompletion( IRowset *pRowset, BOOL fQuiet = FALSE ); void Setup(void); void Cleanup(void); ULONG Delnode( WCHAR const * wcsDir ); void BuildFile( WCHAR const * wcsFile, char const * data, ULONG cb );
void CantRun(void); void Fail(void); void Usage(void);
void LogProgress( char const * pszFormat, ... ); void LogError( char const * pszFormat, ... ); void LogFail( char const * pszFormat, ... ); WCHAR * FormatGuid( GUID const & guid );
void DBSortTest(void);
SCODE SetScopeProperties( ICommand * pCmd, unsigned cDirs, WCHAR const * const * apDirs, ULONG const * aulFlags, WCHAR const * const * apCats = 0, WCHAR const * const * apMachines = 0 );
BOOL DoContentQuery( ICommand * pQuery, CDbRestriction & CiRst, unsigned cExpectedHits );
char *ProgName = PROG_NAME;
void Usage(void) { #ifdef UNIT_TEST
printf("Usage: %s [ -d[:InfoLevel] ] [-v] [-V] [-t] [-c]\n", ProgName); #else // !UNIT_TEST
printf("Usage: %s [-v] [-V] [-t] [-c]\n", ProgName); #endif // UNIT_TEST
printf("\t-v\tverbose\n" "\t-V\tvery verbose - dumps tables, column and rowset info\n" "\t-t\tdon't timeout queries\n" "\t-c\tdon't do content query test\n"); // "\t-dl\tdon't do tests on downlevel file system\n"
// "\t-ofs\tdon't do tests on OFS file system\n");
// "\t-n{d,o}\tdon't do tests on downlevel (-nd) or OFS (-no)\n");
#ifdef UNIT_TEST
printf("\t-d[:InfoLevel]\tset debug infolevel to InfoLevel\n"); #endif // UNIT_TEST
exit(2); }
//+-------------------------------------------------------------------------
//
// Function: IsContentFilteringEnabled, public
//
// Synopsis: Read the registry for the key FilterContent at the
// location
//
//--------------------------------------------------------------------------
BOOL IsContentFilteringEnabled() { WCHAR wcsFilterContents[] = L"FilterContents"; WCHAR wcsRegAdmin[] = L"ContentIndex"; BOOL fFilteringEnabled = FALSE;
RTL_QUERY_REGISTRY_TABLE regtab[2];
regtab[0].DefaultType = REG_NONE; regtab[0].DefaultData = 0; regtab[0].DefaultLength = 0; regtab[0].QueryRoutine = 0; regtab[0].Name = wcsFilterContents; regtab[0].EntryContext = &fFilteringEnabled; regtab[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
regtab[1].QueryRoutine = 0; regtab[1].Flags = 0;
NTSTATUS Status = RtlQueryRegistryValues( RTL_REGISTRY_CONTROL, wcsRegAdmin, ®tab[0], 0, 0 );
if ( NT_ERROR(Status) || !fFilteringEnabled ) return FALSE;
ISimpleCommandCreator * pCmdCreator = 0; CLSID clsidSCC = CLSID_CISimpleCommandCreator; SCODE sc = CoCreateInstance( clsidSCC, NULL, CLSCTX_INPROC_SERVER, IID_ISimpleCommandCreator, (void **)&pCmdCreator );
if ( S_OK != sc ) { LogError( "CoCreateInstance for cmd creator returned %08x\n", sc ); return FALSE; }
WCHAR awchCatalog[80]; ULONG cchCat = 0; sc = pCmdCreator->GetDefaultCatalog( awchCatalog, sizeof awchCatalog/sizeof(awchCatalog[0]), &cchCat );
if ( S_OK != sc ) { LogError( "GetDefaultCatalog returned %08x\n", sc ); pCmdCreator->Release(); return FALSE; }
sc = pCmdCreator->VerifyCatalog( TEST_MACHINE, CONTENT_CATALOG ); pCmdCreator->Release();
return sc == S_OK; }
//+-------------------------------------------------------------------------
//
// Function: main, public
//
// Synopsis: Test the file system implementation of the IRowset
// family of interfaces.
//
// Notes:
//
// History: 25 Mar 1994 Alanw Created
//
//--------------------------------------------------------------------------
int __cdecl main(int argc, char **argv) { #ifdef UNIT_TEST
DBSortTest(); #endif
unsigned i; BOOL fDoContentTest = TRUE;
//
// Parse arguments.
//
ProgName = argv[0];
for ( i = 1; i < (unsigned)argc ; i++ ) { char *pszArg = argv[i]; if ( *pszArg == '-' ) { switch ( *++pszArg ) { case 'd': // if (pszArg[1] == 'l') // -dl - no downlevel tests
// {
// fNoDownlevel = TRUE;
// break;
// }
#if defined (UNIT_TEST) && (DBG == 1)
if (*++pszArg == ':') // -d:xx - debug output mode
pszArg++;
{ unsigned fInfoLevel = atoi(pszArg); tbInfoLevel = fInfoLevel ? fInfoLevel : 0xFFFFF; } break; #else // !UNIT_TEST
Usage(); exit(2); #endif // UNIT_TEST
case 't': // don't timeout
fTimeout = 0; break;
case 'c': fDoContentTest = FALSE; break;
case 'V': // very verbose, dumps table
fVerbose++; case 'v': // verbose
fVerbose++; break;
default: Usage(); exit (2); } } else {
// Exit the argument loop
argc -= i; argv += i; break; } }
printf( "%s: OLE-DB cursor unit test.\n" #if defined (UNIT_TEST)
" No expected failures\n" #if !(defined(DO_CATEG_TESTS) && \
defined(DO_NOTIFICATION) && \ defined(DO_CONTENT_TESTS) && \ defined(MULTI_LEVEL_CATEG_TEST) ) " Not all tests are turned on\n" #endif // conditional tests
#endif // defined(UNIT_TEST)
, ProgName );
for (i = 0; i < clProp8; i++) alProp8[i] = i;
CoInitialize( 0 );
Setup();
// Patch in this iid, which can't be done in the initializer
dbPersistObject.dwFlags = STGM_PRIORITY | STGM_READ; dbPersistObject.iid = IID_IPropertySetStorage;
//
// Base functionality test
//
RunPropTest( ); RunSafeArrayTest();
RunDistribQueryTest( fDoContentTest );
DownlevelTest(TRUE); DownlevelTest(FALSE);
#ifdef DO_CATEG_TESTS
SingleLevelCategTest();
#ifdef DO_MULTI_LEVEL_CATEG_TEST
MultiLevelCategTest(); #endif
#endif // DO_CATEG_TESTS
#ifdef DO_CONTENT_TESTS
if ( fDoContentTest && IsContentFilteringEnabled() ) { ContentTest(); } else #endif
LogProgress("WARNING: Content Query test disabled\n");
DeleteTest(TRUE); DeleteTest(FALSE);
CIShutdown();
//#if defined (UNIT_TEST)
if (cFailures) { printf("%d failures occurred\n", cFailures); Fail(); } //#endif // defined(UNIT_TEST)
Cleanup(); CoUninitialize();
printf( "%s: PASSED\n", ProgName ); if (! _isatty(_fileno(stdout)) ) fprintf( stderr, "%s: PASSED\n", ProgName ); return( 0 ); } //main
//+-------------------------------------------------------------------------
//
// Function: DownlevelTest, public
//
// Synopsis: Basic query feature test.
//
// History: 30 Jun 94 AlanW Created
//
// Notes: Just looks for files in the system directory.
//
//--------------------------------------------------------------------------
void DownlevelTest(BOOL fSequential) { LogProgress( "Non-content %s query\n", fSequential? "sequential" : "scrollable");
SCODE sc;
//
// Find system directory
WCHAR wcsSysDir[MAX_PATH];
#if 0
wcscpy(wcsSysDir, L"F:\\winnt\\system32"); #else
if( !GetSystemDirectory( wcsSysDir, sizeof(wcsSysDir) / sizeof(WCHAR) ) ) { LogFail( "Unable to determine system directory.\n" ); } #endif
//
// Get name, size and class id for *.exe, *.dll, *.doc and *.sys
//
int cCol = 7; if ( !fSequential ) cCol++;
CDbColumns cols(cCol);
cols.Add( psClassid, 0 ); cols.Add( psSize, 1 ); cols.Add( psWriteTime, 2 ); cols.Add( psAttr, 3 ); cols.Add( psName, 4 ); cols.Add( psPath, 5 ); cols.Add( psSelf, 6 ); if ( !fSequential ) { cols.Add( psWorkid, 7); }
CDbPropertyRestriction rst;
rst.SetRelation( DBOP_like ); rst.SetProperty( psName ); rst.SetValue( L"*.|(exe|,dll|,doc|,sys|,zzz|)" );
CDbSortSet ss(cSortColumns); for (unsigned i = 0; i<cSortColumns; i++) ss.Add(aSortCols[i], i);
CDbCmdTreeNode * pDbCmdTree = FormQueryTree(&rst, cols, &ss);
if (! fSequential) { ConflictingPropsTest(wcsSysDir, pDbCmdTree, 0, 0); }
ICommandTree * pCmdTree=0; COuterUnk *pOuterUnk = new COuterUnk();
IRowset * pRowset = InstantiateRowset( 0, QUERY_SHALLOW, // Depth
wcsSysDir, // Scope
pDbCmdTree, // DBCOMMANDTREE
fSequential ? IID_IRowset : IID_IRowsetScroll, // IID of i/f to return
pOuterUnk, &pCmdTree );
//
// Verify columns
//
CheckColumns( pRowset, cols );
if ( !WaitForCompletion( pRowset, TRUE ) ) { pCmdTree->Release(); pRowset->Release(); LogFail( "Downlevel query unsuccessful.\n" ); }
//
// Do basic function tests.
//
BasicTest(pRowset, fSequential, 0, cBasicTestCols, TRUE); BasicTest(pRowset, fSequential, 0, cBasicTestCols, TRUE, pCmdTree);
//
// Do backward fetch tests
//
if ( !fSequential ) { BackwardsFetchTest( pRowset ); }
FetchTest(pRowset);
//
// Test SetBindings, GetBindings, Move and Scroll
//
BindingTest(pRowset, FALSE, fSequential ); BindingTest(pCmdTree, TRUE, fSequential );
if ( ! fSequential ) { MoveTest(pRowset); }
pCmdTree->Release(); pRowset->Release();
pOuterUnk->Release(); // truly release it
} //DownlevelTest
//+---------------------------------------------------------------------------
//
// Function: ConflictingPropsTest
//
// Synopsis: Tests handling of conflicting settings of rowset properties.
//
// Arguments: [pswzScope] - Query scope
// [pTree] - pointer to DBCOMMANDTREE for the query
// [pUnkOuter] - pointer to outer unknown object
// [ppCmdTree] - if non-zero, ICommandTree will be returned here.
//
// Returns: NOTHING
//
// History: 26 May 1998 AlanW Created
//
// Notes:
//
//----------------------------------------------------------------------------
void ConflictingPropsTest( LPWSTR pwszScope, CDbCmdTreeNode * pTree, COuterUnk * pobjOuterUnk, ICommandTree **ppCmdTree ) { DWORD dwDepth = QUERY_SHALLOW;
// run the query
ICommand * pQuery = 0;
IUnknown * pIUnknown; SCODE sc = CICreateCommand( &pIUnknown, (IUnknown *)pobjOuterUnk, IID_IUnknown, TEST_CATALOG, TEST_MACHINE );
if ( FAILED( sc ) ) LogFail( "ConflictingPropsTest - error 0x%x Unable to create command\n", sc );
if (pobjOuterUnk) { pobjOuterUnk->Set(pIUnknown); }
if (pobjOuterUnk) sc = pobjOuterUnk->QueryInterface(IID_ICommand, (void **) &pQuery ); else sc = pIUnknown->QueryInterface(IID_ICommand, (void **) &pQuery );
pIUnknown->Release();
if ( FAILED( sc ) ) LogFail( "ConflictingPropsTest - error 0x%x Unable to QI ICommand\n", sc );
sc = SetScopeProperties( pQuery, 1, &pwszScope, &dwDepth );
if ( FAILED( sc ) ) LogFail( "ConflictingPropsTest - error 0x%x Unable to set scope '%ws'\n", sc, pwszScope );
CheckPropertiesOnCommand( pQuery );
ICommandTree *pCmdTree = 0;
if (pobjOuterUnk) sc = pobjOuterUnk->QueryInterface(IID_ICommandTree, (void **)&pCmdTree); else sc = pQuery->QueryInterface(IID_ICommandTree, (void **)&pCmdTree);
if (FAILED (sc) ) { if ( 0 != pQuery ) pQuery->Release();
LogFail("QI for ICommandTree failed\n"); }
DBCOMMANDTREE * pRoot = pTree->CastToStruct();
sc = pCmdTree->SetCommandTree( &pRoot, 0, TRUE); if (FAILED (sc) ) { if ( 0 != pQuery ) pQuery->Release();
pCmdTree->Release(); LogFail("SetCommandTree failed, %08x\n", sc); }
ICommandProperties *pCmdProp = 0; if (pobjOuterUnk) sc = pobjOuterUnk->QueryInterface(IID_ICommandProperties, (void **)&pCmdProp); else sc = pQuery->QueryInterface(IID_ICommandProperties, (void **)&pCmdProp);
if (FAILED (sc) ) { if ( 0 != pQuery ) pQuery->Release();
LogFail("QI for ICommandProperties failed\n"); }
//
// Set conflicting properties
//
const unsigned MAX_PROPS = 6; DBPROPSET aPropSet[MAX_PROPS]; DBPROP aProp[MAX_PROPS]; ULONG cProp = 0;
aProp[cProp].dwPropertyID = DBPROP_IRowsetScroll; aProp[cProp].dwOptions = DBPROPOPTIONS_REQUIRED; aProp[cProp].dwStatus = 0; // Ignored
aProp[cProp].colid = dbcolNull; aProp[cProp].vValue.vt = VT_BOOL; aProp[cProp].vValue.boolVal = VARIANT_TRUE;
aPropSet[cProp].rgProperties = &aProp[cProp]; aPropSet[cProp].cProperties = 1; aPropSet[cProp].guidPropertySet = DBPROPSET_ROWSET;
cProp++;
aProp[cProp].dwPropertyID = DBPROP_BOOKMARKS; aProp[cProp].dwOptions = DBPROPOPTIONS_REQUIRED; aProp[cProp].dwStatus = 0; // Ignored
aProp[cProp].colid = dbcolNull; aProp[cProp].vValue.vt = VT_BOOL; aProp[cProp].vValue.boolVal = VARIANT_FALSE;
aPropSet[cProp].rgProperties = &aProp[cProp]; aPropSet[cProp].cProperties = 1; aPropSet[cProp].guidPropertySet = DBPROPSET_ROWSET;
cProp++;
sc = pCmdProp->SetProperties( cProp, aPropSet ); //pCmdProp->Release();
if ( FAILED(sc) || DB_S_ERRORSOCCURRED == sc ) { if ( 0 != pQuery ) pQuery->Release();
LogError("ICommandProperties::SetProperties failed\n"); cFailures++; }
IRowset * pRowset = 0;
sc = pQuery->Execute( 0, // no aggr. IUnknown
IID_IRowset, // IID for i/f to return
0, // disp. params
0, // count of rows affected
(IUnknown **)&pRowset); // Returned interface
if (SUCCEEDED (sc)) { if ( 0 == pRowset ) LogError("ICommand::Execute returned success(%x), but pRowset is null\n", sc); else LogError("ICommand::Execute returned success(%x) with conflicting props\n", sc);
if (DB_S_ERRORSOCCURRED == sc) { CheckPropertiesInError(pQuery); } pRowset->Release(); pCmdProp->Release(); pCmdTree->Release(); pQuery->Release(); Fail(); } else // FAILED (sc)
{
if (DB_E_ERRORSOCCURRED != sc) { LogError("ICommand::Execute with conflicing props failed, %x\n", sc); if (DB_E_ERRORSINCOMMAND == sc) GetCommandTreeErrors(pCmdTree);
pCmdProp->Release(); pCmdTree->Release(); pQuery->Release(); Fail(); } CheckPropertiesInError(pQuery, TRUE); }
// TODO: check other combinations of conflicting properties
// check that execute succeeds on same ICommand after reset
// Set properties back to their default state
cProp = 0;
aProp[cProp].dwPropertyID = DBPROP_IRowsetLocate; aProp[cProp].dwOptions = DBPROPOPTIONS_OPTIONAL; aProp[cProp].dwStatus = 0; // Ignored
aProp[cProp].colid = dbcolNull; aProp[cProp].vValue.vt = VT_BOOL; aProp[cProp].vValue.boolVal = VARIANT_FALSE;
aPropSet[cProp].rgProperties = &aProp[cProp]; aPropSet[cProp].cProperties = 1; aPropSet[cProp].guidPropertySet = DBPROPSET_ROWSET;
cProp++;
aProp[cProp].dwPropertyID = DBPROP_BOOKMARKS; aProp[cProp].dwOptions = DBPROPOPTIONS_OPTIONAL; aProp[cProp].dwStatus = 0; // Ignored
aProp[cProp].colid = dbcolNull; aProp[cProp].vValue.vt = VT_BOOL; aProp[cProp].vValue.boolVal = VARIANT_FALSE;
aPropSet[cProp].rgProperties = &aProp[cProp]; aPropSet[cProp].cProperties = 1; aPropSet[cProp].guidPropertySet = DBPROPSET_ROWSET;
cProp++;
aProp[cProp].dwPropertyID = DBPROP_IRowsetScroll; aProp[cProp].dwOptions = DBPROPOPTIONS_OPTIONAL; aProp[cProp].dwStatus = 0; // Ignored
aProp[cProp].colid = dbcolNull; aProp[cProp].vValue.vt = VT_BOOL; aProp[cProp].vValue.boolVal = VARIANT_FALSE;
aPropSet[cProp].rgProperties = &aProp[cProp]; aPropSet[cProp].cProperties = 1; aPropSet[cProp].guidPropertySet = DBPROPSET_ROWSET;
cProp++;
sc = pCmdProp->SetProperties( cProp, aPropSet ); pCmdProp->Release();
if (FAILED (sc) ) { LogError("ICommandProperties::SetProperties failed, %08x\n", sc); if (DB_E_ERRORSINCOMMAND == sc) { GetCommandTreeErrors(pCmdTree); } if (DB_E_ERRORSOCCURRED == sc) { CheckPropertiesInError(pQuery); } pQuery->Release(); pCmdTree->Release(); Fail(); }
pQuery->Release(); if ( 0 == ppCmdTree ) { pCmdTree->Release(); } else { *ppCmdTree = pCmdTree; }
return; }
#ifdef DO_CATEG_TESTS
//+-------------------------------------------------------------------------
//
// Function: SingleLevelCategTest, public
//
// Synopsis: Basic query categorization feature test.
//
// History: 30 Mar 95 dlee Created
//
// Notes: Just looks for files in the system directory.
//
//--------------------------------------------------------------------------
void SingleLevelCategTest() { LogProgress( "Non-content categorization query\n" );
SCODE sc;
//
// Find system directory
//
WCHAR wcsSysDir[MAX_PATH];
#if 0
wcscpy(wcsSysDir,L"g:\\winnt\\system32"); #else
if( !GetSystemDirectory( wcsSysDir, sizeof(wcsSysDir) / sizeof(WCHAR) ) ) LogFail( "Unable to determine system directory.\n" ); #endif
//
// Get name, size and class id for *.exe, *.dll, *.doc, and *.sys
//
CDbColumns cols(8);
cols.Add( psClassid, 0 ); cols.Add( psSize, 1 ); cols.Add( psWriteTime, 2 ); cols.Add( psAttr, 3 ); cols.Add( psName, 4 ); cols.Add( psPath, 5 ); cols.Add( psSelf, 6 ); cols.Add( psBookmark, 7);
CDbNestingNode nest;
nest.AddGroupingColumn( psSize );
nest.AddParentColumn( psBookmark ); nest.AddParentColumn( psSize );
nest.AddChildColumn( psClassid ); nest.AddChildColumn( psSize ); nest.AddChildColumn( psWriteTime ); nest.AddChildColumn( psAttr ); nest.AddChildColumn( psName ); nest.AddChildColumn( psPath ); nest.AddChildColumn( psSelf ); nest.AddChildColumn( psBookmark);
CDbPropertyRestriction rst;
rst.SetRelation( DBOP_like ); rst.SetProperty( psName ); rst.SetValue( L"*.|(exe|,dll|,doc|,sys|,zzz|)" );
CDbSelectNode * pSelect = new CDbSelectNode(); pSelect->AddRestriction( rst.Clone() );
nest.AddTable( pSelect ); pSelect = 0;
IRowset * pRowsets[2]; ICommandTree * pCmdTree = 0;
InstantiateMultipleRowsets( QUERY_SHALLOW, // Depth
wcsSysDir, // Scope
nest.Clone(), // DBCOMMANDTREE
IID_IRowsetScroll, // IID for i/f to return
2, (IUnknown **)pRowsets, &pCmdTree );
IRowset *pRowsetCateg = pRowsets[0]; IRowset *pRowset = pRowsets[1];
//
// Verify columns
//
CDbColumns chapCols(3);
chapCols.Add( psBookmark, 0 ); chapCols.Add( psSize, 1 ); chapCols.Add( psChapt, 2 ); // chapt must be last since it is added to
// the end automatically above.
CheckColumns( pRowsetCateg, chapCols ); CheckColumns( pRowset, cols );
if ( !WaitForCompletion( pRowset, FALSE ) ) { pCmdTree->Release(); pRowset->Release(); pRowsetCateg->Release(); LogFail( "Downlevel query unsuccessful.\n" ); }
//
// Do basic function tests.
//
FetchTest(pRowset);
//
// Test SetBindings, GetBindings, Move and Scroll
//
BindingTest(pRowset); BindingTest(pCmdTree, TRUE);
CategTest(0, pRowsetCateg, pRowset, cBasicTestCols);
pCmdTree->Release(); pRowset->Release(); pRowsetCateg->Release(); } //SingleLevelCategTest
#define MAX_CHAPT_LENGTH 32
static DBBINDING aCategCols[] = { { 0, sizeof DBLENGTH, 0, 0, 0,0,0, DBPART_VALUE|DBPART_LENGTH, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, MAX_CHAPT_LENGTH, 0, DBTYPE_BYTES, 0,0 }, };
const ULONG cCategCols = sizeof aCategCols / sizeof aCategCols[0];
static DBBINDING aSizeCol[] = { { 0, 0, 0, 0, 0,0,0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, sizeof LONGLONG, 0, DBTYPE_UI8, 0, 0 }, };
static DBBINDING aAttrCol[] = { { 0, 0, 0, 0, 0,0,0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, sizeof LONG, 0, DBTYPE_I4, 0, 0 }, };
struct ChaptBinding { DBLENGTH len; ULONG chapt; // because I know the first 4 bytes are the chapt
char abChapt[MAX_CHAPT_LENGTH - sizeof ULONG]; };
void CategTest( HCHAPTER hUpperChapt, IRowset * pRowsetCateg, IRowset * pRowset, unsigned cCols ) { LogProgress( " Categorization test\n" );
BOOL fBackwardFetch = GetBooleanProperty( pRowset, DBPROP_CANFETCHBACKWARDS ); BOOL fCanHoldRows = GetBooleanProperty( pRowset, DBPROP_CANHOLDROWS );
if ( !fBackwardFetch || !fCanHoldRows ) LogProgress("WARNING: Categorized backward fetch test disabled\n");
IUnknown * pAccessor = pRowsetCateg;
HACCESSOR hAccCateg = MapColumns( pAccessor, cCategCols, aCategCols, &psChapt);
HACCESSOR hAccSize = MapColumns( pRowsetCateg, 1, aSizeCol, &psSize);
IRowsetLocate * pRLC = 0; SCODE sc = pRowsetCateg->QueryInterface( IID_IRowsetLocate, (void **)&pRLC);
if (FAILED(sc) || pRLC == 0) LogFail("QueryInterface to IRowsetLocate failed\n");
IRowsetIdentity * pRowsetIdentity = 0; sc = pRowsetCateg->QueryInterface( IID_IRowsetIdentity, (void **)&pRowsetIdentity);
if (FAILED(sc) && (sc != E_NOINTERFACE || pRowsetIdentity != 0)) { LogError("QueryInterface to IRowsetIdentity failed (%x)\n", sc); pRowsetIdentity = 0; cFailures++; }
IChapteredRowset * pChapteredRowset = 0; sc = pRowset->QueryInterface( IID_IChapteredRowset, (void **)&pChapteredRowset);
if (FAILED(sc)) { LogError("QueryInterface to IChapteredRowset failed (%x)\n", sc); pChapteredRowset = 0; cFailures++; }
IRowsetScroll * pRS = 0; sc = pRowset->QueryInterface( IID_IRowsetScroll, (void **)&pRS);
if (FAILED(sc) || pRS == 0) LogFail("QueryInterface to IRowsetScroll failed\n");
SCODE scHier = S_OK; HROW ahRows[10]; HROW* phRows = ahRows; DBCOUNTITEM cCategories = 0; DBCOUNTITEM cRowsTotal = 0; DBCOUNTITEM cRowsReturned = 0;
LONGLONG llSizePrev = -1;
while (scHier != DB_S_ENDOFROWSET) { scHier = pRLC->GetNextRows( hUpperChapt, 0, 10, &cRowsReturned, &phRows); if (FAILED(scHier)) LogFail("pRLC->GetNextRows failed: 0x%lx\n", scHier);
if ( 0 == cRowsReturned ) { if ( DB_S_ENDOFROWSET != scHier ) LogFail("pRLC->GetNextRows bad return at end of rowset: 0x%lx\n", scHier); continue; }
cCategories += cRowsReturned; HCHAPTER hLastChapter = DB_NULL_HCHAPTER;
for (ULONG row = 0; row < cRowsReturned; row++) { ChaptBinding data;
SCODE sc = pRLC->GetData(phRows[row], hAccCateg, &data); if ( FAILED( sc ) ) LogFail("Can't get category data in CategTest()\n");
LONGLONG llSize; sc = pRLC->GetData(phRows[row], hAccSize, &llSize); if ( FAILED( sc ) ) LogFail("Can't get size data in CategTest()\n");
if (fVerbose > 1) printf( " category, file size: %lx, %d\n", data.chapt, (int) llSize );
if ( llSize == llSizePrev ) LogFail("Duplicate size categories\n");
if ( llSizePrev > llSize ) LogFail("categories unsorted by size\n");
llSizePrev = llSize;
DBCOUNTITEM cRows; sc = pRS->GetApproximatePosition( data.chapt, 0, 0, 0, &cRows ); if ( FAILED( sc ) ) LogFail("GetApproximatePosition with chapter failed %x\n", sc); cRowsTotal += cRows;
// then test fetching rows in the category
BasicTest(pRowset, FALSE, data.chapt, cCols, FALSE); MoveTest(pRowset, data.chapt); if (cCategories == cRowsReturned && 0 == row && DB_NULL_HCHAPTER == hUpperChapt) { // Do testing on entire base rowset
BasicTest(pRowset, FALSE, DB_NULL_HCHAPTER, cCols, FALSE); MoveTest(pRowset, DB_NULL_HCHAPTER); }
if (pChapteredRowset && row != (cRowsReturned - 1)) { ULONG ulRefCnt = 10; sc = pChapteredRowset->ReleaseChapter( data.chapt, &ulRefCnt ); if ( FAILED( sc ) ) { LogError("ReleaseChapter failed, sc = %x\n", sc); cFailures++; } else if ( ulRefCnt != 0 ) { LogError("ReleaseChapter returned bad refcount: got %d, exp 0\n", ulRefCnt); cFailures++; } } else hLastChapter = data.chapt; }
if (pChapteredRowset) { ULONG ulRefCnt = 10; sc = pChapteredRowset->AddRefChapter( hLastChapter, &ulRefCnt ); if ( FAILED( sc ) ) { LogError("AddRefChapter failed, sc = %x\n", sc); cFailures++; } else if ( ulRefCnt != 2 ) { LogError("AddRefChapter returned bad refcount: %d\n", ulRefCnt); cFailures++; } } if ( fBackwardFetch && fCanHoldRows ) { HROW ahRows2[10]; HROW* phRows2 = ahRows2; DBCOUNTITEM cRowsRet2 = 0; DBROWOFFSET oRows = - (DBROWOFFSET)cRowsReturned;
// fetch the categories BACKWARD to test GetNextRows behavior
// over chapters.
sc = pRLC->GetNextRows( hUpperChapt, 0, oRows, &cRowsRet2, &phRows2); if (FAILED(sc)) LogFail("pRLC->GetNextRows backward fetch failed: 0x%lx\n", sc); if ( cRowsRet2 != cRowsReturned ) { LogFail("pRLC->GetNextRows different row count on fwd/bkwd fetch: %d %d\n", cRowsReturned, cRowsRet2); }
// The first row retrieved in ahRows2 is the last retrieved in
// ahRows. Fetch the chapter again and check its refcount to see
// if it was collapsed properly.
if (pChapteredRowset) { ChaptBinding data; sc = pRLC->GetData(phRows2[0], hAccCateg, &data); if ( FAILED( sc ) ) LogFail("Can't re-fetch category data in CategTest()\n");
ULONG ulRefCnt = 10; sc = pChapteredRowset->ReleaseChapter( data.chapt, &ulRefCnt ); if ( FAILED( sc ) ) { LogError("ReleaseChapter failed on chapt refetch, sc = %x\n", sc); cFailures++; } else if ( ulRefCnt != 2 ) { LogError("ReleaseChapter returned bad refcount: got %d, exp 2\n", ulRefCnt); cFailures++; } else { pChapteredRowset->ReleaseChapter( data.chapt, &ulRefCnt ); pChapteredRowset->ReleaseChapter( data.chapt, &ulRefCnt ); } }
// Reverse the order of the rows for HROW identity check
unsigned i, j; for (i=0, j=(unsigned)(cRowsRet2-1); i < j; i++, j--) { HROW hrTmp = ahRows2[i]; ahRows2[i] = ahRows2[j]; ahRows2[j] = hrTmp; } int cFailed = CheckHrowIdentity( pRowsetIdentity, 0, cRowsReturned, ahRows, cRowsRet2, ahRows2 ); if ( cFailed > 0 ) { LogFail( "Backwards category fetch CheckHrowIdentity returned %d\n", cFailed ); }
// Release first row in handle array, use that position to refetch
// last row in array.
sc = pRLC->ReleaseRows( 1, phRows2, 0, 0, 0 ); DBCOUNTITEM cRowsRet3 = 0; sc = pRLC->GetNextRows( hUpperChapt, cRowsRet2-1, 1, &cRowsRet3, &phRows2); if (FAILED(sc)) LogFail("pRLC->GetNextRows re-fetch failed: 0x%lx\n", sc); if ( cRowsRet3 != 1 ) { LogFail("pRLC->GetNextRows unexpected row count on re-fetch: %d\n", cRowsRet3); } cFailed = CheckHrowIdentity( pRowsetIdentity, cRowsRet2-1, 1, ahRows2, 1, ahRows2 ); if ( cFailed > 0 ) { LogFail( "Category re-fetch CheckHrowIdentity returned %d\n", cFailed ); } sc = pRLC->ReleaseRows( cRowsRet2, phRows2, 0, 0, 0 ); }
sc = pRLC->ReleaseRows( cRowsReturned, phRows, 0, 0, 0 ); }
if (cCategories == 0) LogFail("No categories found\n");
DBCOUNTITEM cRows; sc = pRS->GetApproximatePosition( DB_NULL_HCHAPTER, 0, 0, 0, &cRows ); if ( FAILED( sc ) ) LogFail("GetApproximatePosition with NULL chapter failed %x\n", sc);
if (DB_NULL_HCHAPTER == hUpperChapt && cRowsTotal != cRows) LogFail("Sum of rows in chapters(%d) is not same as total rows(%d)\n", cRowsTotal, cRows); if (DB_NULL_HCHAPTER != hUpperChapt && cRowsTotal > cRows) LogFail("Sum of rows in chapters(%d) is greater than total rows(%d)\n", cRowsTotal, cRows);
ReleaseAccessor( pAccessor, hAccCateg ); ReleaseAccessor( pRowsetCateg, hAccSize );
pRLC->Release(); pRS->Release(); if (pRowsetIdentity) pRowsetIdentity->Release(); if (pChapteredRowset) pChapteredRowset->Release();
} //CategTest
#endif // DO_CATEG_TESTS
#ifdef DO_MULTI_LEVEL_CATEG_TEST
void UpperLevelCategTest( IRowset *pRowsetUpperCateg, IRowset *pRowsetLowerCateg, IRowset *pRowset, unsigned cCols) { LogProgress( " Upper Level Categorization test\n" );
HACCESSOR hAccCateg = MapColumns( pRowsetUpperCateg, cCategCols, aCategCols, &psChapt);
HACCESSOR hAccAttr = MapColumns( pRowsetUpperCateg, 1, aAttrCol, &psAttr);
IRowsetLocate * pRLUC = 0; SCODE sc = pRowsetUpperCateg->QueryInterface( IID_IRowsetLocate, (void **)&pRLUC);
if (FAILED(sc) || pRLUC == 0) LogFail("QueryInterface to IRowsetLocate failed\n");
IRowsetScroll * pRSLC = 0; sc = pRowsetLowerCateg->QueryInterface( IID_IRowsetScroll, (void **)&pRSLC);
if (FAILED(sc) || pRSLC == 0) LogFail("QueryInterface to IRowsetScroll failed\n"); SCODE scHier = S_OK; HROW ahRows[10]; HROW* phRows = ahRows; ULONG cCategories = 0; DBCOUNTITEM cRowsTotal = 0; DBCOUNTITEM cRowsReturned = 0;
LONG lAttrPrev = 0xffffffff;
while (scHier != DB_S_ENDOFROWSET) { scHier = pRLUC->GetNextRows(0, 0, 10, &cRowsReturned, &phRows); if (FAILED(scHier)) LogFail("pRLUC->GetNextRows failed: 0x%lx\n", scHier);
cCategories += (ULONG) cRowsReturned;
for (ULONG row = 0; row < cRowsReturned; row++) { ChaptBinding data;
SCODE sc = pRLUC->GetData(phRows[row],hAccCateg,&data); if ( FAILED( sc ) ) LogFail("GetData in UpperLevelCategTest failed: 0x%lx\n",sc);
LONG lAttr; sc = pRLUC->GetData(phRows[row],hAccAttr,&lAttr); if ( FAILED( sc ) ) LogFail("GetData in UpperLevelCategTest failed: 0x%lx\n",sc);
if (fVerbose > 1) printf( "upper level category, attr:: %lx, %lx\n", data.chapt, lAttr );
if ( lAttrPrev == lAttr ) LogFail("duplicate attrib categories\n");
if ( lAttrPrev > lAttr ) LogFail("categories unsorted by attrib\n");
lAttrPrev = lAttr;
DBCOUNTITEM cRows; sc = pRSLC->GetApproximatePosition( data.chapt, 0, 0, 0, &cRows ); if ( FAILED( sc ) ) LogFail("GetApproximatePosition with chapter failed %x\n", sc); cRowsTotal += cRows;
// then test fetching rows in the category
MoveTest( pRowsetLowerCateg, data.chapt );
CategTest( data.chapt, pRowsetLowerCateg, pRowset, cCols ); }
sc = pRLUC->ReleaseRows( cRowsReturned, phRows, 0, 0, 0 ); }
if (cCategories == 0) LogFail("No categories found\n");
DBCOUNTITEM cRows; sc = pRSLC->GetApproximatePosition( DB_NULL_HCHAPTER, 0, 0, 0, &cRows ); if ( FAILED( sc ) ) LogFail("GetApproximatePosition with NULL chapter failed %x\n", sc); if (cRowsTotal != cRows) LogFail("Sum of rows in chapters(%d) is not same as total rows(%d)\n", cRowsTotal, cRows);
ReleaseAccessor( pRLUC, hAccCateg ); ReleaseAccessor( pRLUC, hAccAttr );
pRSLC->Release(); pRLUC->Release(); } //UpperLevelCategTest
//+-------------------------------------------------------------------------
//
// Function: MultiLevelCategTest, public
//
// Synopsis: Basic query categorization feature test.
//
// History: 30 Mar 95 dlee Created
//
// Notes: Just looks for files in the system directory.
//
//--------------------------------------------------------------------------
void MultiLevelCategTest() { LogProgress( "Non-content multi-level categorization query\n" );
SCODE sc;
WCHAR wcsSysDir[MAX_PATH];
#if 0
wcscpy(wcsSysDir,L"g:\\winnt\\system32"); #else
if( !GetSystemDirectory( wcsSysDir, sizeof(wcsSysDir) / sizeof(WCHAR) ) ) LogFail( "Unable to determine system directory.\n" ); #endif
//
// Get name, size and class id for *.exe, *.dll, *.doc, and *.sys
// Group on attribute, then size.
//
CDbColumns cols(8);
cols.Add( psClassid, 0 ); cols.Add( psSize, 1 ); cols.Add( psWriteTime, 2 ); cols.Add( psAttr, 3 ); cols.Add( psName, 4 ); cols.Add( psPath, 5 ); cols.Add( psSelf, 6 ); cols.Add( psBookmark, 7);
CDbNestingNode nest1;
nest1.AddGroupingColumn( psAttr );
nest1.AddParentColumn( psBookmark ); nest1.AddParentColumn( psAttr );
CDbNestingNode nest2;
nest2.AddGroupingColumn( psSize );
nest2.AddParentColumn( psBookmark ); nest2.AddParentColumn( psSize );
nest2.AddChildColumn( psClassid ); nest2.AddChildColumn( psSize ); nest2.AddChildColumn( psWriteTime ); nest2.AddChildColumn( psAttr ); nest2.AddChildColumn( psName ); nest2.AddChildColumn( psPath ); nest2.AddChildColumn( psSelf ); nest2.AddChildColumn( psBookmark);
CDbPropertyRestriction rst;
rst.SetRelation( DBOP_like ); rst.SetProperty( psName ); rst.SetValue( L"*.|(exe|,dll|,doc|,sys|,zzz|)" );
CDbSelectNode * pSelect = new CDbSelectNode(); pSelect->AddRestriction( rst.Clone() );
nest2.AddTable( pSelect ); pSelect = 0; nest1.AddTable( nest2.Clone() );
IRowset * pRowsets[3]; ICommandTree * pCmdTree;
InstantiateMultipleRowsets( QUERY_SHALLOW, // Depth
wcsSysDir, // Scope
nest1.Clone(), // DBCOMMANDTREE
IID_IRowsetScroll, // IID for i/f to return
3, (IUnknown **)pRowsets, &pCmdTree );
IRowset *pRowsetUpperCateg = pRowsets[0]; IRowset *pRowsetLowerCateg = pRowsets[1]; IRowset *pRowset = pRowsets[2];
//
// Verify columns
//
CDbColumns chapCols(4);
chapCols.Add( psBookmark, 0 ); chapCols.Add( psAttr, 1 ); chapCols.Add( psChapt, 2 );
CheckColumns( pRowsetUpperCateg, chapCols );
chapCols.Add( psSize, 1 ); chapCols.Add( psChapt, 2 ); CheckColumns( pRowsetLowerCateg, chapCols );
CheckColumns( pRowset, cols );
if ( !WaitForCompletion( pRowset, FALSE ) ) { pRowset->Release(); LogFail( "Downlevel query unsuccessful.\n" ); }
//
// Do basic function tests.
//
FetchTest(pRowset);
//
// Test SetBindings, GetBindings, Move and Scroll
//
BindingTest(pRowset); BindingTest(pCmdTree, TRUE);
MoveTest( pRowsetUpperCateg );
UpperLevelCategTest( pRowsetUpperCateg, pRowsetLowerCateg, pRowset, cBasicTestCols );
pCmdTree->Release();
pRowset->Release();
pRowsetUpperCateg->Release(); pRowsetLowerCateg->Release();
} //MultiLevelCategTest
#endif // DO_MULTI_LEVEL_CATEG_TEST
//+-------------------------------------------------------------------------
//
// Function: RunPropQuery, public
//
// Synopsis: Execute a retricted query and check results
//
// History:
//
//--------------------------------------------------------------------------
static DBBINDING aPropTestColsByRef[] = { { 0, 0 * (sizeof( PROPVARIANT * )), 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, { 1, 1 * (sizeof( PROPVARIANT * )), 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, { 2, 2 * (sizeof( PROPVARIANT * )), 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, { 3, 3 * (sizeof( PROPVARIANT * )), 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, { sizeof( PROPVARIANT * ), 4 * (sizeof( PROPVARIANT * )), 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, { 5, 5 * (sizeof( PROPVARIANT * )), 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, { 6, 6 * (sizeof( PROPVARIANT * )), 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, { 7, 7 * (sizeof( PROPVARIANT * )), 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, { 8, 8 * (sizeof( PROPVARIANT * )), 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, { 9, 9 * (sizeof( PROPVARIANT * )), 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, { 10,10* (sizeof( PROPVARIANT * )), 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, { 11,11* (sizeof( PROPVARIANT * )), 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, { 12,12* (sizeof( PROPVARIANT * )), 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, { 13,13* (sizeof( PROPVARIANT * )), 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof( PROPVARIANT * ), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, };
const ULONG cPropTestColsByRef = sizeof aPropTestColsByRef / sizeof aPropTestColsByRef[0];
LPWSTR aPropTestColNames[] = { L"TestProp1", L"TestProp2", L"Author", L"Keywords", L"RelevantWords", L"MyBlob", L"MyGuid", L"ManyRW", L"SecurityTest", L"TestProp10", L"TestProp11", L"TestProp12", L"TestProp21", L"TestProp22", L"Path", };
void RunPropQueryByRefBindings( ICommand * pQuery, CDbRestriction & PropRst, unsigned cExpectedHits, unsigned numTest ) { //
// Get twelve properties back
//
CDbColumns cols(cPropTestColsByRef); cols.Add( psTestProperty1, 0 ); cols.Add( psTestProperty2, 1 ); cols.Add( psAuthor, 2 ); cols.Add( psKeywords, 3 ); cols.Add( psRelevantWords, 4 ); cols.Add( psBlobTest, 5 ); cols.Add( psGuidTest, 6 ); cols.Add( psManyRW, 7 ); cols.Add( psSecurityTest, 8 ); cols.Add( psTestProperty10, 9 ); cols.Add( psTestProperty11, 10 ); cols.Add( psTestProperty12, 11 ); cols.Add( psTestProperty21, 12 ); cols.Add( psTestProperty22, 13 ); if (isEven( numTest/2 )) cols.Add( psPath, cols.Count() );
BOOL fSeq = isEven( numTest );
CDbSortSet ss(cPropSortColumns); for (unsigned i = 0; i < cPropSortColumns; i++) ss.Add (aPropSortCols[i], i);
//
// Do it!
//
CDbCmdTreeNode * pDbCmdTree = FormQueryTree( &PropRst, cols, fSeq ? 0 : &ss, aPropTestColNames ); ICommandTree * pCmdTree = 0;
IRowsetScroll * pRowset = InstantiateRowset( pQuery, QUERY_SHALLOW, // Depth
0, // Scope
pDbCmdTree, // DBCOMMANDTREE
fSeq ? IID_IRowset : IID_IRowsetScroll, // IID for i/f to return
0, &pCmdTree );
//
// Verify columns
//
CheckColumns( pRowset, cols, TRUE );
if ( !WaitForCompletion( pRowset, TRUE ) ) { LogError( "property query unsuccessful.\n" ); pCmdTree->Release(); pRowset->Release(); Fail(); }
//
// Get data
//
DBCOUNTITEM cRowsReturned = 0; HROW* pgrhRows = 0;
SCODE sc = pRowset->GetNextRows(0, 0, 10, &cRowsReturned, &pgrhRows);
if ( FAILED( sc ) ) { LogError( "IRowset->GetRowsAt A returned 0x%x\n", sc ); pCmdTree->Release(); pRowset->Release(); Fail(); }
if ( 0 == cExpectedHits ) { pCmdTree->Release(); pRowset->Release();
if ( cRowsReturned > 0 ) LogFail("RunPropQueryByRefBindings, %d returned rows, expected 0\n", cRowsReturned); else return;
}
if (sc != DB_S_ENDOFROWSET && cRowsReturned != 10) { LogError( "IRowset->GetRowsAt B returned %d of %d rows," " status (%x) != DB_S_ENDOFROWSET\n", cRowsReturned, 10, sc); pCmdTree->Release(); pRowset->Release(); #if defined(UNIT_TEST)
cFailures++; return; #else
Fail(); #endif
}
//
// Expect 1 or 2 hits
//
if (sc != DB_S_ENDOFROWSET || cRowsReturned != cExpectedHits) { LogError( "IRowset->GetRowsAt C returned %d rows (expected %d)," " status (%x)\n", cRowsReturned, cExpectedHits, sc ); pCmdTree->Release(); pRowset->Release(); #if defined(UNIT_TEST)
cFailures++; return; #else
Fail(); #endif
}
//
// Patch the column index numbers with true column ids
//
DBID aDbCols[cPropTestColsByRef]; aDbCols[0] = psTestProperty1; aDbCols[1] = psTestProperty2; aDbCols[2] = psAuthor; aDbCols[3] = psKeywords; aDbCols[4] = psRelevantWords; aDbCols[5] = psBlobTest; aDbCols[6] = psGuidTest; aDbCols[7] = psManyRW; aDbCols[8] = psSecurityTest; aDbCols[9] = psTestProperty10; aDbCols[10] = psTestProperty11; aDbCols[11] = psTestProperty12; aDbCols[12] = psTestProperty21; aDbCols[13] = psTestProperty22;
IUnknown * pAccessor = (IUnknown *) pRowset; // hAccessor must be created on rowset
// to be used with rowset->GetData below
HACCESSOR hAccessor = MapColumns( pAccessor, cPropTestColsByRef, aPropTestColsByRef, aDbCols, TRUE);
//
// Fetch the data
//
PROPVARIANT * aVarnt[cPropTestColsByRef];
for (unsigned row = 0; row < cRowsReturned; row++) { sc = pRowset->GetData(pgrhRows[row], hAccessor, aVarnt);
if (S_OK != sc) { LogError("IRowset->GetData returned 0x%x (expected 0)\n",sc); pCmdTree->Release(); pRowset->Release(); Fail(); }
//
// Verify the data.
//
// Ascending sort, prop1 > prop1Alternate.
// If one hit, it's PROP1_VAL, not the alternate.
// prop1=1234, alternate=123
BOOL fAlternate = FALSE; if ( fSeq ) { if ( 1 == cRowsReturned ) { varProp1.lVal = PROP1_VAL; CheckPropertyValue( *aVarnt[0], varProp1 ); } else { // no sort order -- it's either prop1 or alternate
if ( PROP1_TYPE != aVarnt[0]->vt ) LogFail( "bad datatype for prop1: 0x%x\n", aVarnt[0]->vt );
if ( PROP1_VAL != aVarnt[0]->lVal && PROP1_VAL_Alternate != aVarnt[0]->lVal ) LogFail( "bad value for prop1: 0x%x\n", aVarnt[0]->lVal ); fAlternate = aVarnt[0]->lVal == PROP1_VAL_Alternate; } } else { fAlternate = (0 == row) && (1 != cRowsReturned); varProp1.lVal = fAlternate ? PROP1_VAL_Alternate : PROP1_VAL; CheckPropertyValue( *aVarnt[0], varProp1 ); }
CheckPropertyValue( *aVarnt[1], varProp2 ); CheckPropertyValue( *aVarnt[2], varProp3 ); CheckPropertyValue( *aVarnt[3], varProp4 ); CheckPropertyValue( *aVarnt[4], varProp5 ); CheckPropertyValue( *aVarnt[5], varProp6 ); CheckPropertyValue( *aVarnt[6], varProp7 ); CheckPropertyValue( *aVarnt[7], fAlternate ? varProp8A : varProp8 ); CheckPropertyValue( *aVarnt[8], varProp9 ); CheckPropertyValue( *aVarnt[9], varProp10 ); if ( aVarnt[10]->vt == VT_BSTR && SysStringLen( aVarnt[10]->bstrVal) < 1000 ) { CheckPropertyValue( *aVarnt[10], varProp11 ); } else { CheckPropertyValue( *aVarnt[10], varProp11A ); } CheckPropertyValue( *aVarnt[11], varProp12 ); CheckPropertyValue( *aVarnt[12], varProp21 ); CheckPropertyValue( *aVarnt[13], varProp22 ); }
sc = pRowset->ReleaseRows( cRowsReturned, pgrhRows, 0, 0, 0);
if (S_OK != sc) { LogError("IRowset->ReleaseRows returned 0x%x (expected 0)\n",sc); pCmdTree->Release(); pRowset->Release(); Fail(); }
CoTaskMemFree(pgrhRows); pgrhRows = 0;
//
// Clean up.
//
ReleaseAccessor( pAccessor, hAccessor);
pCmdTree->Release(); pRowset->Release(); } //RunPropQueryByRefBindings
struct SPropTestColsTight { int p1_i4; WCHAR * p2_pwc; WCHAR * p3_pwc; int dummy1; // vectors need 8 byte alignment
DBVECTOR p4_vpwc; DBVECTOR p5_vi; PROPVARIANT* p6_pvar; GUID * p7_pguid; DBVECTOR p8_vi; SAFEARRAY * p8a_ai; int p9_i4; WCHAR * p10_pwc; BSTR p11_pwc; DBVECTOR p12_vpwc; CLIPDATA * p21_pclipdata; int dummy3; // vectors need 8 byte alignment
CACLIPDATA p22_caclipdata; WCHAR * p2a_pwc;
DBLENGTH p1_cb; DBLENGTH p2_cb; DBLENGTH p3_cb; DBLENGTH p4_cb; DBLENGTH p5_cb; DBLENGTH p6_cb; DBLENGTH p7_cb; DBLENGTH p8_cb; DBLENGTH p8a_cb; DBLENGTH p9_cb; DBLENGTH p10_cb; DBLENGTH p11_cb; DBLENGTH p12_cb; DBLENGTH p21_cb; DBLENGTH p22_cb; DBLENGTH p2a_cb;
ULONG p1_status; ULONG p2_status; ULONG p3_status; ULONG p4_status; ULONG p5_status; ULONG p6_status; ULONG p7_status; ULONG p8_status; ULONG p8a_status; ULONG p9_status; ULONG p10_status; ULONG p11_status; ULONG p12_status; ULONG p21_status; ULONG p22_status; ULONG p2a_status; };
#define DBTYPE_BRWSTR ( DBTYPE_BYREF | DBTYPE_WSTR )
static DBBINDING aPropTestColsTight[] = { { 0, offsetof(SPropTestColsTight,p1_i4), offsetof(SPropTestColsTight,p1_cb), offsetof(SPropTestColsTight,p1_status), 0,0,0, ALLPARTS, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, sizeof ULONG, 0, DBTYPE_I4, 0, 0 }, { 1, offsetof(SPropTestColsTight,p2_pwc), offsetof(SPropTestColsTight,p2_cb), offsetof(SPropTestColsTight,p2_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof (WCHAR *), 0, DBTYPE_BRWSTR, 0, 0 }, { 2, offsetof(SPropTestColsTight,p3_pwc), offsetof(SPropTestColsTight,p3_cb), offsetof(SPropTestColsTight,p3_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof (WCHAR *), 0, DBTYPE_BRWSTR, 0, 0 }, { 3, offsetof(SPropTestColsTight,p4_vpwc), offsetof(SPropTestColsTight,p4_cb), offsetof(SPropTestColsTight,p4_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof DBVECTOR, 0, DBTYPE_VECTOR|VT_LPWSTR, 0, 0 }, { 4, offsetof(SPropTestColsTight,p5_vi), offsetof(SPropTestColsTight,p5_cb), offsetof(SPropTestColsTight,p5_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof DBVECTOR, 0, DBTYPE_VECTOR|DBTYPE_I4, 0, 0 }, { 5, offsetof(SPropTestColsTight,p6_pvar), offsetof(SPropTestColsTight,p6_cb), offsetof(SPropTestColsTight,p6_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof (PROPVARIANT *), 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0 }, { 6, offsetof(SPropTestColsTight,p7_pguid), offsetof(SPropTestColsTight,p7_cb), offsetof(SPropTestColsTight,p7_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof (GUID *), 0, DBTYPE_GUID|DBTYPE_BYREF, 0, 0 }, { 7, offsetof(SPropTestColsTight,p8_vi), offsetof(SPropTestColsTight,p8_cb), offsetof(SPropTestColsTight,p8_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof DBVECTOR, 0, DBTYPE_VECTOR|DBTYPE_I4, 0, 0 }, { 8, offsetof(SPropTestColsTight,p9_i4), offsetof(SPropTestColsTight,p9_cb), offsetof(SPropTestColsTight,p9_status), 0,0,0, ALLPARTS, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, sizeof ULONG, 0, DBTYPE_I4, 0, 0 }, { 9, offsetof(SPropTestColsTight,p10_pwc), offsetof(SPropTestColsTight,p10_cb), offsetof(SPropTestColsTight,p10_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof (WCHAR *), 0, DBTYPE_BRWSTR, 0, 0 }, { 10, offsetof(SPropTestColsTight,p11_pwc), offsetof(SPropTestColsTight,p11_cb), offsetof(SPropTestColsTight,p11_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof (BSTR), 0, DBTYPE_BSTR, 0, 0 }, { 11, offsetof(SPropTestColsTight,p12_vpwc), offsetof(SPropTestColsTight,p12_cb), offsetof(SPropTestColsTight,p12_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof DBVECTOR, 0, DBTYPE_VECTOR|DBTYPE_BSTR, 0, 0 }, { 12, offsetof(SPropTestColsTight,p21_pclipdata), offsetof(SPropTestColsTight,p21_cb), offsetof(SPropTestColsTight,p21_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof( CLIPDATA * ), 0, VT_CF | DBTYPE_BYREF, 0, 0 }, { 13, offsetof(SPropTestColsTight,p22_caclipdata), offsetof(SPropTestColsTight,p22_cb), offsetof(SPropTestColsTight,p22_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof CACLIPDATA, 0, DBTYPE_VECTOR | VT_CF, 0, 0 }, { 14, // Prop 2 again, as a different type
offsetof(SPropTestColsTight,p2a_pwc), offsetof(SPropTestColsTight,p2a_cb), offsetof(SPropTestColsTight,p2a_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, 30, 0, DBTYPE_WSTR | DBTYPE_BYREF, 0, 0 }, { 15, // Prop 8 again, as a different type
offsetof(SPropTestColsTight,p8a_ai), offsetof(SPropTestColsTight,p8a_cb), offsetof(SPropTestColsTight,p8a_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof (SAFEARRAY *), 0, DBTYPE_ARRAY|DBTYPE_I4, 0, 0 }, };
const ULONG cPropTestColsTight = sizeof aPropTestColsTight / sizeof aPropTestColsTight[0];
void RunPropQueryTightBindings( ICommand * pQuery, CDbRestriction & PropRst, unsigned cExpectedHits, unsigned numTest ) { //
// Get twelve properties back
//
CDbColumns cols(cPropTestColsTight); cols.Add( psTestProperty1, 0 ); cols.Add( psTestProperty2, 1 ); cols.Add( psAuthor, 2 ); cols.Add( psKeywords, 3 ); cols.Add( psRelevantWords, 4 ); cols.Add( psBlobTest, 5 ); cols.Add( psGuidTest, 6 ); cols.Add( psManyRW, 7 ); cols.Add( psSecurityTest, 8 ); cols.Add( psTestProperty10, 9 ); cols.Add( psTestProperty11, 10 ); cols.Add( psTestProperty12, 11 ); cols.Add( psTestProperty21, 12 ); cols.Add( psTestProperty22, 13 );
CDbSortSet ss(cPropSortColumns); for (unsigned i = 0; i < cPropSortColumns; i++) ss.Add (aPropSortCols[i], i);
//
// Do it!
//
CDbCmdTreeNode * pDbCmdTree = FormQueryTree(&PropRst, cols, &ss); ICommandTree * pCmdTree = 0;
IRowsetScroll * pRowset = InstantiateRowset( pQuery, QUERY_SHALLOW, // Depth
0, // Scope
pDbCmdTree, // DBCOMMANDTREE
IID_IRowsetScroll, // IID for i/f to return
0, &pCmdTree, TRUE );
//
// Verify columns
//
CheckColumns( pRowset, cols, TRUE );
if ( !WaitForCompletion( pRowset, TRUE ) ) { LogError( "property query unsuccessful.\n" ); pCmdTree->Release(); pRowset->Release(); Fail(); }
//
// Get data
//
DBCOUNTITEM cRowsReturned = 0; HROW* pgrhRows = 0;
SCODE sc = pRowset->GetRowsAt(0,0, 1, &bmkFirst, 0, 10, &cRowsReturned, &pgrhRows);
if ( FAILED( sc ) ) { LogError( "IRowset->GetRowsAt D returned 0x%x\n", sc ); pCmdTree->Release(); pRowset->Release(); Fail(); }
if ( 0 == cExpectedHits ) { pCmdTree->Release(); pRowset->Release();
if ( cRowsReturned > 0 ) { LogError("RunPropQueryTightBindings, %d returned rows, expected 0\n", cRowsReturned); #if defined(UNIT_TEST)
cFailures++; return; #else
Fail(); #endif
} else return;
}
if (sc != DB_S_ENDOFROWSET && cRowsReturned != 10) { LogError( "IRowset->GetRowsAt E returned %d of %d rows," " status (%x) != DB_S_ENDOFROWSET\n", cRowsReturned, 10, sc); pCmdTree->Release(); pRowset->Release(); #if defined(UNIT_TEST)
cFailures++; return; #else
Fail(); #endif
}
//
// Expect 1 or 2 hits
//
if (sc != DB_S_ENDOFROWSET || cRowsReturned != cExpectedHits) { LogError( "IRowset->GetRowsAt F returned %d rows (expected %d)," " status (%x)\n", cRowsReturned, cExpectedHits, sc ); pCmdTree->Release(); pRowset->Release(); #if defined(UNIT_TEST)
cFailures++; return; #else
Fail(); #endif
}
//
// Patch the column index numbers with true column ids
//
DBID aDbCols[cPropTestColsTight]; aDbCols[0] = psTestProperty1; aDbCols[1] = psTestProperty2; aDbCols[2] = psAuthor; aDbCols[3] = psKeywords; aDbCols[4] = psRelevantWords; aDbCols[5] = psBlobTest; aDbCols[6] = psGuidTest; aDbCols[7] = psManyRW; aDbCols[8] = psSecurityTest; aDbCols[9] = psTestProperty10; aDbCols[10] = psTestProperty11; aDbCols[11] = psTestProperty12; aDbCols[12] = psTestProperty21; aDbCols[13] = psTestProperty22; aDbCols[14] = psTestProperty2; // repeated
aDbCols[15] = psManyRW; // repeated
IUnknown * pAccessor = (IUnknown *) pRowset; // hAccessor must be created on rowset
// to be used with rowset->GetData below
HACCESSOR hAccessor = MapColumns( pAccessor, cPropTestColsTight, aPropTestColsTight, aDbCols, TRUE);
//
// Fetch the data
//
for (unsigned row = 0; row < cRowsReturned; row++) { SPropTestColsTight sRow;
// Ascending sort, prop1 > prop1Alternate.
// If one hit, it's not the alternate.
BOOL fAlternate = (0 == row) && (1 != cRowsReturned);
sc = pRowset->GetData( pgrhRows[row], hAccessor, & sRow );
// Either the conversion of varProp8 to array will fail, or the
// conversion of varProp8A to vector will fail.
if (DB_S_ERRORSOCCURRED != sc && !fAlternate) { LogError("IRowset->GetData returned 0x%x (expected 0)\n",sc); LogError("IRowset->GetData returned 0x%x (expected 0x40eda)\n",sc); if (S_OK != sc && DB_E_ERRORSOCCURRED != sc) { pCmdTree->Release(); pRowset->Release(); Fail(); } }
if (DB_S_ERRORSOCCURRED != sc && fAlternate) { // Prop 8 should fail to convert for alternate row.
LogError("IRowset->GetData returned 0x%x (expected 0x40eda)\n",sc); if (S_OK != sc && DB_E_ERRORSOCCURRED != sc) { pCmdTree->Release(); pRowset->Release(); Fail(); } }
//
// Verify the data. Put output data into variants for comparison
//
PROPVARIANT vTest;
if ( DBSTATUS_S_OK != sRow.p1_status ) LogFail( "status of property 1 is bad: %x\n", sRow.p1_status ); varProp1.lVal = fAlternate ? PROP1_VAL_Alternate : PROP1_VAL; vTest.vt = DBTYPE_I4; vTest.iVal = (SHORT) sRow.p1_i4; CheckPropertyValue( vTest, varProp1 ); if ( sRow.p1_cb != PROP1_cb ) LogFail( "cb of property 1 is %ld, should be %ld\n", sRow.p1_cb, PROP1_cb );
if ( DBSTATUS_S_OK != sRow.p2_status ) LogFail( "status of property 2 is bad: %x\n", sRow.p2_status ); vTest.vt = VT_LPWSTR; vTest.pwszVal = sRow.p2_pwc; CheckPropertyValue( vTest, varProp2 ); if ( sRow.p2_cb != PROP2_cb ) LogFail( "cb of property 2 is %ld, should be %ld\n", sRow.p2_cb, PROP2_cb );
if ( DBSTATUS_S_OK != sRow.p3_status ) LogFail( "status of property 3 is bad: %x\n", sRow.p3_status ); vTest.vt = VT_LPWSTR; vTest.pwszVal = sRow.p3_pwc; CheckPropertyValue( vTest, varProp3 ); if ( sRow.p3_cb != PROP3_cb ) LogFail( "cb of property 3 is %ld, should be %ld\n", sRow.p3_cb, PROP3_cb );
if ( DBSTATUS_S_OK != sRow.p4_status ) LogFail( "status of property 4 is bad: %x\n", sRow.p4_status ); vTest.vt = VT_VECTOR | VT_LPWSTR; memcpy( & vTest.cal, & sRow.p4_vpwc, sizeof DBVECTOR ); CheckPropertyValue( vTest, varProp4 ); if ( sRow.p4_cb != PROP4_cb ) LogFail( "cb of property 4 is %ld, should be %ld\n", sRow.p4_cb, PROP4_cb );
if ( DBSTATUS_S_OK != sRow.p5_status ) LogFail( "status of property 5 is bad: %x\n", sRow.p5_status ); vTest.vt = VT_VECTOR | VT_I4; memcpy( & vTest.cal, & sRow.p5_vi, sizeof DBVECTOR ); CheckPropertyValue( vTest, varProp5 ); if ( sRow.p5_cb != PROP5_cb ) LogFail( "cb of property 5 is %ld, should be %ld\n", sRow.p5_cb, PROP5_cb );
if ( DBSTATUS_S_OK != sRow.p6_status ) LogFail( "status of property 6 is bad: %x\n", sRow.p6_status ); CheckPropertyValue( *sRow.p6_pvar, varProp6 ); // is cb of 20 right, or is 0 right? blobs aren't in OLEDB!
if ( sRow.p6_cb != PROP6_cb ) LogFail( "cb of property 6 is %ld, should be %ld\n", sRow.p6_cb, PROP6_cb );
if ( DBSTATUS_S_OK != sRow.p7_status ) LogFail( "status of property 7 is bad: %x\n", sRow.p7_status ); vTest.vt = VT_CLSID; vTest.puuid = sRow.p7_pguid; CheckPropertyValue( vTest, varProp7 ); if ( sRow.p7_cb != PROP7_cb ) LogFail( "cb of property 7 is %ld, should be %ld\n", sRow.p7_cb, PROP7_cb );
if (! fAlternate) { if ( DBSTATUS_S_OK != sRow.p8_status ) LogFail( "status of property 8 is bad: %x\n", sRow.p8_status ); if ( DBSTATUS_E_CANTCONVERTVALUE != sRow.p8a_status ) LogFail( "alt. status of property 8 is OK for prim: %x\n", sRow.p8a_status ); vTest.vt = VT_VECTOR | VT_I4; memcpy( & vTest.cal, & sRow.p8_vi, sizeof DBVECTOR ); CheckPropertyValue( vTest, varProp8 ); if ( sRow.p8_cb != PROP8_cb ) LogFail( "cb of property 8 is %ld, should be %ld\n", sRow.p8_cb, PROP8_cb ); } else { if ( DBSTATUS_E_CANTCONVERTVALUE != sRow.p8_status ) LogFail( "status of property 8 is OK for alt: %x\n", sRow.p8_status ); if ( DBSTATUS_S_OK != sRow.p8a_status ) LogFail( "alt status of property 8 is bad: %x\n", sRow.p8a_status ); vTest.vt = VT_ARRAY | VT_I4; memcpy( &vTest.parray, &sRow.p8a_ai, sizeof (SAFEARRAY *) ); CheckPropertyValue( vTest, varProp8A ); }
// can't see prop9 due to its no-read security
if ( DBSTATUS_S_ISNULL != sRow.p9_status ) LogFail( "status of property 9 is bad: %x\n", sRow.p9_status ); if ( 0 != sRow.p9_cb ) LogFail( "cb of property 9 is bad: %x\n", sRow.p9_cb );
if ( DBSTATUS_S_OK != sRow.p10_status ) LogFail( "status of property 10 is bad: %x\n", sRow.p10_status ); vTest.vt = VT_LPWSTR; vTest.pwszVal = sRow.p10_pwc; CheckPropertyValue( vTest, varProp10 ); if ( sRow.p10_cb != PROP10_cb ) LogFail( "cb of property 10 is %ld, should be %ld\n", sRow.p10_cb, PROP10_cb );
if ( DBSTATUS_S_OK != sRow.p11_status ) LogFail( "status of property 11 is bad: %x\n", sRow.p11_status ); vTest.vt = VT_BSTR; vTest.pwszVal = sRow.p11_pwc; // Note: prop 11 conditional on size...
if ( SysStringLen(sRow.p11_pwc) > 1000) { CheckPropertyValue( vTest, varProp11A ); } else { CheckPropertyValue( vTest, varProp11 ); }
// NOTE: the length of a BSTR is sizeof BSTR
//unsigned PROP11_cb = SysStringLen(varProp11.bstrVal) * sizeof (OLECHAR)
// + sizeof (DWORD) + sizeof (OLECHAR);
unsigned PROP11_cb = sizeof BSTR; if ( sRow.p11_cb != PROP11_cb ) LogFail( "cb of property 11 is %ld, should be %ld\n", sRow.p11_cb, PROP11_cb );
if ( DBSTATUS_S_OK != sRow.p12_status ) LogFail( "status of property 12 is bad: %x\n", sRow.p12_status ); vTest.vt = VT_VECTOR | VT_BSTR; memcpy( & vTest.cal, & sRow.p12_vpwc, sizeof DBVECTOR ); CheckPropertyValue( vTest, varProp12 ); if ( sRow.p12_cb != PROP4_cb ) LogFail( "cb of property 12 is %ld, should be %ld\n", sRow.p12_cb, PROP4_cb );
if ( DBSTATUS_S_OK != sRow.p21_status ) LogFail( "status of property 21 is bad: %x\n", sRow.p21_status ); vTest.vt = VT_CF; vTest.pclipdata = sRow.p21_pclipdata; CheckPropertyValue( vTest, varProp21 ); if ( sRow.p21_cb != PROP21_cb ) LogFail( "cb of property 21 is %ld, should be %ld\n", sRow.p21_cb, PROP21_cb );
if ( DBSTATUS_S_OK != sRow.p22_status ) LogFail( "status of property 22 is bad: %x\n", sRow.p22_status ); vTest.vt = VT_VECTOR | VT_CF; vTest.caclipdata = sRow.p22_caclipdata; CheckPropertyValue( vTest, varProp22 ); if ( sRow.p22_cb != PROP22_cb ) LogFail( "cb of property 22 is %ld, should be %ld\n", sRow.p22_cb, PROP22_cb );
if ( DBSTATUS_S_OK != sRow.p2a_status ) LogFail( "status of property 2 as WSTR is bad: %x\n", sRow.p2a_status );
vTest.vt = VT_LPWSTR; vTest.pwszVal = sRow.p2a_pwc; CheckPropertyValue( vTest, varProp2 );
if ( sRow.p2a_cb != PROP2_cb ) LogFail( "cb of property 2 as WSTR is %ld, should be %ld\n", sRow.p2a_cb, PROP2_cb ); // Don't free anything -- this is byref
}
sc = pRowset->ReleaseRows( cRowsReturned, pgrhRows, 0, 0, 0);
if (S_OK != sc) { LogError("IRowset->ReleaseRows returned 0x%x (expected 0)\n",sc); pRowset->Release(); Fail(); }
CoTaskMemFree(pgrhRows); pgrhRows = 0;
//
// Clean up.
//
ReleaseAccessor( pAccessor, hAccessor);
pCmdTree->Release(); pRowset->Release();
} //RunPropQueryTightBindings
//+-------------------------------------------------------------------------
//
// Function: RunPropQuery, public
//
// Synopsis: Execute a retricted query and check results
//
// History:
//
//--------------------------------------------------------------------------
static DBBINDING aPropTestCols[] = { { 0, 0 * cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, { 1, 1 * cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, { 2, 2 * cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, { 3, 3 * cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, { 4, 4 * cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, { 5, 5 * cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, { 6, 6 * cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, { 7, 7 * cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, { 8, 8 * cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, { 9, 9 * cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, { 10,10* cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, { 11,11* cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, { 12,12* cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, { 13,13* cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, };
const ULONG cPropTestCols = sizeof aPropTestCols / sizeof aPropTestCols[0];
void RunPropQuery( ICommand * pQuery, CDbRestriction & PropRst, unsigned cExpectedHits, unsigned numTest ) { RunPropQueryTightBindings( pQuery, PropRst, cExpectedHits, numTest ); RunPropQueryByRefBindings( pQuery, PropRst, cExpectedHits, numTest );
//
// Get twelve properties back
//
CDbColumns cols(cPropTestCols); cols.Add( psTestProperty1, 0 ); cols.Add( psTestProperty2, 1 ); cols.Add( psAuthor, 2 ); cols.Add( psKeywords, 3 ); cols.Add( psRelevantWords, 4 ); cols.Add( psBlobTest, 5 ); cols.Add( psGuidTest, 6 ); cols.Add( psManyRW, 7 ); cols.Add( psSecurityTest, 8 ); cols.Add( psTestProperty10, 9 ); cols.Add( psTestProperty11, 10 ); cols.Add( psTestProperty12, 11 ); cols.Add( psTestProperty21, 12 ); cols.Add( psTestProperty22, 13 );
BOOL fSeq = isEven( numTest );
CDbSortSet ss(cPropSortColumns); for (unsigned i = 0; i < cPropSortColumns; i++) ss.Add (aPropSortCols[i], i);
//
// Do it!
//
CDbCmdTreeNode * pDbCmdTree = FormQueryTree( &PropRst, cols, fSeq ? 0 : &ss );
ICommandTree * pCmdTree = 0;
IRowsetScroll * pRowset = InstantiateRowset( pQuery, QUERY_SHALLOW, // Depth
0, pDbCmdTree, // DBCOMMANDTREE
fSeq ? IID_IRowset : IID_IRowsetScroll, // IID for i/f to return
0, &pCmdTree );
//
// Verify columns
//
CheckColumns( pRowset, cols, TRUE );
if ( !WaitForCompletion( pRowset, TRUE ) ) { pCmdTree->Release(); pRowset->Release(); LogFail( "property query unsuccessful.\n" ); }
//
// Get data
//
DBCOUNTITEM cRowsReturned = 0; HROW* pgrhRows = 0;
SCODE sc = pRowset->GetNextRows(0, 0, 10, &cRowsReturned, &pgrhRows);
if ( FAILED( sc ) ) { pCmdTree->Release(); pRowset->Release(); LogFail( "IRowset->GetRowsAt G returned 0x%x\n", sc ); }
if ( 0 == cExpectedHits ) { pCmdTree->Release(); pRowset->Release();
if ( cRowsReturned > 0 ) LogFail("RunPropQuery, %d returned rows, expected none\n", cRowsReturned); else return;
}
if (sc != DB_S_ENDOFROWSET && cRowsReturned != 10) { LogError( "IRowset->GetRowsAt H returned %d of %d rows," " status (%x) != DB_S_ENDOFROWSET\n", cRowsReturned, 10, sc); pCmdTree->Release(); pRowset->Release(); #if defined(UNIT_TEST)
cFailures++; return; #else
Fail(); #endif
}
//
// Expect 1 or 2 hits
//
if (sc != DB_S_ENDOFROWSET || cRowsReturned != cExpectedHits) { LogError( "IRowset->GetRowsAt I returned %d rows (expected %d)," " status (%x)\n", cRowsReturned, cExpectedHits, sc ); pCmdTree->Release(); pRowset->Release(); #if defined(UNIT_TEST)
cFailures++; return; #else
Fail(); #endif
}
//
// Patch the column index numbers with true column ids
//
DBID aDbCols[cPropTestCols]; aDbCols[0] = psTestProperty1; aDbCols[1] = psTestProperty2; aDbCols[2] = psAuthor; aDbCols[3] = psKeywords; aDbCols[4] = psRelevantWords; aDbCols[5] = psBlobTest; aDbCols[6] = psGuidTest; aDbCols[7] = psManyRW; aDbCols[8] = psSecurityTest; aDbCols[9] = psTestProperty10; aDbCols[10] = psTestProperty11; aDbCols[11] = psTestProperty12; aDbCols[12] = psTestProperty21; aDbCols[13] = psTestProperty22;
IUnknown * pAccessor = (IUnknown *) pRowset; // hAccessor must be created on rowset
// to be used with rowset->GetData below
HACCESSOR hAccessor = MapColumns(pAccessor, cPropTestCols, aPropTestCols, aDbCols);
//
// Fetch the data
//
PROPVARIANT aVarnt[cPropTestCols];
for (unsigned row = 0; row < cRowsReturned; row++) { sc = pRowset->GetData(pgrhRows[row], hAccessor, aVarnt);
if (S_OK != sc) { LogError("IRowset->GetData returned 0x%x (expected 0)\n",sc); pCmdTree->Release(); pRowset->Release(); Fail(); }
//
// Verify the data.
//
// Ascending sort, prop1 > prop1Alternate.
// If one hit, it's PROP1_VAL, not the alternate.
// prop1=1234, alternate=123
BOOL fAlternate = FALSE; if ( fSeq ) { if ( 1 == cRowsReturned ) { varProp1.lVal = PROP1_VAL; CheckPropertyValue( aVarnt[0], varProp1 ); } else { // no sort order -- it's either prop1 or alternate
if ( PROP1_TYPE != aVarnt[0].vt ) LogFail( "bad datatype for prop1: 0x%x\n", aVarnt[0].vt );
if ( PROP1_VAL != aVarnt[0].lVal && PROP1_VAL_Alternate != aVarnt[0].lVal ) LogFail( "bad value for prop1: 0x%x\n", aVarnt[0].lVal ); fAlternate = aVarnt[0].lVal == PROP1_VAL_Alternate; } } else { fAlternate = (0 == row) && (1 != cRowsReturned); varProp1.lVal = fAlternate ? PROP1_VAL_Alternate : PROP1_VAL; CheckPropertyValue( aVarnt[0], varProp1 ); }
CheckPropertyValue( aVarnt[1], varProp2 ); CheckPropertyValue( aVarnt[2], varProp3 ); CheckPropertyValue( aVarnt[3], varProp4 ); CheckPropertyValue( aVarnt[4], varProp5 ); CheckPropertyValue( aVarnt[5], varProp6 ); CheckPropertyValue( aVarnt[6], varProp7 ); CheckPropertyValue( aVarnt[7], fAlternate ? varProp8A : varProp8 ); CheckPropertyValue( aVarnt[8], varProp9 ); CheckPropertyValue( aVarnt[9], varProp10 ); if ( aVarnt[10].vt == VT_BSTR && SysStringLen( aVarnt[10].bstrVal) < 1000 ) { CheckPropertyValue( aVarnt[10], varProp11 ); } else { CheckPropertyValue( aVarnt[10], varProp11A ); } CheckPropertyValue( aVarnt[11], varProp12 ); CheckPropertyValue( aVarnt[12], varProp21 ); CheckPropertyValue( aVarnt[13], varProp22 );
//
// Free extra data allocated byref in the variants above
//
CoTaskMemFree(aVarnt[1].pwszVal); CoTaskMemFree(aVarnt[2].pwszVal);
for (unsigned x = 0; x < aVarnt[3].calpwstr.cElems; x++ ) CoTaskMemFree( aVarnt[3].calpwstr.pElems[ x ] );
CoTaskMemFree(aVarnt[3].calpwstr.pElems); CoTaskMemFree(aVarnt[4].cal.pElems); CoTaskMemFree(aVarnt[5].blob.pBlobData); CoTaskMemFree(aVarnt[6].puuid);
// sometimes a VT_VECTOR, sometimes a VT_ARRAY
HRESULT hrPVC = PropVariantClear( &aVarnt[7] ); if ( S_OK != hrPVC ) LogError( "bad propvariant clear: %#x\n", hrPVC );
// nothing to free for [8] -- insufficient security to load value
CoTaskMemFree(aVarnt[9].pwszVal); PropVariantClear(&aVarnt[10]); PropVariantClear(&aVarnt[11]); PropVariantClear(&aVarnt[12]); PropVariantClear(&aVarnt[13]); }
sc = pRowset->ReleaseRows( cRowsReturned, pgrhRows, 0, 0, 0);
if (S_OK != sc) { LogError("IRowset->ReleaseRows returned 0x%x (expected 0)\n",sc); pCmdTree->Release(); pRowset->Release(); Fail(); }
CoTaskMemFree(pgrhRows); pgrhRows = 0;
//
// Clean up.
//
ReleaseAccessor( pAccessor, hAccessor);
pCmdTree->Release(); pRowset->Release(); } //RunPropQuery
const int COERCE_PROP_BUF_SIZE = 129;
struct CoercePropStruct { char szProp13[COERCE_PROP_BUF_SIZE]; char szProp14[COERCE_PROP_BUF_SIZE]; char szProp15[COERCE_PROP_BUF_SIZE]; char szProp16[COERCE_PROP_BUF_SIZE]; char szProp17[COERCE_PROP_BUF_SIZE]; char szProp18[COERCE_PROP_BUF_SIZE]; char szProp19[COERCE_PROP_BUF_SIZE]; char szProp7[COERCE_PROP_BUF_SIZE]; double szProp20; } ;
static DBBINDING aPropTestCoerceCols[] = {
{ 0, COERCE_PROP_BUF_SIZE * 0, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, COERCE_PROP_BUF_SIZE, 0, DBTYPE_STR, 0, 0}, // prop13
{ 1, COERCE_PROP_BUF_SIZE * 1, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, COERCE_PROP_BUF_SIZE, 0, DBTYPE_STR, 0, 0}, // prop14
{ 2, COERCE_PROP_BUF_SIZE * 2, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, COERCE_PROP_BUF_SIZE, 0, DBTYPE_STR, 0, 0}, // prop15
{ 3, COERCE_PROP_BUF_SIZE * 3, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, COERCE_PROP_BUF_SIZE, 0, DBTYPE_STR, 0, 0}, // prop16
{ 4, COERCE_PROP_BUF_SIZE * 4, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, 4, 0, DBTYPE_STR, 0, 0}, // prop17 // give smaller size to test if truncation works
{ 5, COERCE_PROP_BUF_SIZE * 5, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, COERCE_PROP_BUF_SIZE, 0, DBTYPE_STR, 0, 0}, //prop18
{ 6, COERCE_PROP_BUF_SIZE * 6, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, COERCE_PROP_BUF_SIZE, 0, DBTYPE_STR, 0, 0}, // prop19
{ 7, COERCE_PROP_BUF_SIZE * 7, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, COERCE_PROP_BUF_SIZE, 0, DBTYPE_STR, 0, 0}, // prop7
{ 8, COERCE_PROP_BUF_SIZE * 8, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, sizeof( double ), 0, DBTYPE_R8, 0, 0} // prop20
};
const ULONG cPropTestCoerceCols = sizeof aPropTestCoerceCols / sizeof aPropTestCoerceCols[0];
void RunPropQueryAndCoerce( ICommand * pQuery, CDbRestriction & PropRst, unsigned cExpectedHits, unsigned numTest ) {
CoercePropStruct CoerceResultTestData;
// set up the expected result data
memset( &CoerceResultTestData, 0, sizeof CoercePropStruct ); strcpy( CoerceResultTestData.szProp13, PROP13_STR_VAL ); strcpy( CoerceResultTestData.szProp14, PROP14_STR_VAL ); strcpy( CoerceResultTestData.szProp15, PROP15_STR_VAL ); strcpy( CoerceResultTestData.szProp16, PROP16_STR_VAL ); strcpy( CoerceResultTestData.szProp17, PROP17_STR_VAL ); strcpy( CoerceResultTestData.szProp18, PROP18_STR_VAL ); strcpy( CoerceResultTestData.szProp19, PROP19_STR_VAL ); strcpy( CoerceResultTestData.szProp7, PROP7_STR_VAL ); CoerceResultTestData.szProp20 = PROP20_DBL_VAL;
CDbColumns cols(cPropTestCoerceCols); cols.Add( psTestProperty13, 0 ); cols.Add( psTestProperty14, 1 ); cols.Add( psTestProperty15, 2 ); cols.Add( psTestProperty16, 3 ); cols.Add( psTestProperty17, 4 ); cols.Add( psTestProperty18, 5 ); cols.Add( psTestProperty19, 6 ); cols.Add( psGuidTest, 7 ); cols.Add( psTestProperty20, 8 );
//
// Do it!
//
CDbCmdTreeNode * pDbCmdTree = FormQueryTree( &PropRst, cols, 0);
ICommandTree * pCmdTree = 0;
IRowsetScroll * pRowset = InstantiateRowset( pQuery, QUERY_SHALLOW, // Depth
0, pDbCmdTree, // DBCOMMANDTREE
IID_IRowset, // IID for i/f to return
0, &pCmdTree );
//
// Verify columns
//
CheckColumns( pRowset, cols, TRUE );
if ( !WaitForCompletion( pRowset, TRUE ) ) { pCmdTree->Release(); pRowset->Release(); LogFail( "property query unsuccessful.\n" ); }
//
// Get data
//
DBCOUNTITEM cRowsReturned = 0; HROW* pgrhRows = 0;
SCODE sc = pRowset->GetNextRows(0, 0, 10, &cRowsReturned, &pgrhRows);
if ( FAILED( sc ) ) { pCmdTree->Release(); pRowset->Release(); LogFail( "RunPropQueryAndCoerce IRowset->GetNextRows A returned 0x%x\n", sc ); }
if ( 0 == cExpectedHits ) { pCmdTree->Release(); pRowset->Release();
if ( cRowsReturned > 0 ) LogFail("RunPropQueryAndCoerce, %d returned rows, expected none\n", cRowsReturned); else return;
}
if (sc != DB_S_ENDOFROWSET && cRowsReturned != 10) { LogError( "RunPropQueryAndCoerce IRowset->GetNextRows C returned %d of %d rows," " status (%x) != DB_S_ENDOFROWSET\n", cRowsReturned, 10, sc); pCmdTree->Release(); pRowset->Release(); #if defined(UNIT_TEST)
cFailures++; return; #else
Fail(); #endif
}
//
// Expect 1 or 2 hits
//
if (sc != DB_S_ENDOFROWSET || cRowsReturned != cExpectedHits) { LogError( "RunPropQueryAndCoerce IRowset->GetNextRows D returned %d rows (expected %d)," " status (%x)\n", cRowsReturned, cExpectedHits, sc ); pCmdTree->Release(); pRowset->Release(); #if defined(UNIT_TEST)
cFailures++; return; #else
Fail(); #endif
}
//
// Patch the column index numbers with true column ids
//
DBID aDbCols[cPropTestCoerceCols];
aDbCols[0] = psTestProperty13; aDbCols[1] = psTestProperty14; aDbCols[2] = psTestProperty15; aDbCols[3] = psTestProperty16; aDbCols[4] = psTestProperty17; aDbCols[5] = psTestProperty18; aDbCols[6] = psTestProperty19; aDbCols[7] = psGuidTest; aDbCols[8] = psTestProperty20;
IUnknown * pAccessor = (IUnknown *) pRowset; // hAccessor must be created on rowset
// to be used with rowset->GetData below
HACCESSOR hAccessor = MapColumns(pAccessor, cPropTestCoerceCols, aPropTestCoerceCols, aDbCols);
//
// Fetch the data
//
//PROPVARIANT aVarnt[cPropTestCols];
CoercePropStruct rowData;
memset( &rowData, 0, sizeof CoercePropStruct );
for (unsigned row = 0; row < cRowsReturned; row++) { sc = pRowset->GetData(pgrhRows[row], hAccessor, &rowData);
if (S_OK != sc) { LogError("RunPropQueryAndCoerce IRowset->GetData returned 0x%x (expected 0)\n",sc); pCmdTree->Release(); pRowset->Release(); Fail(); }
// verify
if ( memcmp( &rowData, &CoerceResultTestData, sizeof CoercePropStruct ) ) { LogFail( "RunPropQueryAndCoerce failed." ); }
} sc = pRowset->ReleaseRows( cRowsReturned, pgrhRows, 0, 0, 0);
if (S_OK != sc) { LogError("IRowset->ReleaseRows returned 0x%x (expected 0)\n",sc); pCmdTree->Release(); pRowset->Release(); Fail(); }
CoTaskMemFree(pgrhRows); pgrhRows = 0;
//
// Clean up.
//
ReleaseAccessor( pAccessor, hAccessor);
pCmdTree->Release(); pRowset->Release(); } //RunPropQueryAndCoerce
//+-------------------------------------------------------------------------
//
// Function: RunDistribQueryTest, public
//
// Synopsis: Minimal test for the distributed rowset
//
// History: 07 Oct 98 vikasman created
//
// Notes: This is a pretty minimal test; should try sorted and
// scrollable (all combinations), larger result sets
//
//--------------------------------------------------------------------------
void RunDistribQueryTest( BOOL fDoContentTest ) { LogProgress( "Distributed Query Test\n" );
IUnknown * pIUnknown; ICommand * pQuery = 0;
SCODE scIC = CICreateCommand( &pIUnknown, 0, IID_IUnknown, TEST_CATALOG, TEST_MACHINE ); if ( FAILED( scIC ) ) LogFail( "RunDistribQueryTest - error 0x%x Unable to create ICommand\n", scIC );
scIC = pIUnknown->QueryInterface(IID_ICommand, (void **) &pQuery ); pIUnknown->Release();
if ( FAILED( scIC ) ) LogFail( "RunDistribQueryTest - error 0x%x Unable to QI ICommand\n", scIC );
if ( 0 == pQuery ) LogFail( "RunDistribQueryTest - CICreateCommand succeeded, but returned null pQuery\n" );
WCHAR * awcMachines[2]; WCHAR * awcCatalogs[2]; WCHAR * awcScopes[2]; WCHAR aComputerName[MAX_COMPUTERNAME_LENGTH + 1]; DWORD aDepths[2]; ULONG cComputerName = MAX_COMPUTERNAME_LENGTH + 1;
GetComputerName( aComputerName, &cComputerName );
awcMachines[0] = TEST_MACHINE; awcCatalogs[0] = TEST_CATALOG; awcScopes[0] = wcsTestPath; aDepths[0] = QUERY_SHALLOW;
awcMachines[1] = aComputerName; awcCatalogs[1] = TEST_CATALOG; awcScopes[1] = wcsTestPath; aDepths[1] = QUERY_SHALLOW;
scIC = SetScopeProperties( pQuery, 2, awcScopes, aDepths, awcCatalogs, awcMachines );
if ( FAILED( scIC ) ) LogFail( "RunDistribQueryTest - error 0x%x Unable to set scope '%ws'\n", scIC, wcsTestPath );
CheckPropertiesOnCommand( pQuery );
unsigned numTest = 1;
// singleton DBOP_equal singleton - Coersion test
{ LogProgress( " DistributedRowset - Property coercion to String test\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psTestProperty1 ); PropRst.SetRelation( DBOP_equal ); PropRst.SetValue( PROP1_VAL ); RunPropQueryAndCoerce( pQuery, PropRst, 2, numTest++ ); }
pQuery->Release(); }
//+-------------------------------------------------------------------------
//
// Function: RunPropTest, public
//
// Synopsis: Very minimal test of property query
//
// History: 13-May-93 KyleP Created
// 15 Oct 94 Alanw Converted to OLE-DB query
//
//--------------------------------------------------------------------------
void RunPropTest( void ) { LogProgress( "Property Retrieval Test\n" );
PROPVARIANT pvProp5; pvProp5.vt = VT_I4|VT_VECTOR; pvProp5.cal.cElems = clProp5; pvProp5.cal.pElems = (LONG *) alProp5;
PROPVARIANT pvProp5Jumble; pvProp5Jumble.vt = VT_I4|VT_VECTOR; pvProp5Jumble.cal.cElems = clProp5Jumble; pvProp5Jumble.cal.pElems = (LONG *) alProp5Jumble;
PROPVARIANT pvProp5Like; pvProp5Like.vt = VT_I4|VT_VECTOR; pvProp5Like.cal.cElems = clProp5Like; pvProp5Like.cal.pElems = (LONG *) alProp5Like;
PROPVARIANT pvProp5None; pvProp5None.vt = VT_I4|VT_VECTOR; pvProp5None.cal.cElems = clProp5None; pvProp5None.cal.pElems = (LONG *) alProp5None;
PROPVARIANT pvProp5Less; pvProp5Less.vt = VT_I4|VT_VECTOR; pvProp5Less.cal.cElems = clProp5Less; pvProp5Less.cal.pElems = (LONG *) alProp5Less;
PROPVARIANT pvProp5AllLess; pvProp5AllLess.vt = VT_I4|VT_VECTOR; pvProp5AllLess.cal.cElems = clProp5AllLess; pvProp5AllLess.cal.pElems = (LONG *) alProp5AllLess;
PROPVARIANT pvProp5More; pvProp5More.vt = VT_I4|VT_VECTOR; pvProp5More.cal.cElems = clProp5More; pvProp5More.cal.pElems = (LONG *) alProp5More;
PROPVARIANT pvProp5AllMore; SAFEARRAY saProp5AllMore = { 1, // Dimension
FADF_AUTO, // Flags: on stack
sizeof(LONG), // Size of an element
1, // Lock count. 1 for safety.
(void *)alProp5AllMore, // The data
{ clProp5AllMore, 0 } };// Bounds (element count, low bound)
pvProp5AllMore.vt = VT_I4|VT_ARRAY; pvProp5AllMore.parray = &saProp5AllMore;
WCHAR *pwszScope = wcsTestPath;
DWORD dwDepth = QUERY_SHALLOW; IUnknown * pIUnknown; ICommand * pQuery = 0; SCODE scIC = CICreateCommand( &pIUnknown, 0, IID_IUnknown, TEST_CATALOG, TEST_MACHINE ); if ( FAILED( scIC ) ) LogFail( "RunPropTest - error 0x%x Unable to create ICommand\n", scIC );
scIC = pIUnknown->QueryInterface(IID_ICommand, (void **) &pQuery ); pIUnknown->Release();
if ( FAILED( scIC ) ) LogFail( "RunPropTest - error 0x%x Unable to QI ICommand\n", scIC );
if ( 0 == pQuery ) LogFail( "RunPropTest - CICreateCommand succeeded, but returned null pQuery\n" );
scIC = SetScopeProperties( pQuery, 1, &pwszScope, &dwDepth );
if ( FAILED( scIC ) ) LogFail( "RunPropTest - error 0x%x Unable to set scope '%ws'\n", scIC, pwszScope );
CheckPropertiesOnCommand( pQuery );
unsigned numTest = 1;
// singleton DBOP_equal singleton - Coersion test
{ LogProgress( " Property coercion to String test 0\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psTestProperty1 ); PropRst.SetRelation( DBOP_equal ); PropRst.SetValue( PROP1_VAL ); RunPropQueryAndCoerce( pQuery, PropRst, 1, numTest++ ); }
// singleton DBOP_equal singleton
{ LogProgress( " Property Retrieval test 0\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psTestProperty1 ); PropRst.SetRelation( DBOP_equal ); PropRst.SetValue( PROP1_VAL ); RunPropQuery( pQuery, PropRst, 1, numTest++ ); }
// vector DBOP_equal vector
{ LogProgress( " Property Retrieval test 1\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psRelevantWords ); PropRst.SetRelation( DBOP_equal ); PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5)) ); RunPropQueryAndCoerce( pQuery, PropRst, 2, numTest ); RunPropQuery( pQuery, PropRst, 2, numTest++ ); }
// vector DBOP_equal_all vector (FAIL getting any hits back)
{ LogProgress( " Property Retrieval test 2\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psRelevantWords ); PropRst.SetRelation( DBOP_equal_all ); PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5)) ); RunPropQuery( pQuery, PropRst, 0, numTest++ ); }
// singleton DBOP_equal_any singleton
{ LogProgress( " Property Retrieval test 3\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psTestProperty1 ); PropRst.SetRelation( DBOP_equal_any ); PropRst.SetValue( PROP1_VAL ); RunPropQuery( pQuery, PropRst, 1, numTest++ ); }
// singleton DBOP_equal vector (FAIL getting any hits back)
{ LogProgress( " Property Retrieval test 4\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psRelevantWords ); PropRst.SetRelation( DBOP_equal ); PropRst.SetValue( SecondRelevantWord ); RunPropQuery( pQuery, PropRst, 0, numTest++ ); }
// singleton DBOP_equal_any vector (FAIL -- singleton not in vector)
{ LogProgress( " Property Retrieval test 5\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psRelevantWords ); PropRst.SetRelation( DBOP_equal_any ); PropRst.SetValue( (LONG) 666 ); RunPropQuery( pQuery, PropRst, 0, numTest++ ); }
// singleton DBOP_equal_any vector
{ LogProgress( " Property Retrieval test 6\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psRelevantWords ); PropRst.SetRelation( DBOP_equal_any ); PropRst.SetValue( SecondRelevantWord ); RunPropQuery( pQuery, PropRst, 2, numTest++ ); }
// reordered vector DBOP_equal_any vector
{ LogProgress( " Property Retrieval test 7\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psRelevantWords ); PropRst.SetRelation( DBOP_equal_any ); PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5Jumble)) ); RunPropQuery( pQuery, PropRst, 2 , numTest++ ); }
// vector with one element match DBOP_equal_any vector
{ LogProgress( " Property Retrieval test 8\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psRelevantWords ); PropRst.SetRelation( DBOP_equal_any ); PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5Like)) ); RunPropQuery( pQuery, PropRst, 2, numTest++ ); }
// vector with 0 element overlap DBOP_equal_any vector (FAIL getting any hits back)
{ LogProgress( " Property Retrieval test 9\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psRelevantWords ); PropRst.SetRelation( DBOP_equal_any ); PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5None)) ); RunPropQuery( pQuery, PropRst, 0, numTest++ ); }
// reordered vector DBOP_equal_any vector
{ LogProgress( " Property Retrieval test 10\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psRelevantWords ); PropRst.SetRelation( DBOP_equal_any ); PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5Jumble)) ); RunPropQuery( pQuery, PropRst, 2, numTest++ ); }
// vector with one element match DBOP_equal_all vector (FAIL getting hits back)
{ LogProgress( " Property Retrieval test 11\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psRelevantWords ); PropRst.SetRelation( DBOP_equal_all ); PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5Like)) ); RunPropQuery( pQuery, PropRst, 0, numTest++ ); }
// less vector DBOP_less vector (FAIL getting hits back)
{ LogProgress( " Property Retrieval test 12\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psRelevantWords ); PropRst.SetRelation( DBOP_less ); PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5Less)) ); RunPropQuery( pQuery, PropRst, 0, numTest++ ); }
// less vector DBOP_greater vector
{ LogProgress( " Property Retrieval test 13\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psRelevantWords ); PropRst.SetRelation( DBOP_greater ); PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5Less)) ); RunPropQuery( pQuery, PropRst, 2, numTest++ ); }
// more vector DBOP_greater_equal vector (FAIL getting hits back)
{ LogProgress( " Property Retrieval test 14\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psRelevantWords ); PropRst.SetRelation( DBOP_greater_equal ); PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5More)) ); RunPropQuery( pQuery, PropRst, 0, numTest++ ); }
// more vector DBOP_less_equal vector
{ LogProgress( " Property Retrieval test 15\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psRelevantWords ); PropRst.SetRelation( DBOP_less_equal ); PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5More)) ); RunPropQuery( pQuery, PropRst, 2, numTest++ ); }
// less vector DBOP_less_all vector (FAIL getting hits back)
{ LogProgress( " Property Retrieval test 16\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psRelevantWords ); PropRst.SetRelation( DBOP_less_all ); PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5AllLess)) ); RunPropQuery( pQuery, PropRst, 0, numTest++ ); }
// less vector DBOP_greater_all vector
{ LogProgress( " Property Retrieval test 17\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psRelevantWords ); PropRst.SetRelation( DBOP_greater_all ); PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5AllLess)) ); RunPropQuery( pQuery, PropRst, 2, numTest++ ); }
// more vector DBOP_greater_equal_all vector (FAIL getting hits back)
{ LogProgress( " Property Retrieval test 18\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psRelevantWords ); PropRst.SetRelation( DBOP_greater_equal_all ); PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5AllMore)) ); RunPropQuery( pQuery, PropRst, 0, numTest++ ); }
// more vector DBOP_less_equal_all vector
{ LogProgress( " Property Retrieval test 19\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psRelevantWords ); PropRst.SetRelation( DBOP_less_equal_all ); PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5AllMore)) ); RunPropQuery( pQuery, PropRst, 2, numTest++ ); }
// less vector DBOP_less_any vector (FAIL getting hits back)
{ LogProgress( " Property Retrieval test 20\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psRelevantWords ); PropRst.SetRelation( DBOP_less_any ); PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5AllLess)) ); RunPropQuery( pQuery, PropRst, 0, numTest++ ); }
// less vector DBOP_greater_any vector
{ LogProgress( " Property Retrieval test 21\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psRelevantWords ); PropRst.SetRelation( DBOP_greater_any ); PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5AllLess)) ); RunPropQuery( pQuery, PropRst, 2, numTest++ ); }
// more vector DBOP_greater_equal_any vector (FAIL getting hits back)
{ LogProgress( " Property Retrieval test 22\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psRelevantWords ); PropRst.SetRelation( DBOP_greater_equal_any ); PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5AllMore)) ); RunPropQuery( pQuery, PropRst, 0, numTest++ ); }
// more vector DBOP_less_equal_any vector
{ LogProgress( " Property Retrieval test 23\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psRelevantWords ); PropRst.SetRelation( DBOP_less_equal_any ); PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5AllMore)) ); RunPropQuery( pQuery, PropRst, 2, numTest++ ); }
// singleton wstr DBOP_equal_any string vector
{ LogProgress( " Property Retrieval test 24\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psKeywords ); PropRst.SetRelation( DBOP_equal_any ); PropRst.SetValue( L"is" ); RunPropQuery( pQuery, PropRst, 2, numTest++ ); }
// bogus singleton wstr DBOP_equal_any string vector (FAIL getting hits back)
{ LogProgress( " Property Retrieval test 25\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psKeywords ); PropRst.SetRelation( DBOP_equal_any ); PropRst.SetValue( L"666" ); RunPropQuery( pQuery, PropRst, 0, numTest++ ); }
// bogus singleton DBOP_equal_any singleton
{ LogProgress( " Property Retrieval test 26\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psTestProperty1 ); PropRst.SetRelation( DBOP_equal_any ); PropRst.SetValue( PROP1_VAL + 100 ); RunPropQuery( pQuery, PropRst, 0, numTest++ ); }
// singleton DBOP_equal singleton (empty string)
{ LogProgress( " Property Retrieval test 27\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psTestProperty10 ); PropRst.SetRelation( DBOP_equal ); PropRst.SetValue( PROP10_VAL ); RunPropQuery( pQuery, PropRst, 2, numTest++ ); }
// singleton DBOP_equal singleton (BSTR string)
{ LogProgress( " Property Retrieval test 28\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psTestProperty11 ); PropRst.SetRelation( DBOP_equal ); PropRst.SetValue( varProp11 ); RunPropQuery( pQuery, PropRst, 1, numTest++ ); }
// less vector DBOP_less_all large vector (FAIL getting hits back)
{ LogProgress( " Property Retrieval test 29\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psManyRW ); PropRst.SetRelation( DBOP_less_all ); PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5AllLess)) ); RunPropQuery( pQuery, PropRst, 0, numTest++ ); }
// less vector DBOP_greater_all large vector (FAIL getting hits back)
{ LogProgress( " Property Retrieval test 30\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psManyRW ); PropRst.SetRelation( DBOP_greater_all ); PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5AllLess)) ); RunPropQuery( pQuery, PropRst, 0, numTest++ ); }
// more vector DBOP_less_all large vector
{ LogProgress( " Property Retrieval test 31\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psManyRW ); PropRst.SetRelation( DBOP_less_all ); PropRst.SetValue( * ((CStorageVariant *) (void *) (&pvProp5AllMore)) ); RunPropQuery( pQuery, PropRst, 2, numTest++ ); }
// singleton DBOP_less_equal_all large vector
{ LogProgress( " Property Retrieval test 32\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( psManyRW ); PropRst.SetRelation( DBOP_less_equal_all ); PropRst.SetValue( (LONG) (clProp8-1) ); RunPropQuery( pQuery, PropRst, 2, numTest++ ); }
pQuery->Release();
} //RunPropTest
struct SSafeArrayTestColsTight { SAFEARRAY * a_I4; SAFEARRAY * a_BSTR; SAFEARRAY * a_VARIANT; SAFEARRAY * a_R8; SAFEARRAY * a_DATE; SAFEARRAY * a_BOOL; SAFEARRAY * a_DECIMAL; SAFEARRAY * a_I1; SAFEARRAY * a_R4; SAFEARRAY * a_CY; SAFEARRAY * a_UINT; SAFEARRAY * a_INT; SAFEARRAY * a_ERROR;
DBLENGTH I4_cb; DBLENGTH BSTR_cb; DBLENGTH VARIANT_cb; DBLENGTH R8_cb; DBLENGTH DATE_cb; DBLENGTH BOOL_cb; DBLENGTH DECIMAL_cb; DBLENGTH I1_cb; DBLENGTH R4_cb; DBLENGTH CY_cb; DBLENGTH UINT_cb; DBLENGTH INT_cb; DBLENGTH ERROR_cb;
ULONG I4_status; ULONG BSTR_status; ULONG VARIANT_status; ULONG R8_status; ULONG DATE_status; ULONG BOOL_status; ULONG DECIMAL_status; ULONG I1_status; ULONG R4_status; ULONG CY_status; ULONG UINT_status; ULONG INT_status; ULONG ERROR_status; };
static DBBINDING aSafeArrayTestColsTight[] = { { 0, offsetof(SSafeArrayTestColsTight,a_I4), offsetof(SSafeArrayTestColsTight,I4_cb), offsetof(SSafeArrayTestColsTight,I4_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof (SAFEARRAY *), 0, DBTYPE_ARRAY|DBTYPE_I4, 0, 0 }, { 1, offsetof(SSafeArrayTestColsTight,a_BSTR), offsetof(SSafeArrayTestColsTight,BSTR_cb), offsetof(SSafeArrayTestColsTight,BSTR_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof (SAFEARRAY *), 0, DBTYPE_ARRAY|DBTYPE_BSTR, 0, 0 }, { 2, offsetof(SSafeArrayTestColsTight,a_VARIANT), offsetof(SSafeArrayTestColsTight,VARIANT_cb), offsetof(SSafeArrayTestColsTight,VARIANT_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof (SAFEARRAY *), 0, DBTYPE_ARRAY|DBTYPE_VARIANT, 0, 0 }, { 3, offsetof(SSafeArrayTestColsTight,a_R8), offsetof(SSafeArrayTestColsTight,R8_cb), offsetof(SSafeArrayTestColsTight,R8_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof (SAFEARRAY *), 0, DBTYPE_ARRAY|DBTYPE_R8, 0, 0 }, { 4, offsetof(SSafeArrayTestColsTight,a_DATE), offsetof(SSafeArrayTestColsTight,DATE_cb), offsetof(SSafeArrayTestColsTight,DATE_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof (SAFEARRAY *), 0, DBTYPE_ARRAY|DBTYPE_DATE, 0, 0 }, { 5, offsetof(SSafeArrayTestColsTight,a_BOOL), offsetof(SSafeArrayTestColsTight,BOOL_cb), offsetof(SSafeArrayTestColsTight,BOOL_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof (SAFEARRAY *), 0, DBTYPE_ARRAY|DBTYPE_BOOL, 0, 0 }, { 6, offsetof(SSafeArrayTestColsTight,a_DECIMAL), offsetof(SSafeArrayTestColsTight,DECIMAL_cb), offsetof(SSafeArrayTestColsTight,DECIMAL_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof (SAFEARRAY *), 0, DBTYPE_ARRAY|DBTYPE_DECIMAL, 0, 0 }, { 7, offsetof(SSafeArrayTestColsTight,a_I1), offsetof(SSafeArrayTestColsTight,I1_cb), offsetof(SSafeArrayTestColsTight,I1_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof (SAFEARRAY *), 0, DBTYPE_ARRAY|DBTYPE_I1, 0, 0 }, { 8, offsetof(SSafeArrayTestColsTight,a_R4), offsetof(SSafeArrayTestColsTight,R4_cb), offsetof(SSafeArrayTestColsTight,R4_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof (SAFEARRAY *), 0, DBTYPE_ARRAY|DBTYPE_R4, 0, 0 }, { 9, offsetof(SSafeArrayTestColsTight,a_CY), offsetof(SSafeArrayTestColsTight,CY_cb), offsetof(SSafeArrayTestColsTight,CY_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof (SAFEARRAY *), 0, DBTYPE_ARRAY|DBTYPE_CY, 0, 0 }, { 10, offsetof(SSafeArrayTestColsTight,a_UINT), offsetof(SSafeArrayTestColsTight,UINT_cb), offsetof(SSafeArrayTestColsTight,UINT_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof (SAFEARRAY *), 0, DBTYPE_ARRAY|VT_UINT, 0, 0 }, { 11, offsetof(SSafeArrayTestColsTight,a_INT), offsetof(SSafeArrayTestColsTight,INT_cb), offsetof(SSafeArrayTestColsTight,INT_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof (SAFEARRAY *), 0, DBTYPE_ARRAY|VT_INT, 0, 0 }, { 12, offsetof(SSafeArrayTestColsTight,a_ERROR), offsetof(SSafeArrayTestColsTight,ERROR_cb), offsetof(SSafeArrayTestColsTight,ERROR_status), 0,0,0, ALLPARTS, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, sizeof (SAFEARRAY *), 0, DBTYPE_ARRAY|DBTYPE_ERROR, 0, 0 }, };
const ULONG cSafeArrayTestColsTight = sizeof aSafeArrayTestColsTight / sizeof aSafeArrayTestColsTight[0];
void RunSafeArrayTightBindings( ICommand * pQuery, CDbRestriction & PropRst, unsigned cExpectedHits, unsigned numTest ) { //
// Get 13 properties back
//
CDbColumns cols(cSafeArrayTestColsTight); cols.Add( colSA_I4, 0 ); cols.Add( colSA_BSTR, 1 ); cols.Add( colSA_VARIANT, 2 ); cols.Add( colSA_R8, 3 ); cols.Add( colSA_DATE, 4 ); cols.Add( colSA_BOOL, 5 ); cols.Add( colSA_DECIMAL, 6 ); cols.Add( colSA_I1, 7 ); cols.Add( colSA_R4, 8 ); cols.Add( colSA_CY, 9 ); cols.Add( colSA_UINT, 10 ); cols.Add( colSA_INT, 11 ); cols.Add( colSA_ERROR, 12 );
BOOL fSeq = isEven( numTest );
CDbSortSet ss( 1 ); ss.Add( colSA_VARIANT, 0 );
//
// Do it!
//
CDbCmdTreeNode * pDbCmdTree = FormQueryTree( &PropRst, cols, fSeq ? 0 : &ss );
ICommandTree * pCmdTree = 0;
IRowsetScroll * pRowset = InstantiateRowset( pQuery, QUERY_SHALLOW, // Depth
0, pDbCmdTree, // DBCOMMANDTREE
fSeq ? IID_IRowset : IID_IRowsetScroll, // IID for i/f to return
0, &pCmdTree );
//
// Verify columns
//
CheckColumns( pRowset, cols, TRUE );
if ( !WaitForCompletion( pRowset, TRUE ) ) { pCmdTree->Release(); pRowset->Release(); LogFail( "property query unsuccessful.\n" ); }
//
// Get data
//
DBCOUNTITEM cRowsReturned = 0; HROW* pgrhRows = 0;
SCODE sc = pRowset->GetNextRows(0, 0, 10, &cRowsReturned, &pgrhRows);
if ( FAILED( sc ) ) { pCmdTree->Release(); pRowset->Release(); LogFail( "IRowset->GetRowsAt G returned 0x%x\n", sc ); }
if ( 0 == cExpectedHits ) { pCmdTree->Release(); pRowset->Release();
if ( cRowsReturned > 0 ) LogFail("RunPropQuery, %d returned rows, expected none\n", cRowsReturned); else return;
}
if (sc != DB_S_ENDOFROWSET && cRowsReturned != 10) { LogError( "IRowset->GetRowsAt H returned %d of %d rows," " status (%x) != DB_S_ENDOFROWSET\n", cRowsReturned, 10, sc); pCmdTree->Release(); pRowset->Release(); #if defined(UNIT_TEST)
cFailures++; return; #else
Fail(); #endif
}
//
// Expect 1 or 2 hits
//
if (sc != DB_S_ENDOFROWSET || cRowsReturned != cExpectedHits) { LogError( "IRowset->GetRowsAt I returned %d rows (expected %d)," " status (%x)\n", cRowsReturned, cExpectedHits, sc ); pCmdTree->Release(); pRowset->Release(); #if defined(UNIT_TEST)
cFailures++; return; #else
Fail(); #endif
}
//
// Patch the column index numbers with true column ids
//
DBID aDbCols[cSafeArrayTestColsTight]; aDbCols[0] = colSA_I4; aDbCols[1] = colSA_BSTR; aDbCols[2] = colSA_VARIANT; aDbCols[3] = colSA_R8; aDbCols[4] = colSA_DATE; aDbCols[5] = colSA_BOOL; aDbCols[6] = colSA_DECIMAL; aDbCols[7] = colSA_I1; aDbCols[8] = colSA_R4; aDbCols[9] = colSA_CY; aDbCols[10] = colSA_UINT; aDbCols[11] = colSA_INT; aDbCols[12] = colSA_ERROR;
IUnknown * pAccessor = (IUnknown *) pRowset; // hAccessor must be created on rowset
// to be used with rowset->GetData below
HACCESSOR hAccessor = MapColumns( pAccessor, cSafeArrayTestColsTight, aSafeArrayTestColsTight, aDbCols, TRUE );
//
// Fetch the data
//
SSafeArrayTestColsTight saData;
for (unsigned row = 0; row < cRowsReturned; row++) { sc = pRowset->GetData(pgrhRows[row], hAccessor, &saData );
if (S_OK != sc) { LogError("IRowset->GetData returned 0x%x (expected 0)\n",sc); pCmdTree->Release(); pRowset->Release(); Fail(); }
//
// Verify the data.
//
PROPVARIANT var;
var.vt = VT_ARRAY | VT_I4; var.parray = saData.a_I4; CheckPropertyValue( var, vaI4 );
var.vt = VT_ARRAY | VT_BSTR; var.parray = saData.a_BSTR; CheckPropertyValue( var, vaBSTR );
var.vt = VT_ARRAY | VT_VARIANT; var.parray = saData.a_VARIANT; CheckPropertyValue( var, vaVARIANT );
var.vt = VT_ARRAY | VT_R8; var.parray = saData.a_R8; CheckPropertyValue( var, vaR8 );
var.vt = VT_ARRAY | VT_DATE; var.parray = saData.a_DATE; CheckPropertyValue( var, vaDATE );
var.vt = VT_ARRAY | VT_BOOL; var.parray = saData.a_BOOL; CheckPropertyValue( var, vaBOOL );
var.vt = VT_ARRAY | VT_DECIMAL; var.parray = saData.a_DECIMAL; CheckPropertyValue( var, vaDECIMAL );
var.vt = VT_ARRAY | VT_I1; var.parray = saData.a_I1; CheckPropertyValue( var, vaI1 );
var.vt = VT_ARRAY | VT_R4; var.parray = saData.a_R4; CheckPropertyValue( var, vaR4 );
var.vt = VT_ARRAY | VT_CY; var.parray = saData.a_CY; CheckPropertyValue( var, vaCY );
var.vt = VT_ARRAY | VT_UINT; var.parray = saData.a_UINT; CheckPropertyValue( var, vaUINT );
var.vt = VT_ARRAY | VT_INT; var.parray = saData.a_INT; CheckPropertyValue( var, vaINT );
var.vt = VT_ARRAY | VT_ERROR; var.parray = saData.a_ERROR; CheckPropertyValue( var, vaERROR ); }
sc = pRowset->ReleaseRows( cRowsReturned, pgrhRows, 0, 0, 0);
if (S_OK != sc) { LogError("IRowset->ReleaseRows returned 0x%x (expected 0)\n",sc); pCmdTree->Release(); pRowset->Release(); Fail(); }
CoTaskMemFree(pgrhRows); pgrhRows = 0;
//
// Clean up.
//
ReleaseAccessor( pAccessor, hAccessor);
pCmdTree->Release(); pRowset->Release(); } //RunSafeArrayTightBindings
static DBBINDING aSafeArrayTestByRefCols[] = { { 0, 0 * cbPPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, { 1, 1 * cbPPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, { 2, 2 * cbPPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, { 3, 3 * cbPPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, { 4, 4 * cbPPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, { 5, 5 * cbPPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, { 6, 6 * cbPPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, { 7, 7 * cbPPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, { 8, 8 * cbPPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, { 9, 9 * cbPPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, { 10,10* cbPPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, { 11,11* cbPPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, { 12,12* cbPPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, cbPPV, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0}, };
const ULONG cSafeArrayTestByRefCols = sizeof aSafeArrayTestByRefCols / sizeof aSafeArrayTestByRefCols[0];
void RunSafeArrayByRefBindings( ICommand * pQuery, CDbRestriction & PropRst, unsigned cExpectedHits, unsigned numTest ) { //
// Get 13 properties back
//
CDbColumns cols(cSafeArrayTestByRefCols); cols.Add( colSA_I4, 0 ); cols.Add( colSA_BSTR, 1 ); cols.Add( colSA_VARIANT, 2 ); cols.Add( colSA_R8, 3 ); cols.Add( colSA_DATE, 4 ); cols.Add( colSA_BOOL, 5 ); cols.Add( colSA_DECIMAL, 6 ); cols.Add( colSA_I1, 7 ); cols.Add( colSA_R4, 8 ); cols.Add( colSA_CY, 9 ); cols.Add( colSA_UINT, 10 ); cols.Add( colSA_INT, 11 ); cols.Add( colSA_ERROR, 12 );
BOOL fSeq = isEven( numTest );
CDbSortSet ss( 1 ); ss.Add( colSA_CY, 0 );
//
// Do it!
//
CDbCmdTreeNode * pDbCmdTree = FormQueryTree( &PropRst, cols, fSeq ? 0 : &ss );
ICommandTree * pCmdTree = 0;
IRowsetScroll * pRowset = InstantiateRowset( pQuery, QUERY_SHALLOW, // Depth
0, pDbCmdTree, // DBCOMMANDTREE
fSeq ? IID_IRowset : IID_IRowsetScroll, // IID for i/f to return
0, &pCmdTree );
//
// Verify columns
//
CheckColumns( pRowset, cols, TRUE );
if ( !WaitForCompletion( pRowset, TRUE ) ) { pCmdTree->Release(); pRowset->Release(); LogFail( "property query unsuccessful.\n" ); }
//
// Get data
//
DBCOUNTITEM cRowsReturned = 0; HROW* pgrhRows = 0;
SCODE sc = pRowset->GetNextRows(0, 0, 10, &cRowsReturned, &pgrhRows);
if ( FAILED( sc ) ) { pCmdTree->Release(); pRowset->Release(); LogFail( "IRowset->GetRowsAt G returned 0x%x\n", sc ); }
if ( 0 == cExpectedHits ) { pCmdTree->Release(); pRowset->Release();
if ( cRowsReturned > 0 ) LogFail("RunPropQuery, %d returned rows, expected none\n", cRowsReturned); else return;
}
if (sc != DB_S_ENDOFROWSET && cRowsReturned != 10) { LogError( "IRowset->GetRowsAt H returned %d of %d rows," " status (%x) != DB_S_ENDOFROWSET\n", cRowsReturned, 10, sc); pCmdTree->Release(); pRowset->Release(); #if defined(UNIT_TEST)
cFailures++; return; #else
Fail(); #endif
}
//
// Expect 1 or 2 hits
//
if (sc != DB_S_ENDOFROWSET || cRowsReturned != cExpectedHits) { LogError( "IRowset->GetRowsAt I returned %d rows (expected %d)," " status (%x)\n", cRowsReturned, cExpectedHits, sc ); pCmdTree->Release(); pRowset->Release(); #if defined(UNIT_TEST)
cFailures++; return; #else
Fail(); #endif
}
//
// Patch the column index numbers with true column ids
//
DBID aDbCols[cSafeArrayTestByRefCols]; aDbCols[0] = colSA_I4; aDbCols[1] = colSA_BSTR; aDbCols[2] = colSA_VARIANT; aDbCols[3] = colSA_R8; aDbCols[4] = colSA_DATE; aDbCols[5] = colSA_BOOL; aDbCols[6] = colSA_DECIMAL; aDbCols[7] = colSA_I1; aDbCols[8] = colSA_R4; aDbCols[9] = colSA_CY; aDbCols[10] = colSA_UINT; aDbCols[11] = colSA_INT; aDbCols[12] = colSA_ERROR;
IUnknown * pAccessor = (IUnknown *) pRowset; // hAccessor must be created on rowset
// to be used with rowset->GetData below
HACCESSOR hAccessor = MapColumns( pAccessor, cSafeArrayTestByRefCols, aSafeArrayTestByRefCols, aDbCols, TRUE );
//
// Fetch the data
//
PROPVARIANT * aVarnt[cSafeArrayTestByRefCols];
for (unsigned row = 0; row < cRowsReturned; row++) { sc = pRowset->GetData(pgrhRows[row], hAccessor, aVarnt);
if (S_OK != sc) { LogError("IRowset->GetData returned 0x%x (expected 0)\n",sc); pCmdTree->Release(); pRowset->Release(); Fail(); }
//
// Verify the data.
//
CheckPropertyValue( *aVarnt[0], vaI4 ); CheckPropertyValue( *aVarnt[1], vaBSTR ); CheckPropertyValue( *aVarnt[2], vaVARIANT ); CheckPropertyValue( *aVarnt[3], vaR8 ); CheckPropertyValue( *aVarnt[4], vaDATE ); CheckPropertyValue( *aVarnt[5], vaBOOL ); CheckPropertyValue( *aVarnt[6], vaDECIMAL ); CheckPropertyValue( *aVarnt[7], vaI1 ); CheckPropertyValue( *aVarnt[8], vaR4 ); CheckPropertyValue( *aVarnt[9], vaCY ); CheckPropertyValue( *aVarnt[10], vaUINT ); CheckPropertyValue( *aVarnt[11], vaINT ); CheckPropertyValue( *aVarnt[12], vaERROR ); }
sc = pRowset->ReleaseRows( cRowsReturned, pgrhRows, 0, 0, 0);
if (S_OK != sc) { LogError("IRowset->ReleaseRows returned 0x%x (expected 0)\n",sc); pCmdTree->Release(); pRowset->Release(); Fail(); }
CoTaskMemFree(pgrhRows); pgrhRows = 0;
//
// Clean up.
//
ReleaseAccessor( pAccessor, hAccessor);
pCmdTree->Release(); pRowset->Release(); } //RunSafeArrayByRefBindings
static DBBINDING aSafeArrayTestCols[] = { { 0, 0 * cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, { 1, 1 * cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, { 2, 2 * cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, { 3, 3 * cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, { 4, 4 * cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, { 5, 5 * cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, { 6, 6 * cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, { 7, 7 * cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, { 8, 8 * cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, { 9, 9 * cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, { 10,10* cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, { 11,11* cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, { 12,12* cbPV, 0, 0, 0, 0, 0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbPV, 0, DBTYPE_VARIANT, 0, 0}, };
const ULONG cSafeArrayTestCols = sizeof aSafeArrayTestCols / sizeof aSafeArrayTestCols[0];
void RunSafeArrayQuery( ICommand * pQuery, CDbRestriction & PropRst, unsigned cExpectedHits, unsigned numTest ) { RunSafeArrayTightBindings( pQuery, PropRst, cExpectedHits, numTest ); RunSafeArrayByRefBindings( pQuery, PropRst, cExpectedHits, numTest );
//
// Get twelve properties back
//
CDbColumns cols(cSafeArrayTestCols); cols.Add( colSA_I4, 0 ); cols.Add( colSA_BSTR, 1 ); cols.Add( colSA_VARIANT, 2 ); cols.Add( colSA_R8, 3 ); cols.Add( colSA_DATE, 4 ); cols.Add( colSA_BOOL, 5 ); cols.Add( colSA_DECIMAL, 6 ); cols.Add( colSA_I1, 7 ); cols.Add( colSA_R4, 8 ); cols.Add( colSA_CY, 9 ); cols.Add( colSA_UINT, 10 ); cols.Add( colSA_INT, 11 ); cols.Add( colSA_ERROR, 12 );
BOOL fSeq = isEven( numTest );
CDbSortSet ss( 1 ); ss.Add( colSA_BSTR, 0 );
//
// Do it!
//
CDbCmdTreeNode * pDbCmdTree = FormQueryTree( &PropRst, cols, fSeq ? 0 : &ss );
ICommandTree * pCmdTree = 0;
IRowsetScroll * pRowset = InstantiateRowset( pQuery, QUERY_SHALLOW, // Depth
0, pDbCmdTree, // DBCOMMANDTREE
fSeq ? IID_IRowset : IID_IRowsetScroll, // IID for i/f to return
0, &pCmdTree );
//
// Verify columns
//
CheckColumns( pRowset, cols, TRUE );
if ( !WaitForCompletion( pRowset, TRUE ) ) { pCmdTree->Release(); pRowset->Release(); LogFail( "property query unsuccessful.\n" ); }
//
// Get data
//
DBCOUNTITEM cRowsReturned = 0; HROW* pgrhRows = 0;
SCODE sc = pRowset->GetNextRows(0, 0, 10, &cRowsReturned, &pgrhRows);
if ( FAILED( sc ) ) { pCmdTree->Release(); pRowset->Release(); LogFail( "IRowset->GetRowsAt G returned 0x%x\n", sc ); }
if ( 0 == cExpectedHits ) { pCmdTree->Release(); pRowset->Release();
if ( cRowsReturned > 0 ) LogFail("RunPropQuery, %d returned rows, expected none\n", cRowsReturned); else return;
}
if (sc != DB_S_ENDOFROWSET && cRowsReturned != 10) { LogError( "IRowset->GetRowsAt H returned %d of %d rows," " status (%x) != DB_S_ENDOFROWSET\n", cRowsReturned, 10, sc); pCmdTree->Release(); pRowset->Release(); #if defined(UNIT_TEST)
cFailures++; return; #else
Fail(); #endif
}
//
// Expect 1 or 2 hits
//
if (sc != DB_S_ENDOFROWSET || cRowsReturned != cExpectedHits) { LogError( "IRowset->GetRowsAt I returned %d rows (expected %d)," " status (%x)\n", cRowsReturned, cExpectedHits, sc ); pCmdTree->Release(); pRowset->Release(); #if defined(UNIT_TEST)
cFailures++; return; #else
Fail(); #endif
}
//
// Patch the column index numbers with true column ids
//
DBID aDbCols[cSafeArrayTestCols]; aDbCols[0] = colSA_I4; aDbCols[1] = colSA_BSTR; aDbCols[2] = colSA_VARIANT; aDbCols[3] = colSA_R8; aDbCols[4] = colSA_DATE; aDbCols[5] = colSA_BOOL; aDbCols[6] = colSA_DECIMAL; aDbCols[7] = colSA_I1; aDbCols[8] = colSA_R4; aDbCols[9] = colSA_CY; aDbCols[10] = colSA_UINT; aDbCols[11] = colSA_INT; aDbCols[12] = colSA_ERROR;
IUnknown * pAccessor = (IUnknown *) pRowset; // hAccessor must be created on rowset
// to be used with rowset->GetData below
HACCESSOR hAccessor = MapColumns(pAccessor, cSafeArrayTestCols, aSafeArrayTestCols, aDbCols);
//
// Fetch the data
//
PROPVARIANT aVarnt[cSafeArrayTestCols];
for (unsigned row = 0; row < cRowsReturned; row++) { sc = pRowset->GetData(pgrhRows[row], hAccessor, aVarnt);
if (S_OK != sc) { LogError("IRowset->GetData returned 0x%x (expected 0)\n",sc); pCmdTree->Release(); pRowset->Release(); Fail(); }
//
// Verify the data.
//
CheckPropertyValue( aVarnt[0], vaI4 ); CheckPropertyValue( aVarnt[1], vaBSTR ); CheckPropertyValue( aVarnt[2], vaVARIANT ); CheckPropertyValue( aVarnt[3], vaR8 ); CheckPropertyValue( aVarnt[4], vaDATE ); CheckPropertyValue( aVarnt[5], vaBOOL ); CheckPropertyValue( aVarnt[6], vaDECIMAL ); CheckPropertyValue( aVarnt[7], vaI1 ); CheckPropertyValue( aVarnt[8], vaR4 ); CheckPropertyValue( aVarnt[9], vaCY ); CheckPropertyValue( aVarnt[10], vaUINT ); CheckPropertyValue( aVarnt[11], vaINT ); CheckPropertyValue( aVarnt[12], vaERROR ); for ( int i = 0; i < 13; i++ ) PropVariantClear( & aVarnt[i] ); }
sc = pRowset->ReleaseRows( cRowsReturned, pgrhRows, 0, 0, 0);
if (S_OK != sc) { LogError("IRowset->ReleaseRows returned 0x%x (expected 0)\n",sc); pCmdTree->Release(); pRowset->Release(); Fail(); }
CoTaskMemFree(pgrhRows); pgrhRows = 0;
//
// Clean up.
//
ReleaseAccessor( pAccessor, hAccessor);
pCmdTree->Release(); pRowset->Release(); } //RunSafeArrayQuery
//+-------------------------------------------------------------------------
//
// Function: RunSafeArrayTest, public
//
// Synopsis: Very minimal test of safe array property query
//
// History: 17-Jun-98 dlee Created
//
//--------------------------------------------------------------------------
void RunSafeArrayTest( void ) { LogProgress( "SafeArray Retrieval Test\n" );
WCHAR *pwszScope = wcsTestPath; DWORD dwDepth = QUERY_SHALLOW; IUnknown * pIUnknown; ICommand * pQuery = 0; SCODE scIC = CICreateCommand( &pIUnknown, 0, IID_IUnknown, TEST_CATALOG, TEST_MACHINE ); if ( FAILED( scIC ) ) LogFail( "RunSafeArrayTest - error 0x%x Unable to create ICommand\n", scIC );
scIC = pIUnknown->QueryInterface(IID_ICommand, (void **) &pQuery ); pIUnknown->Release();
if ( FAILED( scIC ) ) LogFail( "RunSafeArrayTest - error 0x%x Unable to QI ICommand\n", scIC );
if ( 0 == pQuery ) LogFail( "RunSafeArrayTest - CICreateCommand succeeded, but returned null pQuery\n" );
scIC = SetScopeProperties( pQuery, 1, &pwszScope, &dwDepth );
if ( FAILED( scIC ) ) LogFail( "RunSafeArrayTest - error 0x%x Unable to set scope '%ws'\n", scIC, pwszScope );
CheckPropertiesOnCommand( pQuery );
unsigned numTest = 1;
{ LogProgress( " SafeArray test 1\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( colSA_I4 ); PropRst.SetRelation( DBOP_equal ); PropRst.SetValue( vaI4 ); RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ ); }
{ LogProgress( " SafeArray test 2\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( colSA_BSTR ); PropRst.SetRelation( DBOP_equal ); PropRst.SetValue( vaBSTR ); RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ ); }
{ LogProgress( " SafeArray test 3\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( colSA_VARIANT ); PropRst.SetRelation( DBOP_equal ); PropRst.SetValue( vaVARIANT ); RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ ); }
{ LogProgress( " SafeArray test 4\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( colSA_R8 ); PropRst.SetRelation( DBOP_equal ); PropRst.SetValue( vaR8 ); RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ ); }
{ LogProgress( " SafeArray test 5\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( colSA_DATE ); PropRst.SetRelation( DBOP_equal ); PropRst.SetValue( vaDATE ); RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ ); }
{ LogProgress( " SafeArray test 6\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( colSA_BOOL ); PropRst.SetRelation( DBOP_equal ); PropRst.SetValue( vaBOOL ); RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ ); }
{ LogProgress( " SafeArray test 7\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( colSA_DECIMAL ); PropRst.SetRelation( DBOP_equal ); PropRst.SetValue( vaDECIMAL ); RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ ); }
{ LogProgress( " SafeArray test 8\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( colSA_I1 ); PropRst.SetRelation( DBOP_equal ); PropRst.SetValue( vaI1 ); RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ ); }
{ LogProgress( " SafeArray test 9\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( colSA_R4 ); PropRst.SetRelation( DBOP_equal ); PropRst.SetValue( vaR4 ); RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ ); }
{ LogProgress( " SafeArray test 10\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( colSA_CY ); PropRst.SetRelation( DBOP_equal ); PropRst.SetValue( vaCY ); RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ ); }
{ LogProgress( " SafeArray test 11\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( colSA_UINT ); PropRst.SetRelation( DBOP_equal ); PropRst.SetValue( vaUINT ); RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ ); }
{ LogProgress( " SafeArray test 12\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( colSA_INT ); PropRst.SetRelation( DBOP_equal ); PropRst.SetValue( vaINT ); RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ ); }
{ LogProgress( " SafeArray test 13\n" ); CDbPropertyRestriction PropRst; PropRst.SetProperty( colSA_ERROR ); PropRst.SetRelation( DBOP_equal ); PropRst.SetValue( vaERROR ); RunSafeArrayQuery( pQuery, PropRst, 2, numTest++ ); }
pQuery->Release(); } //RunSafeArrayTest
//+-------------------------------------------------------------------------
//
// Function: CheckPropertyValue, public
//
// Synopsis: Check that a returned property value is as expected
//
// Arguments: [varntPropRet] -- Returned property value
// [varntPropExp] -- Expected property value
//
// Returns: nothing - calls Fail() if error
//
// History: 20 Oct 93 Alanw Created
//
//--------------------------------------------------------------------------
void CheckPropertyValue( PROPVARIANT const & varntPropRet, PROPVARIANT const & varntPropExp ) { if ( varntPropRet.vt != varntPropExp.vt ) { LogError( "Invalid return data type for property!\n" ); LogError( " Got %x expected %x\n", varntPropRet.vt, varntPropExp.vt ); cFailures++; //Fail();
} else if (varntPropExp.vt & VT_ARRAY) { SAFEARRAY * pSaRet = varntPropRet.parray; SAFEARRAY * pSaExp = varntPropExp.parray;
if (pSaRet->fFeatures != pSaExp->fFeatures || // pSaRet->cLocks != pSaExp->cLocks ||
pSaRet->cDims != pSaExp->cDims || pSaRet->cbElements!= pSaExp->cbElements) { LogError( "Mismatched safearray param!\n" ); LogError( " Got %x expected %x\n", pSaRet, pSaExp ); cFailures++; //Fail();
} else { BOOL fValuesEqual = TRUE; unsigned cDataElements = 1;
//
// get total data memory, and number of data elements in it.
//
for ( unsigned i = 0; i < pSaExp->cDims; i++ ) { if ( pSaExp->rgsabound[i].cElements != pSaRet->rgsabound[i].cElements || pSaExp->rgsabound[i].lLbound != pSaRet->rgsabound[i].lLbound ) { LogError( "Mismatched safearray dimension %d!\n", i ); LogError( " Got %x expected %x\n", pSaRet, pSaExp ); fValuesEqual = FALSE; //Fail();
}
cDataElements *= pSaExp->rgsabound[i].cElements; }
if (fValuesEqual) { ULONG cb = cDataElements * pSaExp->cbElements; if ( varntPropExp.vt == (VT_ARRAY|VT_VARIANT )) { // Not needed as the engine doesn't support it yet.
LogError( "can't validate arrays of variant\n" ); } else if (varntPropExp.vt != (VT_ARRAY|VT_BSTR)) { fValuesEqual = memcmp( pSaExp->pvData, pSaRet->pvData, cb ) == 0; if (! fValuesEqual) { if ( 0 == ( cb % sizeof ULONGLONG ) ) { ULONG c = cb / sizeof ULONGLONG; unsigned __int64 *pE = (unsigned __int64 *) pSaExp->pvData; unsigned __int64 *pR = (unsigned __int64 *) pSaRet->pvData; for ( ULONG i = 0; i < c; i++ ) { printf( "%d: e %#I64x, r %#I64x\n", i, pE[i], pR[i] ); } } printf( "varntPropExp: %#x\n", varntPropExp.vt ); printf( "varntPropRet: %#x\n", varntPropRet.vt ); LogError("Incorrect value for safearray property.\n"); // " Got %d, expected %d\n", i,
// varntPropRet.cal.pElems[i],
// varntPropExp.cal.pElems[i]);
} } else { BSTR * rgbstrExp = (BSTR *)pSaExp->pvData; BSTR * rgbstrRet = (BSTR *)pSaRet->pvData; for (unsigned i=0; i<cDataElements; i++) { fValuesEqual = (BSTRLEN(rgbstrRet[i]) == BSTRLEN(rgbstrExp[i])) && (memcmp(rgbstrRet[i], rgbstrExp[i], BSTRLEN(rgbstrExp[i])) == 0); if (! fValuesEqual) { LogError("Incorrect value for BSTR array property [%d].\n" " Got <%ws>, expected <%ws>\n", i, rgbstrRet[i], rgbstrExp[i]); break; } } } }
if (! fValuesEqual) { cFailures++; //Fail();
} } } else if (varntPropExp.vt & VT_VECTOR) { if (varntPropExp.cal.cElems != varntPropRet.cal.cElems) { LogError( "Incorrect value count for property.\n" " Got count %d, expected count %d\n", varntPropRet.cal.cElems, varntPropExp.cal.cElems); cFailures++; //Fail();
}
BOOL fValuesEqual = FALSE;
for (unsigned i=0; i<varntPropRet.cal.cElems; i++) {
switch (varntPropExp.vt) { case VT_VECTOR|VT_I4: fValuesEqual = varntPropRet.cal.pElems[i] == varntPropExp.cal.pElems[i]; if (! fValuesEqual) LogError("Incorrect value for vector property [%d].\n" " Got %d, expected %d\n", i, varntPropRet.cal.pElems[i], varntPropExp.cal.pElems[i]); break;
case VT_VECTOR|VT_LPWSTR: fValuesEqual = wcscmp(varntPropRet.calpwstr.pElems[i], varntPropExp.calpwstr.pElems[i]) == 0; if (! fValuesEqual) LogError("Incorrect value for vector property [%d].\n" " Got <%ws>, expected <%ws>\n", i, varntPropRet.calpwstr.pElems[i], varntPropExp.calpwstr.pElems[i]); break;
case VT_VECTOR|VT_BSTR: fValuesEqual = (BSTRLEN(varntPropRet.cabstr.pElems[i]) == BSTRLEN(varntPropExp.cabstr.pElems[i])) && (memcmp(varntPropRet.cabstr.pElems[i], varntPropExp.cabstr.pElems[i], BSTRLEN(varntPropExp.cabstr.pElems[i])) == 0); if (! fValuesEqual) LogError("Incorrect value for vector property [%d].\n" " Got <%ws>, expected <%ws>\n", i, varntPropRet.cabstr.pElems[i], varntPropExp.cabstr.pElems[i]); break;
case VT_VECTOR|VT_CF: { CLIPDATA & cdR = varntPropRet.caclipdata.pElems[i]; CLIPDATA & cdE = varntPropExp.caclipdata.pElems[i]; fValuesEqual = ( ( cdR.cbSize == cdE.cbSize ) && ( cdR.ulClipFmt == cdE.ulClipFmt ) && ( 0 != cdR.pClipData ) && ( 0 != cdE.pClipData ) && ( 0 == memcmp( cdR.pClipData, cdE.pClipData, CBPCLIPDATA( cdR ) ) ) ); if ( !fValuesEqual ) LogError( "Incorrect value for VT_VECTOR|VT_CF property\n" ); break; }
default: LogError("Unexpected property variant type %x\n", varntPropExp.vt); } if (! fValuesEqual) { cFailures++; //Fail();
} } } else { BOOL fValuesEqual = FALSE;
switch (varntPropExp.vt) { case VT_I4: fValuesEqual = varntPropRet.iVal == varntPropExp.iVal; if (! fValuesEqual) LogError("Incorrect value for property.\n" " Got %d, expected %d\n", varntPropRet.iVal, varntPropExp.iVal); break;
case VT_LPWSTR: case DBTYPE_WSTR | DBTYPE_BYREF: fValuesEqual = wcscmp(varntPropRet.pwszVal, varntPropExp.pwszVal) == 0; if (! fValuesEqual) LogError("Incorrect value for property.\n" " Got <%ws>, expected <%ws>\n", varntPropRet.pwszVal, varntPropExp.pwszVal); break;
case VT_BSTR: fValuesEqual = ( SysStringLen( varntPropRet.bstrVal ) == SysStringLen( varntPropExp.bstrVal ) ) && memcmp( varntPropRet.bstrVal, varntPropExp.bstrVal, SysStringLen( varntPropExp.bstrVal ) ) == 0;
if ( SysStringLen( varntPropRet.bstrVal ) != SysStringLen( varntPropExp.bstrVal ) ) LogError("Incorrect BSTR length for property.\n" " Got %d, expected %d\n", SysStringLen( varntPropRet.bstrVal ), SysStringLen( varntPropExp.bstrVal ) ); else if (! fValuesEqual) LogError("Incorrect value for property.\n" " Got <%ws>, expected <%ws>\n", varntPropRet.pwszVal, varntPropExp.pwszVal); break;
case VT_CLSID: fValuesEqual = *varntPropRet.puuid == *varntPropExp.puuid;
if (! fValuesEqual) LogError("Incorrect value for guid property.\n"); break;
case VT_BLOB: fValuesEqual = (varntPropRet.blob.cbSize == varntPropExp.blob.cbSize) && memcmp(varntPropRet.blob.pBlobData, varntPropExp.blob.pBlobData, varntPropExp.blob.cbSize) == 0; if (! fValuesEqual) LogError("Incorrect value for blob property.\n"); break;
case VT_CF: { CLIPDATA & cdR = *varntPropRet.pclipdata; CLIPDATA & cdE = *varntPropExp.pclipdata; fValuesEqual = ( ( cdR.cbSize == cdE.cbSize ) && ( cdR.ulClipFmt == cdE.ulClipFmt ) && ( 0 != cdR.pClipData ) && ( 0 != cdE.pClipData ) && ( 0 == memcmp( cdR.pClipData, cdE.pClipData, CBPCLIPDATA( cdR ) ) ) ); if ( !fValuesEqual ) LogError( "Incorrect value for VT_CF property\n" ); break; }
case VT_EMPTY: // nothing to check
fValuesEqual = TRUE; break;
default: LogError("Unexpected property variant type %d\n", varntPropExp.vt); } if (! fValuesEqual) { cFailures++; //Fail();
} }
return; } //CheckPropertyValue
#ifdef DO_CONTENT_TESTS
//+-------------------------------------------------------------------------
//
// Function: DoContentQuery, public
//
// Synopsis: Execute a retricted content query and check results
//
// Arguments: [pQuery] -- ICommand * for the query
// [CiRst] -- content restirction
// [cExpectedHits] -- expected number of hits
//
// Returns: BOOL - FALSE if first content query, and less than the
// expected number of hits was found. Probably indicates
// that the content index was not up-to-date.
//
// History: 01 Aug 1995 AlanW Created
//
//--------------------------------------------------------------------------
const unsigned MAX_CI_RETRIES = 5; const unsigned CI_SLEEP_TICKS = 15 * 1000;
BOOL DoContentQuery( ICommand * pQuery, CDbRestriction & CiRst, unsigned cExpectedHits ) { static fFirstTime = TRUE;
//
// Get three properties back
//
CDbColumns cols(3); cols.Add( psName, 0 ); cols.Add( psPath, 1 ); cols.Add( psRank, 2 );
//
// Do it!
//
unsigned cRetries = 0; DBCOUNTITEM cRowsReturned = 0; HROW* pgrhRows = 0; SCODE sc; IRowset * pRowset = 0;
do {
CDbCmdTreeNode * pCmdTree = FormQueryTree(&CiRst, cols, 0);
pRowset = InstantiateRowset( pQuery, QUERY_SHALLOW, // Depth
wcsTestPath, // Scope
pCmdTree, // DBCOMMANDTREE
IID_IRowset); // IID of i/f to return
//
// Verify columns
//
CheckColumns( pRowset, cols, TRUE );
if ( !WaitForCompletion( pRowset, TRUE ) ) { LogError( "Content query unsuccessful.\n" ); pRowset->Release(); Fail(); }
//
// Get data
//
sc = pRowset->GetNextRows(0, 0, 10, &cRowsReturned, &pgrhRows);
if ( FAILED( sc ) ) { LogError( "IRowset->GetNextRows returned 0x%x\n", sc ); pRowset->Release(); Fail(); }
//
// Check to see if the CI is up-to-date
//
IRowsetQueryStatus * pRowsetQueryStatus = 0;
SCODE scTemp = pRowset->QueryInterface(IID_IRowsetQueryStatus, (void **) &pRowsetQueryStatus);
if ( FAILED( scTemp ) && scTemp != E_NOINTERFACE ) { LogError( "IRowset::QI IRowsetQueryStatus failed, 0x%x\n", sc ); cFailures++; }
DWORD dwStatus = 0; if (pRowsetQueryStatus != 0) { scTemp = pRowsetQueryStatus->GetStatus( &dwStatus ); pRowsetQueryStatus->Release();
if ( QUERY_RELIABILITY_STATUS(dwStatus) & STAT_CONTENT_OUT_OF_DATE ) { FreeHrowsArray( pRowset, cRowsReturned, &pgrhRows ); pRowset->Release(); cRetries++; if (cRetries < MAX_CI_RETRIES) { Sleep( CI_SLEEP_TICKS ); continue; } } break; } else if (fFirstTime && cRowsReturned < cExpectedHits) { FreeHrowsArray( pRowset, cRowsReturned, &pgrhRows ); pRowset->Release(); cRetries++; if (cRetries < MAX_CI_RETRIES) Sleep( CI_SLEEP_TICKS ); } else { break; } } while ( cRetries < MAX_CI_RETRIES );
if (cRetries >= MAX_CI_RETRIES) { LogError( "Content query test skipped due to timeout\n" ); return FALSE; } fFirstTime = FALSE;
if ( 0 == cExpectedHits ) { pRowset->Release();
if ( cRowsReturned > 0 ) LogFail("DoContentQuery, %d returned rows, expected none\n", cRowsReturned); else return TRUE;
}
if (sc != DB_S_ENDOFROWSET && cRowsReturned != 10) { LogError( "IRowset->GetNextRows returned %d of %d rows," " status (%x) != DB_S_ENDOFROWSET\n", cRowsReturned, 10, sc); pRowset->Release(); #if defined(UNIT_TEST)
cFailures++; return TRUE; #else
Fail(); #endif
}
//
// Expect 1 to 5 hits
//
if (sc != DB_S_ENDOFROWSET || cRowsReturned != cExpectedHits) { LogError( "IRowset->GetNextRows returned %d rows (expected %d)," " status (%x)\n", cRowsReturned, cExpectedHits, sc ); pRowset->Release(); #if defined(UNIT_TEST)
cFailures++; return TRUE; #else
Fail(); #endif
}
FreeHrowsArray( pRowset, cRowsReturned, &pgrhRows );
//
// Clean up.
//
pRowset->Release(); return TRUE; } //DoContentQuery
//+-------------------------------------------------------------------------
//
// Function: ContentTest, public
//
// Synopsis: Very minimal test of Content query
//
// History: 13-May-93 KyleP Created
// 15 Oct 94 Alanw Converted to OLE-DB query
//
//--------------------------------------------------------------------------
void ContentTest() { LogProgress( "Content Query\n" );
WCHAR *pwszScope = wcsTestPath;
DWORD dwDepth = QUERY_SHALLOW; ICommand * pQuery = 0; SCODE scIC = CICreateCommand( (IUnknown **)&pQuery, 0, IID_ICommand, CONTENT_CATALOG, TEST_MACHINE ); if ( FAILED( scIC ) ) LogFail( "RunPropTest - error 0x%x Unable to create ICommand\n", scIC );
if ( 0 == pQuery ) LogFail( "RunPropTest - CICreateCommand succeeded, but returned null pQuery\n" );
scIC = SetScopeProperties( pQuery, 1, &pwszScope, &dwDepth );
// simple content query
{ LogProgress( " Content Query test 0\n" ); CDbContentRestriction CiRst( L"country", psContents); if (! DoContentQuery( pQuery, CiRst, 2 )) { pQuery->Release(); return; } }
// content query on property
{ LogProgress( " Content Query test 1\n" ); CDbContentRestriction CiRst( L"alanw", psAuthor); DoContentQuery( pQuery, CiRst, 2 ); }
// natural language query
{ LogProgress( " Content Query test 2\n" ); CDbNatLangRestriction CiRst( L"who is oscar wilde", psContents); DoContentQuery( pQuery, CiRst, 1 ); }
// content query with prefix match
{ LogProgress( " Content Query test 3\n" ); CDbContentRestriction CiRst( L"cont", psContents, GENERATE_METHOD_PREFIX ); DoContentQuery( pQuery, CiRst, 1 ); }
// content query with stemming
{ LogProgress( " Content Query test 4\n" ); CDbContentRestriction CiRst( L"temptation", psContents, GENERATE_METHOD_INFLECT ); DoContentQuery( pQuery, CiRst, 1 ); }
// content query with more obscure stemming (prefix match)
{ LogProgress( " Content Query test 4A\n" ); CDbContentRestriction CiRst( L"crea", psContents, GENERATE_METHOD_PREFIX ); DoContentQuery( pQuery, CiRst, 1 ); }
// content query with more obscure stemming (stemmed)
{ LogProgress( " Content Query test 4B\n" ); CDbContentRestriction CiRst( L"crea", psContents, GENERATE_METHOD_INFLECT ); DoContentQuery( pQuery, CiRst, 0 ); }
// content query with more obscure stemming (prefix match)
{ LogProgress( " Content Query test 4C\n" ); CDbContentRestriction CiRst( L"create", psContents, GENERATE_METHOD_PREFIX ); DoContentQuery( pQuery, CiRst, 1 ); }
// content query with more obscure stemming (stemmed)
{ LogProgress( " Content Query test 4D\n" ); CDbContentRestriction CiRst( L"create", psContents, GENERATE_METHOD_INFLECT ); DoContentQuery( pQuery, CiRst, 1 ); }
// and content query
{ LogProgress( " Content Query test 5\n" ); CDbBooleanNodeRestriction CiRst( DBOP_and ); CDbContentRestriction *pRst1 = new CDbContentRestriction( L"country", psContents); CDbContentRestriction *pRst2 = new CDbContentRestriction( L"content", psContents); CiRst.AppendChild(pRst1); CiRst.AppendChild(pRst2); DoContentQuery( pQuery, CiRst, 1 ); }
// and not content query
{ LogProgress( " Content Query test 6\n" ); CDbBooleanNodeRestriction CiRst( DBOP_and ); CDbContentRestriction *pRst1 = new CDbContentRestriction( L"country", psContents); CDbContentRestriction *pRst2 = new CDbContentRestriction( L"content", psContents); CDbNotRestriction *pRst3 = new CDbNotRestriction( pRst2 ); CiRst.AppendChild(pRst1); CiRst.AppendChild(pRst3); DoContentQuery( pQuery, CiRst, 1 ); }
// proximity content query
{ LogProgress( " Content Query test 7\n" ); CDbProximityNodeRestriction CiRst; CDbContentRestriction *pRst1 = new CDbContentRestriction( L"country", psContents); CDbContentRestriction *pRst2 = new CDbContentRestriction( L"temptations", psContents); CiRst.AppendChild(pRst1); CiRst.AppendChild(pRst2); DoContentQuery( pQuery, CiRst, 1 ); }
// vector or query
{ LogProgress( " Content Query test 8\n" ); CDbVectorRestriction CiRst( VECTOR_RANK_MIN ); CDbContentRestriction *pRst1 = new CDbContentRestriction( L"country", psContents); CDbContentRestriction *pRst2 = new CDbContentRestriction( L"temptations", psContents); CDbContentRestriction *pRst3 = new CDbContentRestriction( L"DELETE", psContents);
pRst1->SetWeight( 500 ); pRst2->SetWeight( 1000 ); pRst3->SetWeight( 50 );
CiRst.AppendChild( pRst1 ); CiRst.AppendChild( pRst2 ); CiRst.AppendChild( pRst3 );
// This might return 3 if the test directory is on FAT
const unsigned cMatches = 2; DoContentQuery( pQuery, CiRst, cMatches ); }
pQuery->Release(); } //ContentTest
#endif // DO_CONTENT_TESTS
#if defined( DO_NOTIFICATION )
class CTestRowsetNotify : public IRowsetNotify { public: CTestRowsetNotify() : _fChecking(FALSE), _cRef(1), _dwReasonToCheck(0), _cNotifies(0) {}
~CTestRowsetNotify() { }
void StartCheck(DWORD dwReason) { _fChecking = TRUE; _dwReasonToCheck = dwReason; _cNotifies = 0; }
void TestCheck( ULONG cNotifies ) { if (_cNotifies != cNotifies ) LogError ( "CTestRowsetNotify::TestCheck failed, " "reason %d, exp %d got %d\n", _dwReasonToCheck, cNotifies, _cNotifies ); _fChecking = FALSE; }
//
// IUnknown methods.
//
STDMETHOD(QueryInterface) (THIS_ REFIID riid,LPVOID *ppiuk) { *ppiuk = (void **) this; // hold our breath and jump
AddRef(); return S_OK; }
STDMETHOD_(ULONG, AddRef) (THIS) { return ++_cRef; }
STDMETHOD_(ULONG, Release) (THIS) { return --_cRef; }
//
// IRowsetNotify methods.
//
STDMETHOD(OnFieldChange) ( IRowset * pRowset, HROW hRow, DBORDINAL cColumns, DBORDINAL rgColumns[], DBREASON eReason, DBEVENTPHASE ePhase, BOOL fCantDeny ) { if ( _fChecking && eReason == _dwReasonToCheck ) { _cNotifies++; } return S_OK; }
STDMETHOD(OnRowChange) ( IRowset * pRowset, DBCOUNTITEM cRows, const HROW rghRows[], DBREASON eReason, DBEVENTPHASE ePhase, BOOL fCantDeny ) { if ( _fChecking && eReason == _dwReasonToCheck ) { _cNotifies++; } return S_OK; }
STDMETHOD(OnRowsetChange) ( IRowset * pRowset, DBREASON eReason, DBEVENTPHASE ePhase, BOOL fCantDeny ) { if ( _fChecking && eReason == _dwReasonToCheck ) { _cNotifies++; } return S_OK; }
private: ULONG _cRef; BOOL _fChecking; DWORD _dwReasonToCheck; ULONG _cNotifies; };
class CTestWatchNotify : public IRowsetWatchNotify { public: CTestWatchNotify() : _fChecking(FALSE), _fRequery(FALSE), _fComplete(FALSE), _cRowChanges(0), _cRef(1) {}
void DoChecking(BOOL fChecking) { _fChecking = fChecking; }
~CTestWatchNotify() { if (_fChecking) { if (1 != _cRef) // NOTE: notify objects are static allocated
{ LogFail( "Bad refcount on CTestWatchNotify: %#x, %d.\n", this, _cRef ); } } }
//
// IUnknown methods.
//
STDMETHOD(QueryInterface) (THIS_ REFIID riid,LPVOID *ppiuk) { *ppiuk = (void **) this; // hold our breath and jump
AddRef(); return S_OK; }
STDMETHOD_(ULONG, AddRef) (THIS) { /*printf( "addref: %d\n", _cRef+1 );*/ return ++_cRef; }
STDMETHOD_(ULONG, Release) (THIS) { /*printf( "release: %d\n", _cRef-1 );*/ return --_cRef; }
//void DumpRef() { printf( "ref: %d\n", _cRef ); }
//
// IRowsetNotifyWatch method
//
STDMETHOD(OnChange) (THIS_ IRowset* pRowset, DBWATCHNOTIFY changeType) { switch (changeType) { case DBWATCHNOTIFY_ROWSCHANGED: _cRowChanges++; break; case DBWATCHNOTIFY_QUERYDONE: _fComplete = TRUE; break; case DBWATCHNOTIFY_QUERYREEXECUTED: _fRequery = TRUE; break; default: _BadChangeType = changeType; } return S_OK; }
private: ULONG _cRef; BOOL _fChecking; BOOL _fComplete; BOOL _fRequery; ULONG _cRowChanges; DBWATCHNOTIFY _BadChangeType; };
//+-------------------------------------------------------------------------
//
// Function: NotificationTest, public
//
// Synopsis: Test basic notification functionality
//
// Returns: Nothing
//
// Notes: At the point this is called, the notification has been
// set up. This function adds/deletes/modifies files and
// expects to get notifications of these changes.
//
// History: 14 Oct 94 dlee created
//
//--------------------------------------------------------------------------
void NotificationTest() { LogProgress( " Notification test\n" );
//
// Makes files in the nt\system32 directory that look like "X.zzz"
//
WCHAR wcsSysDir[MAX_PATH]; if( !GetSystemDirectory( wcsSysDir, sizeof(wcsSysDir) / sizeof(WCHAR) ) ) { LogFail( "Unable to determine system directory.\n" ); }
wcscat(wcsSysDir,L"\\X.zzz"); unsigned iNamePos = wcslen(wcsSysDir) - 5;
DWORD dwStart = GetTickCount();
//
// create / touch / delete files for 5 seconds
//
while ((GetTickCount() - dwStart) < 3000) { Sleep(rand() % 300);
wcsSysDir[iNamePos] = (WCHAR) ('a' + (rand() % 10));
HANDLE h = CreateFile(wcsSysDir, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | (((rand() % 103) < 20) ? FILE_FLAG_DELETE_ON_CLOSE : 0), 0);
if (INVALID_HANDLE_VALUE != h) { DWORD dw = 0xf0f0f0f0; DWORD dwWritten; WriteFile(h,&dw,sizeof(DWORD),&dwWritten,0);
CloseHandle(h); } else { LogFail( "Can't create test file in the system32 directory.\n" ); } }
//
// sleep some more to pick up all the notifications
//
Sleep(1000);
} //NotificationTest
#endif // defined( DO_NOTIFICATION )
//+-------------------------------------------------------------------------
//
// Function: CheckColumns, public
//
// Synopsis: Verify that the cursor contains all the requested columns
// Also, check to see if the IColumnsInfo and IColumnsRowset
// interfaces are supported. Print out column info. and rowset
// properties if the very verbose option is chosen.
//
// Arguments: [pRowset] - a pointer to an IRowset* to be tested.
// [rColumns] - a reference to a CDbColumns giving the input
// columns
//
// Returns: Nothing
//
// Notes: This function may be called prior to the rowset population
// having completed.
//
// History: 14 Nov 94 Alanw Created
//
//--------------------------------------------------------------------------
char *DBTYPE_Tag (DBTYPE type) { #define CASE(name) \
case DBTYPE_ ## name: \ return #name
switch (type) { CASE (NULL); CASE (BOOL); CASE (I1); CASE (UI1); CASE (I2); CASE (I4); CASE (UI2); CASE (UI4); CASE (I8); CASE (UI8); CASE (R4); CASE (R8); CASE (CY); CASE (DATE); CASE (VARIANT); CASE (GUID); CASE (STR); CASE (BYTES); CASE (WSTR); CASE (NUMERIC);
default: return "BAD"; }
#undef CASE
}
void PrintColumnFlags (DBCOLUMNFLAGS flags) { #define FLAG(name) \
if (flags & DBCOLUMNFLAGS_ ## name) \ printf (#name " ")
FLAG (ISBOOKMARK); FLAG (MAYDEFER); // FLAG (MAYREFERENCE);
FLAG (WRITE); FLAG (WRITEUNKNOWN); // FLAG (ISSIGNED);
FLAG (ISFIXEDLENGTH); FLAG (ISNULLABLE); FLAG (MAYBENULL); FLAG (ISCHAPTER); FLAG (ISLONG); FLAG (ISROWID); FLAG (ISROWVER); FLAG (CACHEDEFERRED);
#undef FLAG
}
DBPROP * LocateProperty ( REFIID rPropSet, DWORD dwPropId, ULONG cPropSets, DBPROPSET * pPropSets) { for (unsigned i=0; i<cPropSets; i++, pPropSets++) { if (pPropSets->guidPropertySet != rPropSet) continue;
for (unsigned j=0; j<pPropSets->cProperties; j++) { if (pPropSets->rgProperties[j].dwPropertyID == dwPropId) return &pPropSets->rgProperties[j]; } return 0; }
return 0; }
DBPROPINFO UNALIGNED * LocatePropertyInfo ( REFIID rPropSet, DWORD dwPropId, ULONG cPropInfoSets, DBPROPINFOSET * pPropInfoSets) { for (unsigned i=0; i<cPropInfoSets; i++, pPropInfoSets++) { if (pPropInfoSets->guidPropertySet != rPropSet) continue;
for (unsigned j=0; j<pPropInfoSets->cPropertyInfos; j++) { if (pPropInfoSets->rgPropertyInfos[j].dwPropertyID == dwPropId) return &pPropInfoSets->rgPropertyInfos[j]; } return 0; }
return 0; }
BOOL CheckBooleanProperty ( REFIID rPropSet, DWORD dwPropId, ULONG cProps, DBPROPSET * pProps) { DBPROP * pPropDesc = LocateProperty( rPropSet, dwPropId, cProps, pProps );
if (pPropDesc) { if ( !( (pPropDesc->vValue.vt == VT_EMPTY && pPropDesc->dwStatus == DBPROPSTATUS_NOTSUPPORTED) || (pPropDesc->vValue.vt == VT_BOOL && (pPropDesc->vValue.boolVal == VARIANT_TRUE || pPropDesc->vValue.boolVal == VARIANT_FALSE)) ) ) { LogError( "Bad boolean property value %d, %d\n", pPropDesc->vValue.vt, pPropDesc->vValue.lVal ); } return (pPropDesc->vValue.vt == VT_BOOL && pPropDesc->vValue.boolVal == VARIANT_TRUE); } return FALSE; }
BOOL CheckNumericProperty ( REFIID rPropSet, DWORD dwPropId, ULONG cProps, DBPROPSET * pProps, LONG & rlVal) { DBPROP * pPropDesc = LocateProperty( rPropSet, dwPropId, cProps, pProps );
if (pPropDesc) { if ( !( (pPropDesc->vValue.vt == VT_EMPTY && pPropDesc->dwStatus == DBPROPSTATUS_NOTSUPPORTED) || (pPropDesc->vValue.vt == VT_I4) ) ) { LogError( "Bad numeric property value %d\n", pPropDesc->vValue.vt ); return FALSE; } rlVal = pPropDesc->vValue.lVal; return (pPropDesc->vValue.vt == VT_I4); } return FALSE; }
void CheckSafeArrayProperty ( REFIID rPropSet, DWORD dwPropId, ULONG cProps, DBPROPSET * pProps ) { DBPROP * pPropDesc = LocateProperty( rPropSet, dwPropId, cProps, pProps );
if (pPropDesc) { if ( pPropDesc->vValue.vt == (VT_ARRAY | VT_BSTR ) ) { if ( 1 != SafeArrayGetDim( pPropDesc->vValue.parray ) ) printf( "Bad array dimension\n" ); else { long LBound = 1; long UBound = 0;
SafeArrayGetLBound( pPropDesc->vValue.parray, 1, &LBound ); SafeArrayGetUBound( pPropDesc->vValue.parray, 1, &UBound );
for ( long j = LBound; j <= UBound; j++ ) { WCHAR ** pwcsVal;
SCODE sc = SafeArrayPtrOfIndex( pPropDesc->vValue.parray, &j, (void **)&pwcsVal );
if ( SUCCEEDED(sc) ) { if ( j != LBound ) printf( ", " ); printf( "%ws", *pwcsVal ); } } } } else if ( pPropDesc->vValue.vt == VT_BSTR ) { printf( "%ws", pPropDesc->vValue.bstrVal ); } else if ( pPropDesc->vValue.vt == (VT_ARRAY | VT_I4 ) ) { if ( 1 != SafeArrayGetDim( pPropDesc->vValue.parray ) ) printf( "Bad array dimension\n" ); else { long LBound = 1; long UBound = 0;
SafeArrayGetLBound( pPropDesc->vValue.parray, 1, &LBound ); SafeArrayGetUBound( pPropDesc->vValue.parray, 1, &UBound );
for ( long j = LBound; j <= UBound; j++ ) { ULONG ulVal;
SCODE sc = SafeArrayGetElement( pPropDesc->vValue.parray, &j, &ulVal );
if ( SUCCEEDED(sc) ) { if ( j != LBound ) printf( ", " ); printf( "%u", ulVal ); } } } } else if ( pPropDesc->vValue.vt == VT_I4 ) { printf( "%u", pPropDesc->vValue.lVal ); } else printf( "Unknown VT type %d\n", pPropDesc->vValue.vt ); } else printf( "n/a" ); }
//
// GetBooleanProperty - return boolean property value setting for dbprop
//
BOOL GetBooleanProperty ( IRowset * pRowset, DBPROPID dbprop ) { DBPROPSET *pPropInfo = 0; ULONG cPropSets = 0; DBPROPIDSET PropIdSet; DBPROPID PropID = dbprop;
PropIdSet.rgPropertyIDs = &PropID; PropIdSet.cPropertyIDs = 1; PropIdSet.guidPropertySet = DBPROPSET_ROWSET;
IRowsetInfo *pIRowInfo = 0; SCODE sc = pRowset->QueryInterface(IID_IRowsetInfo,(void **) &pIRowInfo);
sc = pIRowInfo->GetProperties( 1, &PropIdSet, &cPropSets, &pPropInfo ); pIRowInfo->Release();
BOOL fReturnValue = FALSE; if ( FAILED( sc ) || cPropSets != 1 || pPropInfo->cProperties != 1 ) { LogFail( "IRowsetInfo::GetProperties returned sc=0x%lx, cPropSets=%d\n", sc, cPropSets ); } else { if (pPropInfo->rgProperties->vValue.vt == VT_BOOL && pPropInfo->rgProperties->dwStatus == DBPROPSTATUS_OK) { fReturnValue = (pPropInfo->rgProperties->vValue.boolVal == VARIANT_TRUE); } else { LogFail( "IRowsetInfo::GetProperties returned bad DBPROPSET," " vt = %d status = %x\n", pPropInfo->rgProperties->vValue.vt, pPropInfo->rgProperties->dwStatus ); } if (pPropInfo) { if (pPropInfo->rgProperties) CoTaskMemFree(pPropInfo->rgProperties); CoTaskMemFree(pPropInfo); } } return fReturnValue; }
void PrintRowsetProps (ULONG cProps, DBPROPSET * pProps) { printf("\nRowset Properties:" );
unsigned cBoolProps = 0;
#define BOOLPROP(name) \
if (CheckBooleanProperty( DBPROPSET_ROWSET, DBPROP_ ## name, cProps, pProps) ) \ { if ((cBoolProps % 4) == 0) printf("\n\t"); \ cBoolProps++; \ printf (#name " "); \ }
BOOLPROP (ABORTPRESERVE); BOOLPROP (APPENDONLY); BOOLPROP (BLOCKINGSTORAGEOBJECTS); BOOLPROP (BOOKMARKS); BOOLPROP (BOOKMARKSKIPPED); BOOLPROP (CACHEDEFERRED); BOOLPROP (CANFETCHBACKWARDS); BOOLPROP (CANHOLDROWS); BOOLPROP (CANSCROLLBACKWARDS); BOOLPROP (CHANGEINSERTEDROWS); #ifdef DBPROP_CHAPTERED
BOOLPROP (CHAPTERED); #endif // DBPROP_CHAPTERED
BOOLPROP (COLUMNRESTRICT); BOOLPROP (COMMITPRESERVE); BOOLPROP (DEFERRED); BOOLPROP (DELAYSTORAGEOBJECTS); BOOLPROP (IMMOBILEROWS); BOOLPROP (LITERALBOOKMARKS); BOOLPROP (LITERALIDENTITY); #ifdef DBPROP_MULTICHAPTERED
BOOLPROP (MULTICHAPTERED); #endif // DBPROP_MULTICHAPTERED
BOOLPROP (MAYWRITECOLUMN); BOOLPROP (ORDEREDBOOKMARKS); BOOLPROP (OTHERINSERT); BOOLPROP (OTHERUPDATEDELETE); BOOLPROP (OWNINSERT); BOOLPROP (OWNUPDATEDELETE); BOOLPROP (QUICKRESTART); BOOLPROP (REENTRANTEVENTS); BOOLPROP (REMOVEDELETED); BOOLPROP (REPORTMULTIPLECHANGES); BOOLPROP (RETURNPENDINGINSERTS); BOOLPROP (ROWRESTRICT); BOOLPROP (SERVERCURSOR); BOOLPROP (STRONGIDENTITY); BOOLPROP (TRANSACTEDOBJECT);
cBoolProps = 0; BOOLPROP (IAccessor); BOOLPROP (IChapteredRowset); BOOLPROP (IColumnsInfo); BOOLPROP (IColumnsRowset); BOOLPROP (IConnectionPointContainer); BOOLPROP (IDBAsynchStatus); BOOLPROP (IRowset); BOOLPROP (IRowsetChange); BOOLPROP (IRowsetIdentity); BOOLPROP (IRowsetInfo); BOOLPROP (IRowsetLocate); BOOLPROP (IRowsetResynch); BOOLPROP (IRowsetScroll); BOOLPROP (IRowsetUpdate); BOOLPROP (ISupportErrorInfo); BOOLPROP (IRowsetAsynch); BOOLPROP (IRowsetWatchAll); BOOLPROP (IRowsetWatchRegion);
// The following are per-column
// BOOLPROP (ILockBytes);
// BOOLPROP (ISequentialStream);
// BOOLPROP (IStorage);
// BOOLPROP (IStream);
#undef BOOLPROP
printf("\n");
LONG n;
#define NUMPROP(name) \
if (CheckNumericProperty( DBPROPSET_ROWSET, DBPROP_ ## name, cProps, pProps, n) ) \ printf ("\t" #name ":\t%d\n", n); \ else \ printf ("\t" #name ":\t--\n");
NUMPROP( BOOKMARKTYPE ); NUMPROP( COMMANDTIMEOUT ); NUMPROP( MAXOPENROWS ); #ifdef DBPROP_MAXOPENROWSPERCHAPTER
NUMPROP( MAXOPENROWSPERCHAPTER ); #endif // DBPROP_MAXOPENROWSPERCHAPTER
NUMPROP( MAXPENDINGROWS ); NUMPROP( MAXROWS ); #ifdef DBPROP_MAXPENDINGCHANGESCHAPTER
NUMPROP( MAXPENDINGCHANGESPERCHAPTER ); #endif // DBPROP_MAXPENDINGCHANGESCHAPTER
NUMPROP( MEMORYUSAGE ); NUMPROP( NOTIFICATIONGRANULARITY ); NUMPROP( NOTIFICATIONPHASES ); NUMPROP( NOTIFYROWSETRELEASE ); NUMPROP( NOTIFYROWSETFETCHPOSITIONCHANGE ); // NUMPROP( NOTIFYCOLUMNSET, et al. );
NUMPROP( ROWSET_ASYNCH ); NUMPROP( ROWTHREADMODEL ); NUMPROP( UPDATABILITY );
#undef NUMPROP
#define BOOLPROP(name) \
if (CheckBooleanProperty( guidQueryExt, DBPROP_ ## name, cProps, pProps) ) \ { if ((cBoolProps % 4) == 0) printf("\n\t"); \ cBoolProps++; \ printf (#name " "); \ }
cBoolProps = 0; BOOLPROP (USECONTENTINDEX); BOOLPROP (DEFERNONINDEXEDTRIMMING); BOOLPROP (USEEXTENDEDDBTYPES);
#undef BOOLPROP
printf("\n\n");
#define SAPROP(name) \
printf ( "\t" #name ": "); \ CheckSafeArrayProperty( guidFsCiFrmwrkExt, DBPROP_ ## name, cProps, pProps); \ printf ( "\n" );
SAPROP (CI_INCLUDE_SCOPES); SAPROP (CI_DEPTHS); SAPROP (CI_CATALOG_NAME);
#undef SAPROP
#define SAPROP(name) \
printf ( "\t" #name ": "); \ CheckSafeArrayProperty( guidCiFrmwrkExt, DBPROP_ ## name, cProps, pProps); \ printf ( "\n" );
SAPROP (MACHINE);
#undef SAPROP
printf ( "\n" );
#define SAPROP(name) \
printf ( "\t" #name ": "); \ CheckSafeArrayProperty( guidMsidxsExt, MSIDXSPROP_ ## name, cProps, pProps); \ printf ( "\n" );
SAPROP (ROWSETQUERYSTATUS); SAPROP (COMMAND_LOCALE_STRING); SAPROP (QUERY_RESTRICTION);
#undef SAPROP
}
//
// CheckRowsetProperties - print rowset properties. If IServiceProperties is
// supported, check that the set of properties returned
// by GetPropertyInfo is the same.
//
void CheckRowsetProperties( ULONG cProps, DBPROPSET * pProps, IUnknown * pUnk, BOOL fCheckAllProperties = TRUE ) { IServiceProperties *pSvcProp = 0; SCODE sc = pUnk->QueryInterface(IID_IServiceProperties,(void **) &pSvcProp);
DBPROPSTATUS ExpStatus = fCheckAllProperties ? DBPROPSTATUS_OK : DBPROPSTATUS_CONFLICTING;
if (SUCCEEDED( sc )) { DBPROPINFOSET * pPropInfoSet = 0; ULONG cPropInfoSet = 0; WCHAR * pwszDescriptions = 0;
DBPROPIDSET PropID; PropID.cPropertyIDs = 0; PropID.rgPropertyIDs = 0; PropID.guidPropertySet = DBPROPSET_ROWSETALL;
sc = pSvcProp->GetPropertyInfo( 1, &PropID, &cPropInfoSet, &pPropInfoSet, &pwszDescriptions ); pSvcProp->Release();
if ( FAILED( sc ) ) { LogFail( "IServiceProperties::GetPropertyInfo returned 0x%lx\n", sc ); }
//
// Check that all properties returned by GetProperties are in the
// propinfo structures.
//
for (unsigned iPropSet=0; iPropSet < cProps; iPropSet++) { DBPROP *pDbProp = pProps[iPropSet].rgProperties;
for (unsigned iProp=0; iProp<pProps[iPropSet].cProperties; iProp++) { DBPROPINFO UNALIGNED * pPropInfo = LocatePropertyInfo( pProps[iPropSet].guidPropertySet, pDbProp[iProp].dwPropertyID, cPropInfoSet, pPropInfoSet );
if (0 == pPropInfo) { LogError("Property info record couldn't be found for property %ws %d\n", FormatGuid(pProps[iPropSet].guidPropertySet), pDbProp[iProp].dwPropertyID); cFailures++; continue; } if (pDbProp[iProp].dwStatus != ExpStatus) { LogError("Property status error (%d) for property %ws %d (%ws)\n", pDbProp[iProp].dwStatus, FormatGuid(pProps[iPropSet].guidPropertySet), pDbProp[iProp].dwPropertyID, pPropInfo->pwszDescription); cFailures++; } if (pPropInfo->vtType != pDbProp[iProp].vValue.vt) { LogError("Property type mismatch (%d %d) for property %ws %d (%ws)\n", pPropInfo->vtType, pDbProp[iProp].vValue.vt, FormatGuid(pProps[iPropSet].guidPropertySet), pDbProp[iProp].dwPropertyID, pPropInfo->pwszDescription); cFailures++; } } }
if (fCheckAllProperties) { //
// Check that all properties returned by GetPropertyInfo are in the
// DBPROP structures.
//
for (iPropSet=0; iPropSet<cPropInfoSet; iPropSet++) { DBPROPINFO UNALIGNED *pPropInfo = pPropInfoSet[iPropSet].rgPropertyInfos;
for ( unsigned iProp=0; iProp < pPropInfoSet[iPropSet].cPropertyInfos; iProp++) { DBPROP * pDbProp = LocateProperty( pPropInfoSet[iPropSet].guidPropertySet, pPropInfo[iProp].dwPropertyID, cProps, pProps );
if (0 == pDbProp) { LogError("Property record couldn't be found for property %ws %d\n", FormatGuid(pPropInfoSet[iPropSet].guidPropertySet), pPropInfo[iProp].dwPropertyID); cFailures++; } } } }
//
// Free all the structures in the DBPROPINFOSET
//
for (iPropSet=0; iPropSet<cPropInfoSet; iPropSet++) { DBPROPINFO UNALIGNED *pPropInfo = pPropInfoSet[iPropSet].rgPropertyInfos;
for (unsigned iProp=0; iProp<pPropInfoSet[iPropSet].cPropertyInfos; iProp++) { VARIANT v; RtlCopyMemory( &v, &pPropInfo[iProp].vValues, sizeof v ); VariantClear( &v ); } CoTaskMemFree( pPropInfo ); } CoTaskMemFree( pPropInfoSet ); CoTaskMemFree( pwszDescriptions ); } else {
//
// Check the status of all properties returned by GetProperties.
//
for (unsigned iPropSet=0; iPropSet < cProps; iPropSet++) { DBPROP *pDbProp = pProps[iPropSet].rgProperties;
for (unsigned iProp=0; iProp<pProps[iPropSet].cProperties; iProp++) { if (pDbProp[iProp].dwStatus != ExpStatus) { LogError("Property status error (%d) for property %ws %d\n", pDbProp[iProp].dwStatus, FormatGuid(pProps[iPropSet].guidPropertySet), pDbProp[iProp].dwPropertyID ); cFailures++; }
} } }
if (fVerbose > 1) { PrintRowsetProps (cProps, pProps); printf ("\n"); } for (unsigned i=0; i<cProps; i++) { CoTaskMemFree(pProps[i].rgProperties); } CoTaskMemFree(pProps); }
void CheckPropertiesInError( ICommand* pCmd, BOOL fQuiet ) { if (! fQuiet) LogProgress( " Checking properties in error\n" );
DBPROPSET * pPropInfo = 0; ULONG cPropsets = 0;
DBPROPIDSET PropIDSet; PropIDSet.rgPropertyIDs = 0; PropIDSet.cPropertyIDs = 0; PropIDSet.guidPropertySet = DBPROPSET_PROPERTIESINERROR;
ICommandProperties *pCmdProp = 0; SCODE sc = pCmd->QueryInterface(IID_ICommandProperties,(void **) &pCmdProp);
sc = pCmdProp->GetProperties( 1, &PropIDSet, &cPropsets, &pPropInfo ); pCmdProp->Release(); if ( FAILED( sc ) ) { LogFail( "ICommandProperties::GetProperties returned 0x%lx\n", sc ); } if ( 0 == cPropsets || 0 == pPropInfo ) { LogFail( "ICommandProperties::GetProperties returned no properties\n"); }
if (!fQuiet) fVerbose++; CheckRowsetProperties( cPropsets, pPropInfo, pCmd, FALSE ); if (!fQuiet) fVerbose--; }
void CheckPropertiesOnCommand( ICommand* pCmd, BOOL fQuiet ) { if (! fQuiet) LogProgress( " Verifying rowset properties (from command object)\n" );
DBPROPSET * pPropInfo = 0; ULONG cPropsets = 0;
ICommandProperties *pCmdProp = 0; SCODE sc = pCmd->QueryInterface(IID_ICommandProperties,(void **) &pCmdProp);
sc = pCmdProp->GetProperties( 0, 0, &cPropsets, &pPropInfo );
pCmdProp->Release();
if ( FAILED( sc ) ) { //
// This isn't really kosher, but it helps to avoid spurious (client-side) memory leaks.
//
pCmd->Release(); LogFail( "ICommandProperties::GetProperties returned 0x%lx\n", sc ); }
CheckRowsetProperties( cPropsets, pPropInfo, pCmd ); }
void CheckColumns( IUnknown* pRowset, CDbColumns& rColumns, BOOL fQuiet ) { if (! fQuiet) LogProgress( " Verifying output columns\n" );
DBPROPSET * pPropInfo = 0; ULONG cPropsets = 0;
IRowsetInfo *pIRowInfo = 0; SCODE sc = pRowset->QueryInterface(IID_IRowsetInfo,(void **) &pIRowInfo);
sc = pIRowInfo->GetProperties( 0, 0, &cPropsets, &pPropInfo ); pIRowInfo->Release(); if ( FAILED( sc ) ) { LogFail( "IRowsetInfo::GetProperties returned 0x%lx\n", sc ); }
CheckRowsetProperties( cPropsets, pPropInfo, pRowset );
DBID aDbCols[MAXCOLUMNS];
if (rColumns.Count() > MAXCOLUMNS) { LogError( "TEST ERROR: MAXCOLUMNS is too small\n" ); CantRun(); }
for (ULONG x = 0; x < rColumns.Count(); x++) aDbCols[x] = * ((DBID *) &rColumns.Get(x));
aDbCols[0].uGuid.pguid = &(((DBID *)(&rColumns.Get(0)))->uGuid.guid); if (aDbCols[0].eKind == DBKIND_GUID_PROPID) aDbCols[0].eKind = DBKIND_PGUID_PROPID; else aDbCols[0].eKind = DBKIND_PGUID_NAME;
IColumnsInfo *pIColInfo = 0; sc = pRowset->QueryInterface(IID_IColumnsInfo,(void **) &pIColInfo);
if ( FAILED( sc ) ) { if ( sc == E_NOINTERFACE ) LogError( "IColumnsInfo failed (must be supported for MapColumnIDs), 0x%x\n", sc );
LogError( "IRowset::QI IColumnsInfo failed, 0x%x\n", sc ); cFailures++; }
DBORDINAL aColIds[MAXCOLUMNS]; sc = pIColInfo->MapColumnIDs(rColumns.Count(), aDbCols, aColIds);
if (S_OK != sc) { LogFail( "CheckColumns, IRowset->MapColumnIDs returned 0x%lx\n",sc); }
unsigned iExpCol = 1; for (unsigned i = 0; i < rColumns.Count(); i++) { DBID dbidCol = rColumns.Get(i); if (dbidCol.eKind = DBKIND_GUID_PROPID && dbidCol.uName.ulPropid == PROPID_DBBMK_BOOKMARK && dbidCol.uGuid.guid == guidBmk) { if (aColIds[i] != 0) { LogError( "IRowset->MapColumnIDs returned unexpected column number for bookmark col.\n" ); cFailures++; } } else { if (aColIds[i] != iExpCol) { LogError( "IRowset->MapColumnIDs returned unexpected column number for col. %d\n", i); cFailures++; } iExpCol++; } }
DBORDINAL cColumns = 0; DBCOLUMNINFO *pColumnInfo = 0; WCHAR *pColumnNames = 0;
sc = pIColInfo->GetColumnInfo( &cColumns, &pColumnInfo, &pColumnNames );
if ( FAILED( sc ) ) { LogError( "IColumnsInfo::GetColumnInfo failed, 0x%x\n", sc ); cFailures++; } else { if ( cColumns < rColumns.Count() ) { LogError( "Rowset has too few columns, %d %d\n", cColumns, rColumns.Count() ); cFailures++; } }
if (pColumnInfo != 0) { if (fVerbose > 1) printf("Columns Info:\n" );
for (ULONG iCol = 0; iCol < cColumns; iCol++) { DBCOLUMNINFO &Info = pColumnInfo [iCol];
if ( ( 0 == Info.iOrdinal && ! ( Info.dwFlags & DBCOLUMNFLAGS_ISBOOKMARK) ) || Info.iOrdinal > cColumns) { LogError( "IColumnsInfo->GetColumnInfo returned bad column number %d) for col. %d\n", Info.iOrdinal, iCol); cFailures++; } if (Info.columnid.eKind != DBKIND_GUID_PROPID && Info.columnid.eKind != DBKIND_GUID_NAME && Info.columnid.eKind != DBKIND_PGUID_PROPID && Info.columnid.eKind != DBKIND_PGUID_NAME && Info.columnid.eKind != DBKIND_NAME) { LogError( "IColumnsInfo->GetColumnInfo returned bad column kind %d) for col. %d\n", Info.columnid.eKind, iCol); cFailures++; }
if (fVerbose > 1) { if (Info.columnid.eKind == DBKIND_GUID_PROPID) printf ("(G) %-12li ", Info.columnid.uName.ulPropid); else if (Info.columnid.eKind == DBKIND_GUID_NAME) printf ("(G) '%-10ls' ", Info.columnid.uName.pwszName); else if (Info.columnid.eKind == DBKIND_PGUID_PROPID) printf ("(PG) %-12li ", Info.columnid.uName.ulPropid); else if (Info.columnid.eKind == DBKIND_PGUID_NAME) printf ("(PG) '%-10ls' ", Info.columnid.uName.pwszName); else if (Info.columnid.eKind == DBKIND_NAME) printf ("'%-14ls' ", Info.columnid.uName.pwszName); else printf ("BAD NAME ");
printf ("'%-14ls' %2lu %6s %2lu", Info.pwszName, Info.iOrdinal, DBTYPE_Tag (Info.wType), Info.ulColumnSize);
printf ("\n "); PrintColumnFlags (Info.dwFlags);
printf ("\n"); } } CoTaskMemFree(pColumnInfo); CoTaskMemFree(pColumnNames); }
IColumnsRowset *pIColRowset = 0;
sc = pRowset->QueryInterface(IID_IColumnsRowset,(void **) &pIColRowset );
if ( FAILED( sc ) && sc != E_NOINTERFACE ) { LogError( "IRowset::qi for IColumnsRowset failed, 0x%x\n", sc ); cFailures++; }
if (0 == pIColRowset && 0 == pIColInfo) { LogError( "At least one of IColumnsInfo and IColumnsRowset " "must be implemented\n" ); cFailures++; }
if (pIColRowset) { IRowset *pRowsetCols = 0; SCODE scCC = pIColRowset->GetColumnsRowset(0, 0, 0, IID_IRowset, 0, 0, (IUnknown**)&pRowsetCols);
if (FAILED(scCC)) { LogError( "IColumnsRowset::GetColumnsRowset failed, 0x%x\n", scCC ); cFailures++; }
if (SUCCEEDED(scCC)) pRowsetCols->Release(); }
if (pIColInfo) { pIColInfo->Release(); pIColInfo = 0; } if ( pIColRowset ) { pIColRowset->Release(); pIColRowset = 0; }
} //CheckColumns
//+-------------------------------------------------------------------------
//
// Function: BasicTest, public
//
// Synopsis: Test basic cursor functionality
//
// Arguments: [pCursor] - a pointer to an IRowset* to be tested.
// [fSequential] - if TRUE, the pCursor will not support
// IRowsetLocate, etc.
// [hChapt] - chapter pointer
// [cCols] - # of columns over which to test
//
// Returns: Nothing
//
// Notes: The passed in cursor is assumed to be set up with the
// usual column bindings. It is also assumed that the
// query has not necesarily completed.
//
// History: 26 Sep 94 AlanW Created from DownLevel test
// 11 Nov 94 Alanw Converted for phase 3
//
//--------------------------------------------------------------------------
void BasicTest( IRowset* pCursor, BOOL fSequential, HCHAPTER hChapt, unsigned cCols, BOOL fByRef, ICommandTree * pCmdTree ) { int fFailed = 0; DBCOUNTITEM cRows = 0; IRowsetScroll * pIRowsetScroll = 0; BOOL fChaptered = GetBooleanProperty( pCursor, DBPROP_IChapteredRowset );
if (cCols != cBasicTestCols && cCols != cBasicTestCols-1) LogFail( "TEST ERROR - bad cCols (%d) passed to BasicTest\n", cCols );
SCODE sc = pCursor->QueryInterface(IID_IRowsetScroll,(void **) &pIRowsetScroll );
if ( FAILED( sc ) && sc != E_NOINTERFACE ) { LogError( "IRowset::qi for IRowsetScroll failed, 0x%x\n", sc ); cFailures++; }
if ( fSequential ) { if (0 != pIRowsetScroll ) { LogError( "Sequential cursor supports IRowsetScroll\n" ); cFailures++; } } else { if (0 == pIRowsetScroll ) { LogError( "Non-sequential cursor does not support IRowsetScroll\n" ); cFailures++; } else { sc = pIRowsetScroll->GetApproximatePosition(hChapt, 0,0, 0, &cRows);
if ( FAILED( sc ) ) { LogError( "IRowset->GetApproximatePosition returned 0x%lx\n", sc ); cFailures++; }
if ( cRows == 0 ) { LogError( "Query failed to return data\n" ); pIRowsetScroll->Release(); pCursor->Release(); Fail(); } } }
//
// Patch the column index numbers with true numbers
//
DBID aDbCols[cBasicTestCols]; aDbCols[0] = psClassid; aDbCols[1] = psSize; aDbCols[2] = psWriteTime; aDbCols[3] = psAttr; aDbCols[4] = psName; aDbCols[5] = psPath; aDbCols[6] = psSelf;
IUnknown * pAccessor = (IUnknown *) pCursor; // hAccessor must be created on rowset
// to be used with rowset->GetData below
if (fByRef) { aBasicTestCols[5].dwMemOwner = DBMEMOWNER_PROVIDEROWNED; } else { aBasicTestCols[5].dwMemOwner = DBMEMOWNER_CLIENTOWNED; } HACCESSOR hAccessor = MapColumns( pAccessor, cCols, aBasicTestCols, aDbCols, fByRef );
DBID aDbAltCols[cBasicAltCols]; aDbAltCols[0] = psSize; aDbAltCols[1] = psWriteTime; aDbAltCols[2] = psWriteTime; aDbAltCols[3] = psWriteTime;
HACCESSOR hAccessor2 = MapColumns( pAccessor, cBasicAltCols, aBasicAltCols, aDbAltCols, fByRef );
#if defined( DO_NOTIFICATION )
IConnectionPoint *pConnectionPoint = 0; DWORD dwAdviseID = 0;
CTestWatchNotify Notify;
if ( ! fSequential ) { Notify.DoChecking(TRUE);
//
// Get the connection point container
//
IConnectionPointContainer *pConnectionPointContainer = 0; sc = pCursor->QueryInterface(IID_IConnectionPointContainer, (void **) &pConnectionPointContainer); if (FAILED(sc)) { LogError( "IRowset->QI for IConnectionPointContainer failed: 0x%x\n", sc ); pCursor->Release(); Fail(); }
//
// Make a connection point from the connection point container
//
sc = pConnectionPointContainer->FindConnectionPoint( IID_IRowsetWatchNotify, &pConnectionPoint);
if (FAILED(sc) && CONNECT_E_NOCONNECTION != sc ) { LogError( "FindConnectionPoint failed: 0x%x\n",sc ); pCursor->Release(); Fail(); }
pConnectionPointContainer->Release();
if (0 != pConnectionPoint) { //
// Give a callback object to the connection point
//
sc = pConnectionPoint->Advise((IUnknown *) &Notify, &dwAdviseID); if (FAILED(sc)) { LogError( "IConnectionPoint->Advise failed: 0x%x\n",sc ); pConnectionPoint->Release(); pCursor->Release(); Fail(); } } } #endif // DO_NOTIFICATION
DBCOUNTITEM totalRowsFetched = 0; DBCOUNTITEM cRowsReturned = 0; HROW ahRows[10]; HROW* phRows = ahRows; LONGLONG PrevFileSize = 0x7fffffffffffffff;
//
// Try passing chapters to non-chaptered rowsets.
// This causes an exception, so just do it once for each case.
//
static BOOL fTriedChaptOnNonChaptered = FALSE;
#if 0 // NOTE: null chapters work on chaptered rowsets!
static BOOL fTriedNoChaptOnChaptered = FALSE; if ( !fTriedNoChaptOnChaptered && 0 != hChapt ) { fTriedNoChaptOnChaptered = TRUE; sc = pCursor->GetNextRows(DB_NULL_HCHAPTER, 0, 10, &cRowsReturned, &phRows); if (!FAILED(sc)) LogFail("chaptered IRowset->GetNextRows should have failed\n"); } #endif 0
if ( !fTriedChaptOnNonChaptered && (0 == hChapt) ) { fTriedChaptOnNonChaptered = TRUE; sc = pCursor->GetNextRows(DBCHP_FIRST, 0, 10, &cRowsReturned, &phRows); if (!FAILED(sc)) LogFail("unchaptered IRowset->GetNextRows should have failed\n"); }
do { sc = pCursor->GetNextRows(hChapt, 0, 10, &cRowsReturned, &phRows);
if ( FAILED( sc ) ) { LogError( "IRowset->GetNextRows returned 0x%x\n", sc ); pCursor->Release(); Fail(); }
if (sc != DB_S_ENDOFROWSET && cRowsReturned != 10) { LogError( "IRowset->GetNextRows returned %d of %d rows," " status (%x) != DB_S_ENDOFROWSET\n", cRowsReturned, 10, sc); #if defined (UNIT_TEST)
cFailures++; #else // defined(UNIT_TEST)
pCursor->Release(); Fail(); #endif // defined(UNIT_TEST)
}
totalRowsFetched += cRowsReturned;
if ( (0 != pIRowsetScroll ) && (totalRowsFetched > cRows) ) { //
// check that no more rows have been added while we were
// fetching.
//
LogProgress("Checking for expansion of result set\n");
SCODE sc1 = pIRowsetScroll->GetApproximatePosition(hChapt, 0,0, 0, &cRows);
if ( totalRowsFetched > cRows ) { LogError("Fetched more rows than exist in the result set, %d %d\n", totalRowsFetched, cRows); cFailures++; } } //
// Make sure the hits are sorted by size and that the query
// really was shallow and that the length fields are correct.
//
unsigned i; for (i = 0; i < cRowsReturned; i++) { SBasicTest Row; Row.pIPSStorage = 0;
SCODE sc1 = pCursor->GetData(ahRows[i],hAccessor,&Row);
if ( FAILED( sc1 ) ) LogFail( "IRowset->GetData returned 0x%x\n", sc1 );
LONGLONG size = Row.size; if ( PrevFileSize < size && ( ! fChaptered || hChapt != DB_NULL_HCHAPTER) ) LogFail("Hitset not sorted by filesize\n");
if (wcsstr( Row.pwcPath, L"system32\\drivers\\" ) || wcsstr( Row.pwcPath, L"SYSTEM32\\DRIVERS\\" ) || wcsstr( Row.pwcPath, L"System32\\Drivers\\" )) LogFail("Query wasn't shallow as expected\n");
if ( Row.sClsid == DBSTATUS_S_OK && Row.cbClsid != sizeof CLSID ) LogFail("length of clsid column not correct: %d\n", Row.cbClsid);
if ( Row.sSize != DBSTATUS_S_OK || Row.cbSize != sizeof LONGLONG ) LogFail("status or length of size column not correct: %d\n", Row.cbSize);
if ( Row.sWriteTime != DBSTATUS_S_OK || Row.cbWriteTime != sizeof LONGLONG) LogFail("status or length of time column not correct: %d\n", Row.cbWriteTime);
if ( Row.sAttr != DBSTATUS_S_OK || Row.cbAttr != sizeof ULONG) LogFail("length of attr column not correct: %d\n", Row.cbAttr);
if ( Row.sName == DBSTATUS_S_OK && Row.cbName != wcslen(Row.awcName) * sizeof (WCHAR) ) LogFail( "length of name column 0x%x not consistent with data 0x%x\n", Row.cbName, wcslen(Row.awcName) * sizeof WCHAR );
if ( Row.sPath == DBSTATUS_S_OK && Row.cbPath != (wcslen(Row.pwcPath) * sizeof (WCHAR)) ) LogFail("length of path column not consistent with data\n");
if ( !fByRef ) CoTaskMemFree(Row.pwcPath);
if ( 0 != Row.pIPSStorage ) { Row.pIPSStorage->Release(); Row.pIPSStorage = 0; }
SBasicAltTest AltRow; SCODE sc2 = pCursor->GetData(ahRows[i], hAccessor2, &AltRow);
if ( FAILED( sc2 ) ) LogFail( "IRowset->GetData returned 0x%x\n", sc2 );
if ( AltRow.sSize != DBSTATUS_S_OK || AltRow.cbSize != sizeof AltRow.Size ) LogFail("status or length of alt size column not correct: %d\n", AltRow.cbSize);
if ( AltRow.Size != Row.size ) LogFail("size column doesn't compare in alt. accessor\n");
//
// Check time conversions
//
FILETIME LocalFTime; SYSTEMTIME SysTime;
FileTimeToSystemTime((FILETIME *) &(Row.writeTime), &SysTime);
if ( AltRow.sWriteTime1 != DBSTATUS_S_OK || AltRow.cbWriteTime1 != sizeof AltRow.writeTime1) LogFail("status or length of writeTime1 column not correct: %d\n", AltRow.cbWriteTime1);
if ( AltRow.sWriteTime2 != DBSTATUS_S_OK || AltRow.cbWriteTime2 != sizeof AltRow.writeTime2) LogFail("status or length of writeTime2 column not correct: %d\n", AltRow.cbWriteTime2);
if ( AltRow.sWriteTime3 != DBSTATUS_S_OK || AltRow.cbWriteTime3 != sizeof AltRow.writeTime3) LogFail("status or length of writeTime3 column not correct: %d\n", AltRow.cbWriteTime3);
if ( SysTime.wYear != AltRow.writeTime1.year || SysTime.wMonth != AltRow.writeTime1.month || SysTime.wDay != AltRow.writeTime1.day) LogFail("Write time 1 mismatch\n");
if ( SysTime.wHour != AltRow.writeTime2.hour || SysTime.wMinute != AltRow.writeTime2.minute || SysTime.wSecond != AltRow.writeTime2.second) LogFail("Write time 2 mismatch\n");
if ( SysTime.wYear != AltRow.writeTime3.year || SysTime.wMonth != AltRow.writeTime3.month || SysTime.wDay != AltRow.writeTime3.day || SysTime.wHour != AltRow.writeTime3.hour || SysTime.wMinute != AltRow.writeTime3.minute || SysTime.wSecond != AltRow.writeTime3.second || SysTime.wMilliseconds != AltRow.writeTime3.fraction/1000000) LogFail("Write time 3 mismatch\n");
PrevFileSize = size; }
if (fVerbose > 1) { for (i = 0; i < cRowsReturned; i++) { SBasicTest Row; Row.pIPSStorage = 0;
SCODE sc1 = pCursor->GetData(ahRows[i],hAccessor,&Row);
if ( FAILED( sc1 ) ) { LogError( "IRowset->GetData returned 0x%x\n", sc1 ); pCursor->Release(); Fail(); }
//
// print name, attributes and size
//
printf( "\t%-16.16ws%04x\t%7d\t", Row.awcName, Row.attr, (ULONG) Row.size );
//
// print file mod. time
//
FILETIME LocalFTime; SYSTEMTIME SysTime;
FileTimeToLocalFileTime((FILETIME *) &(Row.writeTime), &LocalFTime); FileTimeToSystemTime(&LocalFTime, &SysTime);
printf("%02d/%02d/%02d %2d:%02d:%02d\n", SysTime.wMonth, SysTime.wDay, SysTime.wYear % 100, SysTime.wHour, SysTime.wMinute, SysTime.wSecond);
if ( !fByRef ) CoTaskMemFree(Row.pwcPath);
if (0 != Row.pIPSStorage ) { Row.pIPSStorage->Release(); Row.pIPSStorage = 0; } } }
if (0 != cRowsReturned) { SCODE sc1 = pCursor->ReleaseRows(cRowsReturned, ahRows, 0, 0, 0); if ( FAILED( sc1 ) ) { LogError( "IRowset->ReleaseRows returned 0x%x\n", sc1 ); pCursor->Release(); Fail(); } cRowsReturned = 0; }
} while (SUCCEEDED(sc) && sc != DB_S_ENDOFROWSET);
if (0 != cRowsReturned) { SCODE sc1 = pCursor->ReleaseRows(cRowsReturned, ahRows, 0, 0, 0); if ( FAILED( sc1 ) ) { LogError( "IRowset->ReleaseRows returned 0x%x\n", sc1 ); pCursor->Release(); Fail(); } }
if ( 0 == totalRowsFetched && 0 != hChapt ) LogFail("Chapter had no rows for GetNextRows()\n");
ReleaseAccessor( pAccessor, hAccessor); ReleaseAccessor( pAccessor, hAccessor2);
#if defined( DO_NOTIFICATION )
if ( ! fSequential && 0 != pConnectionPoint ) { NotificationTest();
//
// Clean up notification stuff
//
sc = pConnectionPoint->Unadvise(dwAdviseID);
if (S_OK != sc) { LogError( "IConnectionPoint->Unadvise returned 0x%lx\n",sc); pCursor->Release(); Fail(); }
pConnectionPoint->Release(); //Notify.Release();
} #endif // DO_NOTIFICATION
if (0 != pIRowsetScroll ) { pIRowsetScroll->Release(); pIRowsetScroll = 0; }
#if !defined(UNIT_TEST)
if (cFailures) { pCursor->Release(); Fail(); } #endif // !UNIT_TEST
} //BasicTest
//+-------------------------------------------------------------------------
//
// Function: BackwardsFetchTest, public
//
// Synopsis: Test backwards fetching
//
// Arguments: [pRowset] - IRowset to be tested
//
// History: 03-Sep-97 SitaramR Created
//
//--------------------------------------------------------------------------
void BackwardsFetchTest( IRowset* pRowset ) { //
// Patch the column index numbers with true numbers
//
DBID aDbCols[cBasicTestCols]; aDbCols[0] = psClassid; aDbCols[1] = psSize; aDbCols[2] = psWriteTime; aDbCols[3] = psAttr; aDbCols[4] = psName; aDbCols[5] = psPath; aDbCols[6] = psSelf;
IUnknown * pAccessor = (IUnknown *) pRowset; // hAccessor must be created on rowset
// to be used with rowset->GetData below
aBasicTestCols[5].dwMemOwner = DBMEMOWNER_PROVIDEROWNED;
HACCESSOR hAccessor = MapColumns( pAccessor, cBasicTestCols, aBasicTestCols, aDbCols, TRUE );
DBCOUNTITEM cRowsReturned = 0; HROW ahRows[10]; HROW* phRows = ahRows;
//
// Backwards fetch for GetNextRows
//
SCODE sc = pRowset->RestartPosition( 0 ); if ( FAILED( sc ) ) { LogError( "IRowset->RestartPosition returned 0x%x\n", sc ); pRowset->Release(); Fail(); }
sc = pRowset->GetNextRows(0, 9, -9, &cRowsReturned, &phRows);
if ( FAILED( sc ) ) { LogError( "IRowset->GetNextRows returned 0x%x\n", sc ); pRowset->Release(); Fail(); }
if ( cRowsReturned != 9 ) { LogError( "IRowset->GetNextRows returned %d of %d rows," " status (%x) != DB_S_ENDOFROWSET\n", cRowsReturned, 10, sc); #if defined (UNIT_TEST)
cFailures++; #else
pRowset->Release(); Fail(); #endif
}
//
// Check data of some of the fields
//
for ( unsigned i = 0; i < cRowsReturned; i++) { SBasicTest Row; Row.pIPSStorage = 0;
SCODE sc1 = pRowset->GetData(ahRows[i],hAccessor,&Row);
if ( FAILED( sc1 ) ) LogFail( "IRowset->GetData returned 0x%x\n", sc1 );
if (wcsstr( Row.pwcPath, L"system32\\drivers\\" ) || wcsstr( Row.pwcPath, L"SYSTEM32\\DRIVERS\\" ) || wcsstr( Row.pwcPath, L"System32\\Drivers\\" )) LogFail("Query wasn't shallow as expected\n");
if ( Row.sClsid == DBSTATUS_S_OK && Row.cbClsid != sizeof CLSID ) LogFail("length of clsid column not correct: %d\n", Row.cbClsid);
if ( Row.sSize != DBSTATUS_S_OK || Row.cbSize != sizeof LONGLONG ) LogFail("status or length of size column not correct: %d\n", Row.cbSize); }
if (0 != cRowsReturned) { SCODE sc1 = pRowset->ReleaseRows(cRowsReturned, ahRows, 0, 0, 0); if ( FAILED( sc1 ) ) { LogError( "IRowset->ReleaseRows returned 0x%x\n", sc1 ); pRowset->Release(); Fail(); } }
sc = pRowset->RestartPosition( 0 ); if ( FAILED( sc ) ) { LogError( "IRowset->RestartPosition returned 0x%x\n", sc ); pRowset->Release(); Fail(); }
//
// Backwards fetch for GetRowsAt
//
IRowsetLocate *pRowsetLocate = 0; sc = pRowset->QueryInterface(IID_IRowsetLocate,(void **) &pRowsetLocate );
if ( FAILED( sc ) && sc != E_NOINTERFACE ) { LogError( "IRowset::qi for IRowsetLocate failed, 0x%x\n", sc ); #if defined (UNIT_TEST)
cFailures++; #else
pRowset->Release(); Fail(); #endif
}
sc = pRowsetLocate->GetRowsAt(0, 0, 1, &bmkFirst, 9, -10, &cRowsReturned, &phRows);
if ( FAILED( sc ) ) { LogError( "IRowsetLocate->GetRowsAt returned 0x%x\n", sc ); pRowsetLocate->Release(); Fail(); }
if ( cRowsReturned != 10 ) { LogError( "IRowset->GetRowsAt returned %d of %d rows," " status (%x) != DB_S_ENDOFROWSET\n", cRowsReturned, 10, sc); #if defined (UNIT_TEST)
cFailures++; #else
pRowsetLocate->Release(); Fail(); #endif
}
//
// Check data of some of the fields
//
for ( i = 0; i < cRowsReturned; i++) { SBasicTest Row; Row.pIPSStorage = 0;
SCODE sc1 = pRowsetLocate->GetData(ahRows[i],hAccessor,&Row);
if ( FAILED( sc1 ) ) LogFail( "IRowset->GetData returned 0x%x\n", sc1 );
if (wcsstr( Row.pwcPath, L"system32\\drivers\\" ) || wcsstr( Row.pwcPath, L"SYSTEM32\\DRIVERS\\" ) || wcsstr( Row.pwcPath, L"System32\\Drivers\\" )) LogFail("Query wasn't shallow as expected\n");
if ( Row.sClsid == DBSTATUS_S_OK && Row.cbClsid != sizeof CLSID ) LogFail("length of clsid column not correct: %d\n", Row.cbClsid);
if ( Row.sSize != DBSTATUS_S_OK || Row.cbSize != sizeof LONGLONG ) LogFail("status or length of size column not correct: %d\n", Row.cbSize); }
HROW ahRows2[10]; HROW ahRows3[10]; DBCOUNTITEM cRowsReturned2; HROW *phRows2 = ahRows2;
//
// Forward fetch rows 1 to 10 for CheckHrowIdentity comparison below
//
sc = pRowsetLocate->GetRowsAt(0, 0, 1, &bmkFirst, 0, 10, &cRowsReturned2, &phRows2);
if ( FAILED( sc ) ) { LogError( "IRowsetLocate->GetRowsAt returned 0x%x\n", sc ); pRowsetLocate->Release(); Fail(); }
if ( cRowsReturned2 != 10 ) { LogError( "IRowset->GetRowsAt returned %d of %d rows," " status (%x) != DB_S_ENDOFROWSET\n", cRowsReturned, 10, sc); #if defined (UNIT_TEST)
cFailures++; #else
pRowsetLocate->Release(); Fail(); #endif
}
//
// Reverse ahRows2 into ahRows3 in preparation for CheckHrowIdentity
// comparison below.
//
for ( i=0; i<10; i++ ) ahRows3[i] = ahRows2[9-i];
//
// Check that forward fetch of rows 1 thru 10 and backwards fetch of
// rows 10 thru 1 (and then reversed) are the same.
//
int fFailed = CheckHrowIdentity( 0, 0, 10, ahRows, 10, ahRows3 ); if ( fFailed > 0 ) { LogError( "Backwards fetch CheckHrowIdentity returned 0x%x\n", fFailed ); pRowsetLocate->Release(); Fail(); }
if (0 != cRowsReturned2) { SCODE sc1 = pRowsetLocate->ReleaseRows(cRowsReturned2, ahRows2, 0, 0, 0); if ( FAILED( sc1 ) ) { LogError( "IRowset->ReleaseRows returned 0x%x\n", sc1 ); pRowsetLocate->Release(); Fail(); } }
if (0 != cRowsReturned) { SCODE sc1 = pRowsetLocate->ReleaseRows(cRowsReturned, ahRows, 0, 0, 0); if ( FAILED( sc1 ) ) { LogError( "IRowset->ReleaseRows returned 0x%x\n", sc1 ); pRowsetLocate->Release(); Fail(); } }
pRowsetLocate->Release();
//
// Backwards fetch for GetRowsAtRatio
//
IRowsetScroll *pRowsetScroll = 0; sc = pRowset->QueryInterface(IID_IRowsetScroll,(void **) &pRowsetScroll );
if ( FAILED( sc ) && sc != E_NOINTERFACE ) { LogError( "IRowset::qi for IRowsetScroll failed, 0x%x\n", sc ); #if defined (UNIT_TEST)
cFailures++; #else
pRowset->Release(); Fail(); #endif
}
sc = pRowsetScroll->GetRowsAtRatio(0, 0, 50, 100, -9, &cRowsReturned, &phRows);
if ( FAILED( sc ) ) { LogError( "IRowsetScroll->GetRowsAtRatio returned 0x%x\n", sc ); pRowsetScroll->Release(); Fail(); }
//
// Check data of some of the fields
//
for ( i = 0; i < cRowsReturned; i++) { SBasicTest Row; Row.pIPSStorage = 0;
SCODE sc1 = pRowsetScroll->GetData(ahRows[i],hAccessor,&Row);
if ( FAILED( sc1 ) ) LogFail( "IRowsetScroll->GetData returned 0x%x\n", sc1 );
if (wcsstr( Row.pwcPath, L"system32\\drivers\\" ) || wcsstr( Row.pwcPath, L"SYSTEM32\\DRIVERS\\" ) || wcsstr( Row.pwcPath, L"System32\\Drivers\\" )) LogFail("Query wasn't shallow as expected\n");
if ( Row.sClsid == DBSTATUS_S_OK && Row.cbClsid != sizeof CLSID ) LogFail("length of clsid column not correct: %d\n", Row.cbClsid);
if ( Row.sSize != DBSTATUS_S_OK || Row.cbSize != sizeof LONGLONG ) LogFail("status or length of size column not correct: %d\n", Row.cbSize); }
if (0 != cRowsReturned) { SCODE sc1 = pRowsetScroll->ReleaseRows(cRowsReturned, ahRows, 0, 0, 0); if ( FAILED( sc1 ) ) { LogError( "IRowsetScroll->ReleaseRows returned 0x%x\n", sc1 ); pRowsetScroll->Release(); Fail(); } }
pRowsetScroll->Release(); ReleaseAccessor( pAccessor, hAccessor); }
//+-------------------------------------------------------------------------
//
// Function: FetchTest, public
//
// Synopsis: Test GetNextRows variations
//
// Arguments: [pRowset] - a pointer to an IRowset to be tested.
//
// Returns: Nothing
//
// Notes: The passed in Rowset is assumed to be set up with the
// usual column bindings and is capable of supporting
// Rowset movement via bookmarks in GetRowsAt.
//
// History: 30 Sep 94 AlanW Created from BasicTest test
//
// ToDo: add tests:
// backward fetch
// caller/callee allocated hrow array
// fetch of 0 rows
//
//--------------------------------------------------------------------------
void FetchTest( IRowset* pRowset ) { LogProgress( " Row fetch test\n" );
int fFailed = 0; HROW hBad = (HROW) 0xDEDEDEDE; ULONG cRefsLeft = 0; DBROWSTATUS RowStatus = 0;
// Try releasing a bad HROW (bug #7449)
SCODE sc = pRowset->ReleaseRows( 1, &hBad, 0, &cRefsLeft, &RowStatus ); if (sc != DB_E_ERRORSOCCURRED || RowStatus != DBROWSTATUS_E_INVALID) { LogError( "ReleaseRows of bad handle returned %x, %x\n", sc, RowStatus ); fFailed++; }
cFailures += fFailed; #if !defined(UNIT_TEST)
if (fFailed) { pRowset->Release(); Fail(); } #endif // !UNIT_TEST
} //FetchTest
//+-------------------------------------------------------------------------
//
// Function: BindingTest, public
//
// Synopsis: Test some of the many possible error paths in CreateAccessor
//
// Arguments: [pCursor] - a pointer to an IRowset* to be tested.
//
// Returns: Nothing
//
// Notes: The helper function TryBinding does much of the work,
// trying a couple of different scenarios with each input
// binding set, checking results and reporting errors.
//
// History: 02 Jul 94 AlanW Created
//
//--------------------------------------------------------------------------
static DBBINDING aTestBindings[] = { { 0, // binding 0
0, 0, 0, 0,0,0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, sizeof (VARIANT), 0, DBTYPE_VARIANT, 0,0}, { 2, // binding 1
0, 0, 0, 0,0,0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, 0, 0, DBTYPE_I8, 0,0}, { 2, // binding 2
2 * sizeof (VARIANT), 0, 0, 0,0,0, (DBPART) 0x01000000, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, sizeof (VARIANT), 0, DBTYPE_VARIANT, 0,0}, { 2, // binding 3
3 * sizeof (VARIANT), 0, 0, 0,0,0, DBPART_STATUS, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, sizeof (VARIANT), 0, DBTYPE_VARIANT, 0,0}, { 2, // binding 4
7, 0, 0, 0,0,0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, 1, 0, DBTYPE_I8, 0,0}, { 1, // binding 5
0, 0, 0, 0,0,0, DBPART_VALUE|DBPART_STATUS, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, 1, 0, DBTYPE_I8, 0,0}, { 1, // binding 6
0, 0, 0, 0,0,0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, 1, 0, DBTYPE_GUID, 0,0}, { 1, // binding 7
0, 0, 0, 0,0,0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, 1, 0, DBTYPE_GUID, 0,0}, { 1, // binding 8
0, 0, 0, (ITypeInfo *) 1,0,0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, 1, 0, DBTYPE_VARIANT, 0,0}, { 1, // binding 9
0, 0, 0, 0,0,0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, 1, 0, DBTYPE_GUID, 0,0}, { 1, // binding 10
0, 0, 0, 0,0,0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, 1, 0, DBTYPE_I4|DBTYPE_BYREF, 0,0}, { 1, // binding 11
0, 20, 0, 0,0,0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, 1, DBBINDFLAG_HTML, DBTYPE_WSTR, 0,0}, { 1, // binding 12
0, 20, 0, 0,0,0, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, 1, 0x20, DBTYPE_WSTR, 0,0}, };
int TryBinding( int iTest, IAccessor * pIAccessor, DBACCESSORFLAGS dwAccessorFlags, ULONG cBindings, ULONG iFirstBinding, SCODE scExpected, DBBINDSTATUS FailStatus = DBBINDSTATUS_OK) { HACCESSOR hAccessor = 0; DBBINDSTATUS aBindStatus[20]; SCODE sc = pIAccessor->CreateAccessor( dwAccessorFlags, cBindings, &(aTestBindings[iFirstBinding]), 0, &hAccessor, aBindStatus );
int iRet = 0;
if (scExpected != sc) { LogError( "IAccessor->CreateAccessor test %d returned 0x%x (expected 0x%x)\n", iTest, sc, scExpected ); iRet = 1; }
if ((SUCCEEDED(sc) || DB_E_ERRORSOCCURRED == sc) && DBBINDSTATUS_OK != FailStatus) { for (unsigned i=0; i<cBindings; i++) { if (aBindStatus[i] == FailStatus) break; }
if (i == cBindings) { LogError( "IAccessor->CreateAccessor test %d returned DBBINDSTATUS 0x%x (expected 0x%x)\n", iTest, aBindStatus[0], FailStatus ); iRet = 1; } }
if (! FAILED(sc)) pIAccessor->ReleaseAccessor( hAccessor, 0);
return iRet; } //TryBinding
void BindingTest( IUnknown* pUnk, BOOL fICommand, BOOL fSequential ) { LogProgress( " Accessor binding test\n" );
int fFailed = 0; DBACCESSORFLAGS StdFlags = DBACCESSOR_ROWDATA;
IAccessor * pIAcc = 0;
SCODE sc = pUnk->QueryInterface( IID_IAccessor, (void **)&pIAcc); if ( FAILED( sc ) || pIAcc == 0 ) { LogFail( "QueryInterface for IAccessor returned 0x%lx\n", sc ); }
// regr test for bug #71492, check that we can QI to IConvertType
// from IAccessor
IConvertType * pICvtType = 0; sc = pUnk->QueryInterface( IID_IConvertType, (void **)&pICvtType); if ( FAILED( sc ) || pICvtType == 0 ) { LogError( "QueryInterface for IConvertType returned 0x%lx\n", sc ); fFailed++; } else { pICvtType->Release(); }
sc = pIAcc->QueryInterface( IID_IConvertType, (void **)&pICvtType); if ( FAILED( sc ) || pICvtType == 0 ) { LogError( "QueryInterface for IConvertType from accessor returned 0x%lx\n", sc ); fFailed++; } else { pICvtType->Release(); }
SCODE scExpected = (fSequential & !fICommand) ? DB_E_ERRORSOCCURRED : S_OK; DBBINDSTATUS BindStatExp = (fSequential & !fICommand) ? DBBINDSTATUS_BADORDINAL : DBBINDSTATUS_OK;
// Test the return value for a bad column ordinal
aTestBindings[0].iOrdinal = 0; fFailed += TryBinding( 1, pIAcc, StdFlags, 1, 0, scExpected, BindStatExp);
scExpected = fICommand ? S_OK : DB_E_ERRORSOCCURRED; BindStatExp = fICommand ? DBBINDSTATUS_OK : DBBINDSTATUS_BADORDINAL;
// Test the return value for another bad column ordinal
aTestBindings[0].iOrdinal = 1000; fFailed += TryBinding( 2, pIAcc, StdFlags, 1, 0, scExpected, BindStatExp);
// Don't allow room for the I8 to be returned
// But that's ok! fixed-len fields are allowed to pass bogus
// values for length
fFailed += TryBinding( 3, pIAcc, StdFlags, 1, 1, S_OK );
// bogus accessor flags (no bits on, and unused bits turned on)
fFailed += TryBinding( 4, pIAcc, 0, 1, 1, DB_E_BADACCESSORFLAGS ); fFailed += TryBinding( 5, pIAcc, DBACCESSOR_ROWDATA|(DBACCESSOR_OPTIMIZED<<1), 1, 1, DB_E_BADACCESSORFLAGS );
// null binding array
fFailed += TryBinding( 6, pIAcc, StdFlags, 0, 1, DB_E_NULLACCESSORNOTSUPPORTED );
// ofs doesn't support Param accessors (yet)
fFailed += TryBinding( 7, pIAcc, DBACCESSOR_PARAMETERDATA, 1, 1, DB_E_BADACCESSORFLAGS ); //E_NOTIMPL );
#if 0 // Replace these with some other test...
// ofs doesn't support writable accessors
fFailed += TryBinding( 8, pIAcc, DBACCESSOR_ROWDATA, 1, 1, DB_E_ACCESSVIOLATION ); #endif //
// ofs doesn't support passbyref accessors
fFailed += TryBinding( 9, pIAcc, DBACCESSOR_ROWDATA|DBACCESSOR_PASSBYREF, 1, 1, DB_E_BYREFACCESSORNOTSUPPORTED );
// bogus dbcolumnpart -- none of the valid bits turned on
fFailed += TryBinding( 10, pIAcc, StdFlags, 1, 2, DB_E_ERRORSOCCURRED, DBBINDSTATUS_BADBINDINFO );
// just ask for status -- not for data too
fFailed += TryBinding( 11, pIAcc, StdFlags, 1, 3, S_OK );
// bad alignment for output data -- No longer fatal.
fFailed += TryBinding( 12, pIAcc, StdFlags, 1, 4, S_OK );
// overlap value and status output fields
fFailed += TryBinding( 13, pIAcc, StdFlags, 1, 5, DB_E_ERRORSOCCURRED, DBBINDSTATUS_BADBINDINFO );
// make sure each of the two duplicate bindings used below is ok by itself
fFailed += TryBinding( 14, pIAcc, StdFlags, 1, 6, S_OK ); fFailed += TryBinding( 15, pIAcc, StdFlags, 1, 7, S_OK );
// overlap value fields in two bindings
fFailed += TryBinding( 16, pIAcc, StdFlags, 2, 6, DB_E_ERRORSOCCURRED, DBBINDSTATUS_BADBINDINFO );
// supply ITypeInfo field
fFailed += TryBinding( 17, pIAcc, StdFlags, 1, 8, DB_E_ERRORSOCCURRED, DBBINDSTATUS_BADBINDINFO );
// direct bind to GUID type
fFailed += TryBinding( 18, pIAcc, StdFlags, 1, 9, S_OK );
// unsupported byref binding
fFailed += TryBinding( 19, pIAcc, StdFlags, 1, 10, DB_E_ERRORSOCCURRED, DBBINDSTATUS_BADBINDINFO ); //danleg changed hraccess... UNSUPPORTEDCONVERSION );
// unsupported HTML flag
fFailed += TryBinding( 20, pIAcc, StdFlags, 1, 11, DB_E_ERRORSOCCURRED, DBBINDSTATUS_BADBINDINFO );
// unknown dwFlags field
fFailed += TryBinding( 21, pIAcc, StdFlags, 1, 12, DB_E_ERRORSOCCURRED, DBBINDSTATUS_BADBINDINFO );
cFailures += fFailed; pIAcc->Release();
#if !defined(UNIT_TEST)
if (fFailed) { pUnk->Release(); Fail(); } #endif // !UNIT_TEST
} //BindingTest
void TestIAccessorOnCommand( ICommandTree * pCmdTree ) { DBID aDbCols[cBasicTestCols]; aDbCols[0] = psClassid; aDbCols[1] = psSize; aDbCols[2] = psWriteTime; aDbCols[3] = psAttr; aDbCols[4] = psName; aDbCols[5] = psPath; aDbCols[6] = psSelf;
HACCESSOR hAccessor = MapColumns( pCmdTree, cBasicTestCols, aBasicTestCols, aDbCols, FALSE );
//
// Clean up.
//
ReleaseAccessor( pCmdTree, hAccessor); }
#define MAX_BOOKMARK_LENGTH 16
DBBINDING aMoveTestCols[] = { // the iOrdinal field is filled out after the cursor is created
{ 0, sizeof DBLENGTH, 0, 0, 0,0,0, DBPART_VALUE|DBPART_LENGTH, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, MAX_BOOKMARK_LENGTH, 0, DBTYPE_BYTES, 0, 0}, };
const ULONG cMoveTestCols = sizeof aMoveTestCols / sizeof aMoveTestCols[0];
struct BookmarkBinding { DBLENGTH cbBmk; BYTE abBmk[MAX_BOOKMARK_LENGTH]; };
BookmarkBinding aBmks[21];
HACCESSOR hBmkAccessor = 0;
//+-------------------------------------------------------------------------
//
// Function: GetBookmarks, public
//
// Synopsis: Retrieve bookmarks into the global bookmarks array
//
// Effects: aBmks is loaded with bookmarks, one for each row
//
// Arguments: [pRowset] - a pointer to IRowsetLocate
// [cRows] - nuumber of HROWs in the array
// [phRows] - a pointer to the HROWs array
//
// Returns: 0/1 - count of failures
//
// Notes: Assumes hBmkAccessor is bound to the rowset for
// retrieving into the BookmarkBinding struct.
//
// History: 30 Mar 1995 AlanW Created
//
//--------------------------------------------------------------------------
int GetBookmarks( IRowsetLocate * pRowset, DBCOUNTITEM cRows, HROW * phRows ) { int fFailed = 0; SCODE sc;
for (unsigned i=0; i<cRows; i++) { sc = pRowset->GetData(phRows[i], hBmkAccessor, &aBmks[i]); if (FAILED(sc) || DB_S_ERRORSOCCURRED == sc) { if (! fFailed) LogError( "IRowset::GetData for bookmark failed 0x%x\n", sc ); fFailed++; } } if (fFailed) LogError(" %d/%d failures\n", fFailed, cRows);
return fFailed != 0; }
//+-------------------------------------------------------------------------
//
// Function: CheckHrowIdentity, private
//
// Synopsis: Check for hrow identity among two arrays of HROWs
//
// Arguments: [pRowsetIdentity] - if non-zero, a pointer to an
// IRowsetIdentity for comparing the HROWs.
// [lOffset] - offset of matching rows in the two arrays.
// Positive if second array is shifted from first,
// negative otherwise.
// [cRows1] - count of rows in first array
// [phRows1] - pointer to HROWs, first array
// [cRows2] - count of rows in second array
// [phRows2] - pointer to HROWs, second array
//
// Returns: int - error count
//
// Notes:
//
// History: 03 Apr 95 AlanW Created
//
//--------------------------------------------------------------------------
int CheckHrowIdentity( IRowsetIdentity * pRowsetIdentity, DBROWCOUNT lOffset, DBCOUNTITEM cRows1, HROW * phRows1, DBCOUNTITEM cRows2, HROW * phRows2 ) { int fFailed = 0; SCODE sc;
DBROWCOUNT o1 = 0, o2 = 0; DBCOUNTITEM cRows = min(cRows1, cRows2);
if (lOffset < 0) { o1 = -lOffset; if (cRows1 - o1 < cRows) cRows = cRows1 - o1; } else if (lOffset > 0) { o2 = lOffset; if (cRows2 - o2 < cRows) cRows = cRows2 - o2; }
for (unsigned i=0; i<cRows; i++) { int fHrowEqual = 0;
// Compare HROWs for identity
if (pRowsetIdentity) { sc = pRowsetIdentity->IsSameRow(phRows1[i+o1], phRows2[i+o2]); if (sc == S_OK) fHrowEqual = 1; else if (sc == S_FALSE) fHrowEqual = 0; else { LogError("IRowsetIdentity->IsSameRow returned %x\n", sc); fFailed++; fHrowEqual = 1; // only one error for this
} } else fHrowEqual = (phRows1[i+o1] == phRows2[i+o2]);
if (! fHrowEqual) { LogError( "Hrows didn't compare for equality (used identity %d), %x %x\n", ( 0 != pRowsetIdentity ), phRows1[i+o1], phRows2[i+o2] ); fFailed++; }
if (o1 == o2 || phRows1 == phRows2) continue;
// Now compare two which should be unequal
if (pRowsetIdentity) { sc = pRowsetIdentity->IsSameRow(phRows1[i], phRows2[i]); if (sc == S_OK) fHrowEqual = 1; else if (sc == S_FALSE) fHrowEqual = 0; else { LogError("IRowsetIdentity->IsSameRow (2) returned %x\n", sc); fFailed++; fHrowEqual = 1; // only one error for this
} } else fHrowEqual = (phRows1[i] == phRows2[i]);
if (fHrowEqual) { LogError("Different Hrows compared equal, %x %x\n", phRows1[i], phRows2[i]); fFailed++; } } return fFailed; }
//+-------------------------------------------------------------------------
//
// Function: MoveTest, public
//
// Synopsis: Test IRowsetLocate and IRowsetScroll methods
//
// Arguments: [pRowset] - a rowset supporting IRowsetLocate and
// optionally IRowsetScroll
// [hChapt] - rowset chapter if chaptered
//
// Returns: Nothing, exits if test error
//
// Notes: IRowsetLocate tests:
// QI to IRowsetLocate
// QI to IRowsetIdentity
// Bind to bookmark column
// Compare bookmarks with standard bookmark combinations
// Move to beginning and fetch
// Get bookmarks for fetched rows
// Compare bookmarks for first and second rows
// Fetch starting at second row
// Check bookmark equivalence for overlapping rows
// Check HROW identity for overlapping rows
// Move to end and fetch, check cRowsReturned and status
// Move after end and fetch, check cRowsReturned and status
//
// IRowsetScroll tests:
// QI to IRowsetScroll
// Scroll to 50% and fetch, check GetApproximatePosition
// Scroll to 14/27 and fetch, compare rows from 50% fetch
// Scroll to 14/13, check for error
// Check GetApproximatePosition with std bookmarks
//
// History: 16 Aug 94 AlanW Created
// 02 Apr 95 AlanW Updated for ole-db phase 3, bookmark
// bindings.
//
//--------------------------------------------------------------------------
BookmarkBinding FirstRowBmk; BookmarkBinding SecondRowBmk; BookmarkBinding LastRowBmk; BookmarkBinding PenultimateRowBmk;
const long cLocateTest = 7; const long cLocateTest2 = 9;
void MoveTest( IRowset * pRowset, HCHAPTER hChapt ) { int fFailed = 0;
if (hChapt == DB_NULL_HCHAPTER) LogProgress( " IRowsetLocate test\n" );
IRowsetLocate * pRowsetLocate = 0; SCODE sc = pRowset->QueryInterface(IID_IRowsetLocate, (void **)&pRowsetLocate);
if (FAILED(sc) || pRowsetLocate == 0) { LogFail("QueryInterface to IRowsetLocate failed\n"); }
IRowsetIdentity * pRowsetIdentity = 0; sc = pRowset->QueryInterface(IID_IRowsetIdentity, (void **)&pRowsetIdentity);
if (FAILED(sc) && (sc != E_NOINTERFACE || pRowsetIdentity != 0)) { LogError("QueryInterface to IRowsetIdentity failed (%x)\n", sc); pRowsetIdentity = 0; fFailed++; }
BOOL fCompareOrdered = GetBooleanProperty( pRowset, DBPROP_ORDEREDBOOKMARKS ); BOOL fBookmarkBound = FALSE;
// need to know how many rows in the chapter total, so that tests
// below can be relaxed if there are just a few.
DBCOUNTITEM cTableRows; IRowsetScroll * pIRowsetScroll = 0; SCODE sca = pRowset->QueryInterface(IID_IRowsetScroll,(void **) &pIRowsetScroll ); if ( FAILED( sca ) ) { LogError( "IRowset::qi for rowsetscroll returned 0x%lx\n", sca ); fFailed++; }
sca = pIRowsetScroll->GetApproximatePosition(hChapt, 0,0, 0, &cTableRows);
if ( FAILED( sca ) ) { LogError( "IRowsetScroll::GetApproximatePosition returned 0x%lx\n", sca ); fFailed++; }
if (fVerbose > 1) LogProgress(" Movable rowset has %d rows\n",cTableRows);
pIRowsetScroll->Release();
//
// Get the column number for the standard bookmark if available
//
hBmkAccessor = MapColumns(pRowset, 1, aMoveTestCols, &psBookmark); fBookmarkBound = TRUE;
if ( aMoveTestCols[0].iOrdinal != 0 ) { LogError( "Bookmark column is not ordinal 0 ( = %d)\n", aMoveTestCols[0].iOrdinal ); fFailed++; }
HROW* phRows = 0; DBROWCOUNT cRowsRequested = 1000; DBCOUNTITEM cRowsReturned = 0;
//
// Fetch 1000 rows from the beginning of the rowset.
//
sc = pRowsetLocate->GetRowsAt( 0, hChapt, 1, &bmkFirst, 0, cRowsRequested, &cRowsReturned, &phRows);
if ( FAILED( sc ) ) { LogError( "IRowsetLocate->GetRowsAt(1000) returned 0x%x\n", sc ); fFailed++; } else if (sc != DB_S_ENDOFROWSET && cRowsReturned != (DBCOUNTITEM) cRowsRequested) { LogError( "IRowsetLocate->GetRowsAt J returned %d of %d rows\n", cRowsReturned, cRowsRequested); fFailed++; }
if (phRows) FreeHrowsArray( pRowsetLocate, cRowsReturned, &phRows);
//
// Fetch 10 rows from the beginning of the rowset.
//
cRowsRequested = 10; sc = pRowsetLocate->GetRowsAt(0, hChapt, 1,&bmkFirst, 0, cRowsRequested, &cRowsReturned, &phRows);
if ( FAILED( sc ) ) { LogError( "IRowsetLocate->GetRowsAt K returned 0x%x\n", sc ); fFailed++; } else if (sc != DB_S_ENDOFROWSET && cRowsReturned != (DBCOUNTITEM) cRowsRequested) { LogError( "IRowsetLocate->GetRowsAt L returned %d of %d rows\n", cRowsReturned, cRowsRequested); fFailed++; }
HROW* phRows2 = 0; DBCOUNTITEM cRowsReturned2 = 0;
DWORD dwCompare = 0xFFFFFFFF;
if (fBookmarkBound) { fFailed += GetBookmarks( pRowsetLocate, cRowsReturned, phRows); FirstRowBmk = aBmks[0];
if ( cRowsReturned > 1 ) SecondRowBmk = aBmks[1]; else SecondRowBmk.cbBmk = 0;
sc = pRowsetLocate->Compare(hChapt, 1,&bmkFirst, FirstRowBmk.cbBmk, FirstRowBmk.abBmk, &dwCompare);
if ( FAILED( sc ) ) { LogError( "IRowsetLocate->Compare of DBBMK_FIRST returned 0x%x\n", sc ); fFailed++; } else if (dwCompare != DBCOMPARE_NE) { // DBBMK_FIRST is not the same as the first row's bookmark
LogError( "Compare of DBBMK_FIRST and returned bookmark not " "notequal (%d)\n", dwCompare ); fFailed++; } if (cRowsReturned >= 2) { sc = pRowsetLocate->Compare(hChapt, FirstRowBmk.cbBmk, FirstRowBmk.abBmk, SecondRowBmk.cbBmk, SecondRowBmk.abBmk, &dwCompare);
if ( FAILED( sc ) ) { LogError( "IRowsetLocate->Compare returned 0x%x\n", sc ); fFailed++; } else if ((fCompareOrdered && dwCompare != DBCOMPARE_LT) || (! fCompareOrdered && dwCompare != DBCOMPARE_NE)) { LogError( "Compare of first and second returned bookmarks not " "%s (%d)\n", fCompareOrdered? "less than" : "not equal", dwCompare ); fFailed++; }
//
// Fetch 10 rows starting at the second row. Compare
// the overlapping returned HROWs.
//
sc = pRowsetLocate->GetRowsAt(0, hChapt, SecondRowBmk.cbBmk, SecondRowBmk.abBmk, 0, cRowsRequested, &cRowsReturned2, &phRows2);
if ( FAILED( sc ) ) { LogError("IRowsetLocate->GetRowsAt (2) returned 0x%x\n", sc ); fFailed++; } else if (sc != DB_S_ENDOFROWSET && cRowsReturned2 != (DBCOUNTITEM) cRowsRequested) { LogError("IRowsetLocate->GetRowsAt (2) returned %d of %d rows\n", cRowsReturned2, cRowsRequested); fFailed++; } else if (sc == DB_S_ENDOFROWSET && cRowsReturned2 < (DBCOUNTITEM) cRowsRequested && cRowsReturned2 != cRowsReturned - 1) { LogError("IRowsetLocate->GetRowsAt (2) returned inconsistent row count, %d - %d\n", cRowsReturned2, cRowsReturned); fFailed++; }
fFailed += CheckHrowIdentity(pRowsetIdentity, -1, cRowsReturned, phRows, cRowsReturned2, phRows2);
fFailed += GetBookmarks( pRowsetLocate, 1, phRows2);
sc = pRowsetLocate->Compare(hChapt, SecondRowBmk.cbBmk, SecondRowBmk.abBmk, aBmks[0].cbBmk, aBmks[0].abBmk, &dwCompare);
if ( FAILED( sc ) ) { LogError( "IRowsetLocate->Compare returned 0x%x\n", sc ); fFailed++; } else if (dwCompare != DBCOMPARE_EQ) { LogError( "Compare of second row bookmarks not equal (%d)\n", dwCompare ); fFailed++; } FreeHrowsArray( pRowsetLocate, cRowsReturned2, &phRows2); } }
FreeHrowsArray( pRowsetLocate, cRowsReturned, &phRows);
//
// Fetch at end, 3 cases:
// Last - 1 expect 2 rows returned
// Last + 0 expect 1 row returned
// Last + 1 expect 0 rows
//
sc = pRowsetLocate->GetRowsAt(0, hChapt, 1,&bmkLast, -1, cRowsRequested, &cRowsReturned, &phRows);
PenultimateRowBmk.cbBmk = 0; LastRowBmk.cbBmk = 0;
if ( FAILED( sc ) ) { LogError( "IRowsetLocate->GetRowsAt M returned 0x%x\n", sc ); fFailed++; } else if (sc != DB_S_ENDOFROWSET || (cRowsReturned != 2 && cTableRows >= 2 ) ) { LogError( "IRowsetLocate->GetRowsAt N returned %d rows at DBBMK_LAST - 1, sc: %lx\n", cRowsReturned, sc ); fFailed++; } else if (fBookmarkBound && cRowsReturned >= 2) { fFailed += GetBookmarks( pRowsetLocate, cRowsReturned, phRows); LastRowBmk = aBmks[1]; PenultimateRowBmk = aBmks[0];
sc = pRowsetLocate->Compare(hChapt, 1,&bmkLast, LastRowBmk.cbBmk, LastRowBmk.abBmk, &dwCompare);
if ( FAILED( sc ) ) { LogError( "IRowsetLocate->Compare of DBBMK_LAST returned 0x%x\n", sc ); fFailed++; } else if (dwCompare != DBCOMPARE_NE) { // DBBMK_LAST is not the same as the last row's bookmark
LogError( "Compare of DBBMK_LAST and returned bookmark not " "notequal (%d)\n", dwCompare ); fFailed++; }
if (cRowsReturned >= 2) { sc = pRowsetLocate->Compare(hChapt, LastRowBmk.cbBmk, LastRowBmk.abBmk, aBmks[0].cbBmk, aBmks[0].abBmk, &dwCompare);
if ( FAILED( sc ) ) { LogError( "IRowsetLocate->Compare returned 0x%x\n", sc ); fFailed++; } else if ((fCompareOrdered && dwCompare != DBCOMPARE_GT) || (! fCompareOrdered && dwCompare != DBCOMPARE_NE)) { LogError( "Compare of last and penultimate returned bookmarks not " "%s (%d)\n", fCompareOrdered? "greater than" : "not equal", dwCompare ); fFailed++; } } }
FreeHrowsArray( pRowsetLocate, cRowsReturned, &phRows);
sc = pRowsetLocate->GetRowsAt(0, hChapt, 1,&bmkLast, 0, cRowsRequested, &cRowsReturned, &phRows);
if ( FAILED( sc ) ) { LogError( "IRowsetLocate->GetRowsAt O returned 0x%x\n", sc ); fFailed++; } else if (sc != DB_S_ENDOFROWSET || cRowsReturned != 1 ) { LogError( "IRowsetLocate->GetRowsAt P returned %d rows at DBBMK_LAST, sc: %lx\n", cRowsReturned, sc ); fFailed++; }
FreeHrowsArray( pRowsetLocate, cRowsReturned, &phRows);
sc = pRowsetLocate->GetRowsAt(0, hChapt, 1,&bmkLast, 1, cRowsRequested, &cRowsReturned, &phRows);
if ( FAILED( sc ) /* && DB_E_BADSTARTPOSITION != sc */ ) { LogError( "IRowsetLocate->GetRowsAt Q returned 0x%x\n", sc ); fFailed++; } else if ( sc != DB_S_ENDOFROWSET || cRowsReturned != 0 ) { LogError( "IRowsetLocate->GetRowsAt R returned sc 0x%x, %d rows at DBBMK_LAST + 1\n", sc, cRowsReturned ); fFailed++; }
if (0 == cRowsReturned && phRows != 0) // Bug #7668 (part)
{ LogError("HROW array allocated without returned rows\n"); fFailed++; }
FreeHrowsArray( pRowsetLocate, cRowsReturned, &phRows);
// OLE-DB spec. bug #1007
sc = pRowsetLocate->GetRowsAt(0, hChapt, 1,&bmkLast, 0, 1, &cRowsReturned, &phRows);
if ( FAILED( sc ) ) { LogError( "IRowsetLocate->GetRowsAt S returned 0x%x\n", sc ); fFailed++; } else if (sc == DB_S_ENDOFROWSET || cRowsReturned != 1 ) { LogError( "IRowsetLocate->GetRowsAt T returned ENDOFROWSET inappropriately" " at DBBMK_LAST, %d\n", cRowsReturned ); fFailed++; } FreeHrowsArray( pRowsetLocate, cRowsReturned, &phRows);
if ( cTableRows > cLocateTest2 ) { sc = pRowsetLocate->GetRowsAt(0, hChapt, 1,&bmkLast, -cLocateTest, cLocateTest + 1, &cRowsReturned, &phRows);
if ( FAILED( sc ) ) { LogError("IRowsetLocate->GetRowsAt U (end-%d) returned 0x%x\n", cLocateTest, sc ); fFailed++; } else if (fBookmarkBound) fFailed += GetBookmarks( pRowsetLocate, cRowsReturned, phRows);
sc = pRowsetLocate->GetRowsAt(0, hChapt, 1,&bmkLast, -cLocateTest2, cLocateTest2 + 1, &cRowsReturned2, &phRows2);
if ( FAILED( sc ) ) { LogError("IRowsetLocate->GetRowsAt(2) V (end-%d) returned 0x%x\n", cLocateTest2, sc ); fFailed++; } else if ( (cRowsReturned <= cLocateTest && cRowsReturned2 != cRowsReturned) || (cRowsReturned == (cLocateTest+1) && cRowsReturned2 <= cLocateTest) ) { if ( sc != DB_S_ENDOFROWSET ) { LogError("IRowsetLocate->GetRowsAt W (end-%d) returned %d rows\n", cLocateTest2, cRowsReturned2 ); fFailed++; } } else { fFailed += CheckHrowIdentity( pRowsetIdentity, cRowsReturned2 - cRowsReturned, cRowsReturned, phRows, cRowsReturned2, phRows2);
} FreeHrowsArray( pRowsetLocate, cRowsReturned2, &phRows2); FreeHrowsArray( pRowsetLocate, cRowsReturned, &phRows);
if (fBookmarkBound) { // Attempt to call GetRowsByBookmark with bookmarks we've collected.
const unsigned cBybmkTest = cLocateTest + 1 + 5 + 1; DBBKMARK rgcbBookmarks[cBybmkTest]; BYTE* rgpBookmarks[cBybmkTest]; ULONG cBookmarks = 0;
for (unsigned i = 0; i<cRowsReturned; i++) { rgcbBookmarks[cBookmarks] = aBmks[i].cbBmk; rgpBookmarks[cBookmarks] = &aBmks[i].abBmk[0]; cBookmarks++; }
rgcbBookmarks[cBookmarks] = FirstRowBmk.cbBmk; rgpBookmarks[cBookmarks++] = &FirstRowBmk.abBmk[0];
if ( 0 != SecondRowBmk.cbBmk ) { rgcbBookmarks[cBookmarks] = SecondRowBmk.cbBmk; rgpBookmarks[cBookmarks++] = &SecondRowBmk.abBmk[0]; }
if ( 0 != LastRowBmk.cbBmk ) { rgcbBookmarks[cBookmarks] = LastRowBmk.cbBmk; rgpBookmarks[cBookmarks++] = &LastRowBmk.abBmk[0]; }
if ( 0 != PenultimateRowBmk.cbBmk ) { rgcbBookmarks[cBookmarks] = PenultimateRowBmk.cbBmk; rgpBookmarks[cBookmarks++] = &PenultimateRowBmk.abBmk[0]; }
rgcbBookmarks[cBookmarks] = FirstRowBmk.cbBmk; rgpBookmarks[cBookmarks++] = &FirstRowBmk.abBmk[0];
DBROWSTATUS BmkErrors[cBybmkTest]; HROW hRows[cBybmkTest]; sc = pRowsetLocate->GetRowsByBookmark( hChapt, cBookmarks, rgcbBookmarks, (const BYTE **)rgpBookmarks, hRows, BmkErrors); if ( FAILED( sc ) ) { LogError( "IRowsetLocate->GetRowsByBookmark returned 0x%x\n", sc ); fFailed++; } else if ( sc != S_OK ) { LogError( "Not all rows returned from GetRowsByBookmark, sc = 0x%x" "\t%d\n", sc, cBookmarks ); fFailed++; } else { fFailed += GetBookmarks( pRowsetLocate, cBookmarks, hRows); }
ReleaseStaticHrows( pRowsetLocate, cBookmarks, hRows);
//
// Try with a bad bookmark; check that correct status and
// HROW are returned. Regression test for #80381.
//
unsigned iBadRow = cBookmarks / 2; rgcbBookmarks[cBookmarks] = rgcbBookmarks[iBadRow]; rgpBookmarks[cBookmarks++] = rgpBookmarks[iBadRow];
rgcbBookmarks[iBadRow] = 1; rgpBookmarks[iBadRow] = (BYTE *)&bmkFirst;
sc = pRowsetLocate->GetRowsByBookmark( hChapt, cBookmarks, rgcbBookmarks, (const BYTE **)rgpBookmarks, hRows, BmkErrors);
if ( sc != DB_S_ERRORSOCCURRED ) { LogError( "GetRowsByBookmark with special bookmark didn't give error, sc = 0x%x" "\t%d\n", sc, cBookmarks ); fFailed++; } else if (hRows[iBadRow] != DB_NULL_HROW || BmkErrors[iBadRow] != DBROWSTATUS_E_INVALID) { LogError( "GetRowsByBookmark with special bookmark didn't give null hrow or correct status, " "hrow = 0x%x\trs = 0x%x\n", hRows[iBadRow], BmkErrors[iBadRow] ); fFailed++; } ReleaseStaticHrows( pRowsetLocate, cBookmarks, hRows); } }
//-------------------------
//
// IRowsetScroll tests
//
//-------------------------
IRowsetScroll * pRowsetScroll; sc = pRowset->QueryInterface(IID_IRowsetScroll, (void **)&pRowsetScroll);
BOOL fScroll = SUCCEEDED(sc);
if (fScroll) { if (hChapt == DB_NULL_HCHAPTER) LogProgress( " IRowsetScroll test\n" );
DBCOUNTITEM ulNum = 1, cRows = 0; BookmarkBinding HalfRowBmk;
/***
Additional Scroll tests to be coded up: Scroll to 10%, 20%, 30%..., GetBookmark, GetPosition and check Try bad fractions, 0/0, 101/100, fffffffe/ffffffff, etc. ***/ //
// Try a simple scroll
//
cRowsRequested = 20; sc = pRowsetScroll->GetRowsAtRatio(0, hChapt, 50, 100, cRowsRequested, &cRowsReturned, &phRows);
if ( FAILED( sc ) ) { LogError( "IRowset->GetRowsAtRatio returned 0x%x\n", sc ); fFailed++; } else if (sc != DB_S_ENDOFROWSET && cRowsReturned != (DBCOUNTITEM) cRowsRequested) { LogError( "IRowset->GetRowsAtRatio returned %d of %d rows\n", cRowsReturned, cRowsRequested); fFailed++; } else if (fBookmarkBound) { fFailed += GetBookmarks(pRowsetScroll, cRowsReturned, phRows);
HalfRowBmk = aBmks[0]; sc = pRowsetScroll->GetApproximatePosition(hChapt, HalfRowBmk.cbBmk, HalfRowBmk.abBmk, &ulNum, &cRows); if ( FAILED( sc ) ) { LogError( "IRowset->GetApproximatePosition returned 0x%x\n", sc ); fFailed++; } else if (cRows == 0 || (ulNum-1 < ((cRows-1)*40)/100 || ulNum-1 > (cRows*60)/100)) { LogError( "Scroll 50%%/GetApproximatePosition returned %d, %d\n", ulNum, cRows ); fFailed++; } }
cRowsRequested = 10; sc = pRowsetScroll->GetRowsAtRatio(0, hChapt, 14, 27, cRowsRequested, &cRowsReturned2, &phRows2); if ( FAILED( sc ) ) { LogError( "IRowset->GetRowsAtRation 14/27 returned 0x%x\n", sc ); fFailed++; } else if (fBookmarkBound) { DBCOUNTITEM ulNum2 = 0; fFailed += GetBookmarks(pRowsetScroll, cRowsReturned2, phRows2);
sc = pRowsetScroll->GetApproximatePosition( hChapt, aBmks[0].cbBmk, aBmks[0].abBmk, &ulNum2, &cRows); if ( FAILED( sc ) ) { LogError( "IRowset->GetApproximatePosition 14/27 returned 0x%x\n", sc ); fFailed++; } else if (cRows == 0 || ulNum > ulNum2) { LogError( "Scroll 51.8%%/GetApproximatePosition returned %d, %d, %d, total rows: %d\n", ulNum, ulNum2, cRows, cTableRows ); fFailed++; } else if (ulNum != ulNum2) { sc = pRowsetLocate->Compare(hChapt, HalfRowBmk.cbBmk, HalfRowBmk.abBmk, aBmks[0].cbBmk, aBmks[0].abBmk, &dwCompare);
if ( FAILED( sc ) ) { LogError( "IRowsetLocate->Compare returned 0x%x\n", sc ); fFailed++; } else if ((fCompareOrdered && dwCompare != DBCOMPARE_LT) || (! fCompareOrdered && dwCompare != DBCOMPARE_NE)) { LogError( "Compare of 50%% and 51.8%% returned bookmarks not " "%s (%d)\n", fCompareOrdered? "less than" : "not equal", dwCompare ); fFailed++; } }
if ( ( ulNum2 - ulNum ) < (DBCOUNTITEM) cRowsRequested) { DBCOUNTITEM oRowDiff = ulNum - ulNum2; fFailed += CheckHrowIdentity( pRowsetIdentity, oRowDiff, cRowsReturned, phRows, cRowsReturned2, phRows2); } } FreeHrowsArray(pRowsetScroll, cRowsReturned2, &phRows2); FreeHrowsArray(pRowsetScroll, cRowsReturned, &phRows);
static cTimesBadRatioTested = 0;
if ( cTimesBadRatioTested < 10 ) { // limited to 10 tests of this because it causes an exception
// internally which slows the drt down unnecessarily
cTimesBadRatioTested++; sc = pRowsetScroll->GetRowsAtRatio(0, hChapt, 14, 13, cRowsRequested, &cRowsReturned, &phRows); if ( sc != DB_E_BADRATIO ) { LogError( "IRowset->GetRowsAtRatio returned 0x%x for invalid fraction\n", sc ); fFailed++; }
FreeHrowsArray(pRowsetScroll, cRowsReturned, &phRows); }
sc = pRowsetScroll->GetRowsAtRatio(0, hChapt, 0, 100, cRowsRequested, &cRowsReturned, &phRows); if ( FAILED( sc ) ) { LogError( "IRowset->GetRowsAtRatio, 0%% returned 0x%x\n", sc ); fFailed++; } else if (fBookmarkBound) fFailed += GetBookmarks( pRowsetScroll, cRowsReturned, phRows);
FreeHrowsArray(pRowsetScroll, cRowsReturned, &phRows);
if (fBookmarkBound) { sc = pRowsetScroll->GetApproximatePosition( hChapt, aBmks[0].cbBmk, aBmks[0].abBmk, &ulNum, &cRows); if ( FAILED( sc ) ) { LogError( "IRowset->GetApproximatePosition 0%% returned 0x%x\n", sc ); fFailed++; } else if (cRows == 0 || ulNum != 1) { LogError( "GetApproximatePosition, first row returned %d, %d\n", ulNum, cRows ); fFailed++; } }
if ( 0 == hChapt ) { sc = pRowsetScroll->GetRowsAtRatio(0, hChapt, 100, 100, cRowsRequested, &cRowsReturned, &phRows); // if ( FAILED(sc) )
if (cRowsReturned != 0 || sc != DB_S_ENDOFROWSET) { LogError( "IRowsetScroll->GetRowsAtRatio 100%% returned sc: 0x%x, cRowsReturned: 0x%x\n", sc, cRowsReturned ); fFailed++; } FreeHrowsArray(pRowsetScroll, cRowsReturned, &phRows); }
sc = pRowsetScroll->GetApproximatePosition( hChapt, 1, &bmkLast, &ulNum, &cRows); if ( FAILED( sc ) ) { LogError( "IRowset->GetApproximatePosition DBBMK_LAST returned 0x%x\n", sc ); fFailed++; } else if (ulNum != cRows) { LogError( "GetApproximatePosition, last row returned %d, %d\n", ulNum, cRows ); fFailed++; } pRowsetScroll->Release(); } // end if (fScroll)
cFailures += fFailed; pRowsetLocate->Release(); if (fBookmarkBound) ReleaseAccessor( pRowset, hBmkAccessor);
if (0 != pRowsetIdentity) pRowsetIdentity->Release();
#if !defined(UNIT_TEST)
// if (fFailed) {
// pRowset->Release();
// Fail();
// }
#endif // !UNIT_TEST
return; } //MoveTest
//+-------------------------------------------------------------------------
//
// Function: DeleteTest, public
//
// Synopsis: Check that row delete works correctly
//
// Returns: Nothing
//
// Notes: Duplication scenario for bug# 12282
//
// History: 18 May 1995 AlanW Created
//
//--------------------------------------------------------------------------
struct SDeleteTest { DBLENGTH cbName; DBLENGTH cbPath;
DBROWSTATUS sName; DBROWSTATUS sPath;
WCHAR awcName[40]; WCHAR awcPath[MAX_PATH+1]; };
DBBINDING aDeleteTestCols[] = { // the iOrdinal field is filled out after the cursor is created
{ 0, offsetof(SDeleteTest,awcName), offsetof(SDeleteTest,cbName), offsetof(SDeleteTest,sName), 0,0,0, ALLPARTS, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, 40 * sizeof (WCHAR), 0, DBTYPE_WSTR, 0,0, }, { 0, offsetof(SDeleteTest,awcPath), offsetof(SDeleteTest,cbPath), offsetof(SDeleteTest,sPath), 0,0,0, ALLPARTS, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, cbRowName, 0, DBTYPE_WSTR, 0,0, }, };
const ULONG cDeleteTestCols = sizeof aDeleteTestCols / sizeof aDeleteTestCols[0];
void DeleteTest(BOOL fSequential) { LogProgress( "Delete function test with %s rowset\n", fSequential ? "sequential" : "movable" );
WCHAR wcsTestSubDir[MAX_PATH]; wcscpy( wcsTestSubDir, wcsTestPath ); wcscat( wcsTestSubDir, L"\\DeleteTest." ); wcscat( wcsTestSubDir, fSequential ? L"1" : L"2" );
unsigned cchTestSubDir = wcslen(wcsTestSubDir);
//
// Get name, size and class id for *.*
//
CDbColumns cols(2);
cols.Add( psName, 0 ); cols.Add( psPath, 1 );
CDbSortSet ss(1);
if (! fSequential ) ss.Add(psName, QUERY_SORTASCEND, 0);
CDbCmdTreeNode * pCmdTree = FormQueryTree( 0, cols, &ss );
IRowset * pRowset = InstantiateRowset( 0, QUERY_DEEP, // Depth
wcsTestPath, // Scope
pCmdTree, // DBCOMMANDTREE
IID_IRowsetScroll); // IID of i/f to return
//
// Verify columns
//
CheckColumns( pRowset, cols );
if ( !WaitForCompletion( pRowset ) ) { LogError( "DeleteTest query unsuccessful.\n" ); pRowset->Release(); Fail(); }
int fFailed = 0;
//
// Get an IRowsetScroll if possible.
//
DBCOUNTITEM cRows = 0;
IRowsetScroll * pIRowsetScroll = 0;
SCODE sc = pRowset->QueryInterface(IID_IRowsetScroll,(void **) &pIRowsetScroll );
if ( FAILED( sc ) && sc != E_NOINTERFACE ) { LogError( "IRowset::qi for IRowsetScroll failed, 0x%x\n", sc ); cFailures++; }
if (0 == pIRowsetScroll ) { if (! fSequential) { LogError( "Non-sequential cursor does not support IRowsetScroll\n" ); cFailures++; } } else { sc = pIRowsetScroll->GetApproximatePosition(0, 0,0, 0, &cRows);
if ( FAILED( sc ) ) { LogError( "IRowset->GetApproximatePosition returned 0x%lx\n", sc ); cFailures++; }
if ( cRows == 0 ) { LogError( "Query failed to return data\n" ); pIRowsetScroll->Release(); pRowset->Release(); Fail(); } }
//
// Patch the column index numbers with true numbers
//
DBID aDbCols[cDeleteTestCols]; aDbCols[0] = psName; aDbCols[1] = psPath;
HACCESSOR hAccessor = MapColumns(pRowset, cDeleteTestCols, aDeleteTestCols, aDbCols);
DBCOUNTITEM totalRowsFetched = 0; DBCOUNTITEM cRowsReturned = 0; HROW ahRows[10]; HROW* phRows = ahRows;
BOOL fDidDelete = FALSE; BOOL fDidDirDelete = FALSE;
do { sc = pRowset->GetNextRows(0, 0, 1, &cRowsReturned, &phRows);
if ( FAILED( sc ) ) { LogError( "IRowset->GetNextRows returned 0x%x\n", sc ); pRowset->Release(); Fail(); }
if (sc != DB_S_ENDOFROWSET && cRowsReturned != 1) { LogError( "IRowset->GetNextRows returned %d of %d rows," " status (%x) != DB_S_ENDOFROWSET\n", cRowsReturned, 1, sc); #if defined (UNIT_TEST)
cFailures++; #else // defined(UNIT_TEST)
pRowset->Release(); Fail(); #endif // defined(UNIT_TEST)
}
totalRowsFetched += cRowsReturned;
if ( (0 != pIRowsetScroll ) && (totalRowsFetched > cRows) ) { //
// check that no more rows have been added while we were
// fetching.
//
LogProgress("Checking for expansion of result set\n");
SCODE sc1 = pIRowsetScroll->GetApproximatePosition(0, 0,0, 0, &cRows);
if ( totalRowsFetched > cRows ) { LogError("Fetched more rows than exist in the result set, %d %d\n", totalRowsFetched, cRows); cFailures++; } } //
// When the retrieved row is the file name "F0005.txt" in the
// test directory, delete that file and
// continue the enumeration. We expect that GetNextRows can
// deal with the deletion.
//
// When the retrieved row is the file name "F0009.txt" in the
// test directory, delete the entire test directory and
// continue the enumeration. We expect that GetNextRows can
// deal with this deletion also.
//
unsigned i; for (i = 0; i < cRowsReturned; i++) { SDeleteTest Row;
SCODE sc1 = pRowset->GetData(ahRows[i],hAccessor,&Row);
if ( FAILED( sc1 ) ) { LogError( "IRowset->GetData returned 0x%x\n", sc1 ); pRowset->Release(); Fail(); }
if ( Row.sName == DBSTATUS_S_OK && Row.cbName != (wcslen(Row.awcName) * sizeof (WCHAR)) ) LogFail( "length of name column 0x%x not consistent with data 0x%x\n", Row.cbName, wcslen(Row.awcName) * sizeof WCHAR );
if ( Row.sPath == DBSTATUS_S_OK && Row.cbPath != (wcslen(Row.awcPath) * sizeof (WCHAR)) ) LogFail("length of path column not consistent with data\n");
if ( _wcsicmp( Row.awcName, L"F0005.txt" ) == 0 && _wcsnicmp( Row.awcPath, wcsTestSubDir, cchTestSubDir) == 0) { fDidDelete = DeleteFile(Row.awcPath); if (!fDidDelete) { if (fDidDirDelete && fSequential) { // Already did the delnode; we expect the delete to fail
fDidDelete = TRUE; } else { LogError( "Delete of %ws failed\n", Row.awcPath ); } } Sleep(2000); // Give time for delete to be processed
}
if ( _wcsicmp( Row.awcName, L"F0009.txt" ) == 0 && _wcsnicmp( Row.awcPath, wcsTestSubDir, cchTestSubDir) == 0) { fDidDirDelete = TRUE; if ( Delnode(wcsTestSubDir) != NO_ERROR ) LogError( "Delnode of %ws failed\n", wcsTestSubDir ); Sleep(2000); // Give time for delete to be processed
} }
if (0 != cRowsReturned) { SCODE sc1 = pRowset->ReleaseRows(cRowsReturned, ahRows, 0, 0, 0); if ( FAILED( sc1 ) ) { LogError( "IRowset->ReleaseRows returned 0x%x\n", sc1 ); pRowset->Release(); Fail(); } cRowsReturned = 0; }
} while (SUCCEEDED(sc) && sc != DB_S_ENDOFROWSET);
if (0 != cRowsReturned) { SCODE sc1 = pRowset->ReleaseRows(cRowsReturned, ahRows, 0, 0, 0); if ( FAILED( sc1 ) ) { LogError( "IRowset->ReleaseRows returned 0x%x\n", sc1 ); pRowset->Release(); Fail(); } }
if (!fDidDirDelete) { LogFail("Couldn't find file to trigger directory delete\n"); } if (!fDidDelete) { // NOTE: if F0009.txt is found before F0005.txt, this could
// occur, but we don't expect that with OFS's normal
// directory order.
LogFail("Couldn't find file to delete\n"); } if (totalRowsFetched < 10) { LogFail("Unexpectedly small number of files found in delete test, %d\n", totalRowsFetched); }
ReleaseAccessor( pRowset, hAccessor);
if ( (0 != pIRowsetScroll ) && (totalRowsFetched != cRows) ) { //
// check that no more rows have been added while we were
// fetching.
//
LogError("Wrong number of rows returned. Exp %d, got %d\n", cRows, totalRowsFetched); cFailures++; }
if (0 != pIRowsetScroll ) { pIRowsetScroll->Release(); pIRowsetScroll = 0; }
#if !defined(UNIT_TEST)
if (cFailures) { pRowset->Release(); Fail(); } #endif // !UNIT_TEST
pRowset->Release(); } //DeleteTest
//+-------------------------------------------------------------------------
//
// Function: GiveAccess
//
// Synopsis: Gives access to the system or current user
//
//--------------------------------------------------------------------------
BOOL GiveAccess( WCHAR * pwcFile, BOOL fCurrUser, DWORD accessMask ) { PACL pACLNew; DWORD cbACL = 1024; DWORD cbSID = 1024; DWORD cchDomainName = 80; PSID pSID; PSID_NAME_USE psnuType; WCHAR * pwcDomain;
WCHAR awcUser[100];
// setup username -- current user or system
if ( fCurrUser ) { DWORD cwc = sizeof awcUser / sizeof WCHAR; if ( !GetUserName( awcUser, &cwc ) ) LogFail("Couldn't get user name\n"); } else { wcscpy( awcUser, L"SYSTEM" ); }
// Initialize a new security descriptor.
PSECURITY_DESCRIPTOR pSD = (PSECURITY_DESCRIPTOR) LocalAlloc( LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH ); if (pSD == NULL) LogFail("Couldn't alloc security descriptor\n");
if ( !InitializeSecurityDescriptor( pSD, SECURITY_DESCRIPTOR_REVISION ) ) LogFail("Couldn't init security descriptor\n");
// Initialize a new ACL.
pACLNew = (PACL) LocalAlloc(LPTR, cbACL); if (pACLNew == NULL) LogFail("Couldn't alloc acl\n");
if (!InitializeAcl(pACLNew, cbACL, ACL_REVISION2)) LogFail("Couldn't init acl\n");
// Retrieve the SID for user
pSID = (PSID) LocalAlloc(LPTR, cbSID); psnuType = (PSID_NAME_USE) LocalAlloc(LPTR, 1024); pwcDomain = (WCHAR *) LocalAlloc(LPTR, cchDomainName); if (pSID == NULL || psnuType == NULL || pwcDomain == NULL) LogFail("Couldn't alloc security data\n");
if ( !LookupAccountName( (WCHAR *) NULL, awcUser, pSID, &cbSID, pwcDomain, &cchDomainName, psnuType ) ) LogFail("Couldn't lookup account '%ws'\n", awcUser );
// Allow write but not read access to the file.
if ( !AddAccessAllowedAce( pACLNew, ACL_REVISION2, accessMask, pSID )) LogFail("Couldn't AddAccessAllowedAce\n");
// Add a new ACL to the security descriptor.
if ( !SetSecurityDescriptorDacl( pSD, TRUE, // fDaclPresent flag
pACLNew, FALSE ) ) // not a default disc. ACL
LogFail("Couldn't SetSecurityDescriptorDacl\n");
// Apply the new security descriptor to the file.
if ( !SetFileSecurity( pwcFile, DACL_SECURITY_INFORMATION, pSD)) LogFail("Couldn't SetFileSecurity\n");
LogProgress( "set security '%ws' user '%ws' domain '%ws' to %x\n", pwcFile, awcUser, pwcDomain, accessMask );
FreeSid(pSID); LocalFree((HLOCAL) pSD); LocalFree((HLOCAL) pACLNew); LocalFree((HLOCAL) psnuType); LocalFree((HLOCAL) pwcDomain);
return TRUE; } //GiveAccess
//+-------------------------------------------------------------------------
//
// Function: DenyAllAccess
//
// Synopsis: Deniess all access to a file
//
//--------------------------------------------------------------------------
BOOL DenyAllAccess( WCHAR *pwcFile ) { // Initialize a security descriptor.
PSECURITY_DESCRIPTOR pSD = (PSECURITY_DESCRIPTOR) LocalAlloc( LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH ); if (pSD == NULL) LogFail("Couldn't alloc security descriptor\n");
if ( !InitializeSecurityDescriptor( pSD, SECURITY_DESCRIPTOR_REVISION ) ) LogFail("Couldn't InitializeSecurityDescriptor\n");
// Initialize a DACL.
DWORD cbACL; cbACL = 1024; PACL pACL; pACL = (PACL) LocalAlloc(LPTR, cbACL); if (pACL == NULL) LogFail("Couldn't allocate acl\n");
if (!InitializeAcl(pACL, cbACL, ACL_REVISION2)) LogFail("Couldn't init acl\n");
// Add an empty ACL to the SD to deny access.
if ( !SetSecurityDescriptorDacl( pSD, TRUE, // fDaclPresent flag
pACL, FALSE ) ) // not a default acl
LogFail("Couldn't SetSecurityDescriptorDacl\n");
// Use the new SD as the file's security info.
if ( !SetFileSecurity( pwcFile, DACL_SECURITY_INFORMATION, pSD ) ) LogFail("Couldn't SetFileSecurity\n");
if(pSD != NULL) LocalFree((HLOCAL) pSD); if(pACL != NULL) LocalFree((HLOCAL) pACL);
return TRUE; } //DenyAllAccess
void AddSafeArrays( IPropertySetStorage * ppsstg ) { // aI4 (DBTYPE_I4, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 2
// aBstr (DBTYPE_BSTR, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 3
// aVariant (DBTYPE_I4, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 4
// aR8 (DBTYPE_R8, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 5
// aDate (DBTYPE_DATE, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 6
// aBool (DBTYPE_BOOL, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 7
// aDecimal (DBTYPE_R8, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 8
// aI1 (DBTYPE_I1, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 9
// aR4 (DBTYPE_R4, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 10
// aCy (DBTYPE_R8, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 11
// aUINT (DBTYPE_UI4, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 12
// aINT (DBTYPE_I4, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 13
// aError (DBTYPE_I4, 10) = 92452ac2-fcbb-11d1-b7ca-00a0c906b239 14
IPropertyStorage * ppstg; ULONG ulMode = STGM_DIRECT | STGM_SHARE_EXCLUSIVE; SCODE sc = ppsstg->Create( guidArray, // property set guid
0, PROPSETFLAG_DEFAULT, ulMode | STGM_READWRITE, // Open mode
&ppstg ); // IProperty
if ( FAILED(sc) ) LogFail( "SA: can't create ps %#x\n", sc );
// VT_ARRAY | VT_I4
{ SAFEARRAYBOUND saBounds[3]; saBounds[0].lLbound = 1; saBounds[0].cElements = 3; saBounds[1].lLbound = 1; saBounds[1].cElements = 4; saBounds[2].lLbound = 1; saBounds[2].cElements = 2;
SAFEARRAY * psa = SafeArrayCreateEx( VT_I4, 3, saBounds, 0 ); if ( 0 == psa ) LogFail( "SA: can't create sa I4: %#x\n", sc );
vaI4.vt = VT_I4 | VT_ARRAY; vaI4.parray = psa;
for ( int x = 1; x <= 3; x++ ) for ( int y = 1; y <= 4; y++ ) for ( int z = 1; z <= 2; z++ ) { LONG *pl; LONG aDim[3]; aDim[0] = x; aDim[1] = y; aDim[2] = z; HRESULT hr = SafeArrayPtrOfIndex( psa, aDim, (void **) &pl ); *pl = (x-1) * 8 + (y-1) * 2 + (z-1); }
sc = ppstg->WriteMultiple( 1, &psSA_I4, &vaI4, 0x1000 ); if ( FAILED( sc ) ) LogFail( "SA: can't writemultiple VT_I4 %#x\n", sc ); }
// VT_ARRAY | VT_BSTR
{ SAFEARRAYBOUND saBounds[3]; saBounds[0].lLbound = -1; saBounds[0].cElements = 2; saBounds[1].lLbound = 0; saBounds[1].cElements = 3; saBounds[2].lLbound = 49; saBounds[2].cElements = 2;
SAFEARRAY * psa = SafeArrayCreateEx( VT_BSTR, 3, saBounds, 0 ); if ( 0 == psa ) LogFail( "SA: can't create sa I4\n" );
vaBSTR.vt = VT_BSTR | VT_ARRAY; vaBSTR.parray = psa;
int i = 0;
for ( int x = -1; x <= 0; x++ ) for ( int y = 0; y <= 2; y++ ) for ( int z = 49; z <= 50; z++ ) { void * pv; LONG aDim[3]; aDim[0] = x; aDim[1] = y; aDim[2] = z; HRESULT hr = SafeArrayPtrOfIndex( psa, aDim, &pv ); WCHAR awc[20]; swprintf( awc, L"%db", i ); BSTR bstr = SysAllocString( awc ); * (BSTR *) pv = bstr; i++; }
sc = ppstg->WriteMultiple( 1, &psSA_BSTR, &vaBSTR, 0x1000 ); if ( FAILED( sc ) ) LogFail( "SA: can't writemultiple VT_BSTR %#x\n", sc ); }
// VT_ARRAY | VT_VARIANT
{ SAFEARRAYBOUND saBounds[3]; saBounds[0].lLbound = 0; saBounds[0].cElements = 2; saBounds[1].lLbound = -3; saBounds[1].cElements = 2; saBounds[2].lLbound = 20; saBounds[2].cElements = 4;
SAFEARRAY * psa = SafeArrayCreateEx( VT_VARIANT, 3, saBounds, 0 ); if ( 0 == psa ) LogFail( "SA: can't create sa VARIANT\n" );
vaVARIANT.vt = VT_VARIANT | VT_ARRAY; vaVARIANT.parray = psa;
int i = 0; for ( int x = 0; x <= 1; x++ ) for ( int y = -3; y <= -2; y++ ) for ( int z = 20; z <= 23; z++ ) { LONG aDim[3]; aDim[0] = x; aDim[1] = y; aDim[2] = z;
PROPVARIANT * pVar; HRESULT hr = SafeArrayPtrOfIndex( psa, aDim, (void **) &pVar );
if ( 20 == z ) { pVar->lVal = i; pVar->vt = VT_I4; } else if ( 21 == z ) { WCHAR awc[20]; swprintf( awc, L"%db", i ); pVar->bstrVal = SysAllocString( awc ); pVar->vt = VT_BSTR;
} #if 0 // in 1829, the OLE group removed support for this!
else if ( 22 == z ) { *pVar = vaI4; } else if ( 23 == z ) { *pVar = vaBSTR; } #endif
else { pVar->fltVal = (float) i; pVar->vt = VT_R4; }
i++; }
sc = ppstg->WriteMultiple( 1, &psSA_VARIANT, &vaVARIANT, 0x1000 ); if ( FAILED( sc ) ) LogFail( "SA: can't writemultiple VT_VARIANT %#x\n", sc ); }
// VT_ARRAY | VT_R8
{ SAFEARRAYBOUND saBounds[2]; saBounds[0].lLbound = 100; saBounds[0].cElements = 3; saBounds[1].lLbound = -100; saBounds[1].cElements = 4;
SAFEARRAY * psa = SafeArrayCreateEx( VT_R8, 2, saBounds, 0 ); if ( 0 == psa ) LogFail( "SA: can't create sa r8\n" ); vaR8.vt = VT_R8 | VT_ARRAY; vaR8.parray = psa;
double d = 0.0l;
for ( int x = 100; x <= 102; x++ ) for ( int y = -100; y <= -97; y++ ) { double * pd; LONG aDim[2]; aDim[0] = x; aDim[1] = y; HRESULT hr = SafeArrayPtrOfIndex( psa, aDim, (void **) &pd ); *pd = d; d = d + 2.0l; }
sc = ppstg->WriteMultiple( 1, &psSA_R8, &vaR8, 0x1000 ); if ( FAILED( sc ) ) LogFail( "SA: can't writemultiple VT_r8 %#x\n", sc ); }
// VT_ARRAY | VT_DATE
{ SAFEARRAYBOUND saBounds[2]; saBounds[0].lLbound = 1; saBounds[0].cElements = 2; saBounds[1].lLbound = 1; saBounds[1].cElements = 3;
SAFEARRAY * psa = SafeArrayCreateEx( VT_DATE, 2, saBounds, 0 ); if ( 0 == psa ) LogFail( "can't create safearray of VT_DATE\n" );
vaDATE.vt = VT_DATE | VT_ARRAY; vaDATE.parray = psa;
int i = 0;
for ( int x = 1; x <= 2; x++ ) for ( int y = 1; y <= 3; y++ ) { LONG aDim[2]; aDim[0] = x; aDim[1] = y; DATE *pdate; HRESULT hr = SafeArrayPtrOfIndex( psa, aDim, (void **) &pdate );
// round the seconds and milliseconds to 0 since the
// property set API often is off by as much as 4 seconds
// when you marshall and unmarshall the value.
SYSTEMTIME st; GetSystemTime( &st ); st.wSecond = 0; st.wMilliseconds = 0; st.wYear += (USHORT) i; SystemTimeToVariantTime( &st, pdate ); i++; }
sc = ppstg->WriteMultiple( 1, &psSA_DATE, &vaDATE, 0x1000 ); if ( FAILED( sc ) ) LogFail( "can't writemultiple date %#x\n", sc ); }
// VT_ARRAY | VT_BOOL
{ SAFEARRAYBOUND saBounds[2]; saBounds[0].lLbound = 1; saBounds[0].cElements = 2; saBounds[1].lLbound = 1; saBounds[1].cElements = 3;
SAFEARRAY * psa = SafeArrayCreateEx( VT_BOOL, 2, saBounds, 0 ); if ( 0 == psa ) LogFail( "can't create safearray of VT_BOOL\n" );
vaBOOL.vt = VT_BOOL | VT_ARRAY; vaBOOL.parray = psa;
int i = 0; GUID guid = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
for ( int x = 1; x <= 2; x++ ) for ( int y = 1; y <= 3; y++ ) { LONG aDim[2]; aDim[0] = x; aDim[1] = y; VARIANT_BOOL *pB; HRESULT hr = SafeArrayPtrOfIndex( psa, aDim, (void **) &pB ); *pB = (i & 1) ? VARIANT_TRUE : VARIANT_FALSE; i++; }
sc = ppstg->WriteMultiple( 1, &psSA_BOOL, &vaBOOL, 0x1000 ); if ( FAILED( sc ) ) LogFail( "can't writemultiple bool %#x\n", sc ); }
// VT_ARRAY | VT_DECIMAL
{ SAFEARRAYBOUND saBounds[2]; saBounds[0].lLbound = 1; saBounds[0].cElements = 2; saBounds[1].lLbound = 1; saBounds[1].cElements = 3;
SAFEARRAY * psa = SafeArrayCreateEx( VT_DECIMAL, 2, saBounds, 0 ); if ( 0 == psa ) LogFail( "can't create safearray of VT_DECIMAL\n" );
vaDECIMAL.vt = VT_DECIMAL | VT_ARRAY; vaDECIMAL.parray = psa;
int i = 0;
for ( int x = 1; x <= 2; x++ ) for ( int y = 1; y <= 3; y++ ) { LONG aDim[2]; aDim[0] = x; aDim[1] = y; DECIMAL *pd; HRESULT hr = SafeArrayPtrOfIndex( psa, aDim, (void **) &pd ); if ( FAILED( hr ) ) LogFail( "can't get ptr of index for DECIMAL %#x", hr ); double d = i; VarDecFromR8( d, pd ); i++; }
sc = ppstg->WriteMultiple( 1, &psSA_DECIMAL, &vaDECIMAL, 0x1000 ); if ( FAILED( sc ) ) LogFail( "can't writemultiple decimal %#x\n", sc ); }
// VT_ARRAY | VT_I4
{ SAFEARRAYBOUND saBounds[3]; saBounds[0].lLbound = 1; saBounds[0].cElements = 3; saBounds[1].lLbound = 1; saBounds[1].cElements = 4; saBounds[2].lLbound = 1; saBounds[2].cElements = 2;
SAFEARRAY * psa = SafeArrayCreateEx( VT_I1, 3, saBounds, 0 ); vaI1.vt = VT_I1 | VT_ARRAY; vaI1.parray = psa;
for ( int x = 1; x <= 3; x++ ) for ( int y = 1; y <= 4; y++ ) for ( int z = 1; z <= 2; z++ ) { BYTE *pb; LONG aDim[3]; aDim[0] = x; aDim[1] = y; aDim[2] = z; HRESULT hr = SafeArrayPtrOfIndex( psa, aDim, (void **) &pb ); *pb = (x-1) * 8 + (y-1) * 2 + (z-1); }
sc = ppstg->WriteMultiple( 1, &psSA_I1, &vaI1, 0x1000 ); if ( FAILED( sc ) ) LogFail( "can't writemultiple i1 %#x\n", sc ); }
// VT_ARRAY | VT_R4
{ SAFEARRAYBOUND saBounds[2]; saBounds[0].lLbound = 100; saBounds[0].cElements = 3; saBounds[1].lLbound = -100; saBounds[1].cElements = 4;
SAFEARRAY * psa = SafeArrayCreateEx( VT_R4, 2, saBounds, 0 ); vaR4.vt = VT_R4 | VT_ARRAY; vaR4.parray = psa;
float f = 0.0;
for ( int x = 100; x <= 102; x++ ) for ( int y = -100; y <= -97; y++ ) { float * pf; LONG aDim[2]; aDim[0] = x; aDim[1] = y; HRESULT hr = SafeArrayPtrOfIndex( psa, aDim, (void **) &pf ); RtlCopyMemory( pf, &f, sizeof f ); f = (float) ( f + (float) 3.0 ); }
sc = ppstg->WriteMultiple( 1, &psSA_R4, &vaR4, 0x1000 ); if ( FAILED( sc ) ) LogFail( "can't writemultiple r4 %#x\n", sc ); }
// VT_ARRAY | VT_CY
{ SAFEARRAYBOUND saBounds[2]; saBounds[0].lLbound = 100; saBounds[0].cElements = 3; saBounds[1].lLbound = -100; saBounds[1].cElements = 4;
SAFEARRAY * psa = SafeArrayCreateEx( VT_CY, 2, saBounds, 0 ); vaCY.vt = VT_CY | VT_ARRAY; vaCY.parray = psa;
double d = 0.0l;
for ( int x = 100; x <= 102; x++ ) for ( int y = -100; y <= -97; y++ ) { CY *pcy; LONG aDim[2]; aDim[0] = x; aDim[1] = y; HRESULT hr = SafeArrayPtrOfIndex( psa, aDim, (void **) &pcy ); CY cy; VarCyFromR8( d, &cy ); *pcy = cy; d = d + 4.0l; }
sc = ppstg->WriteMultiple( 1, &psSA_CY, &vaCY, 0x1000 ); if ( FAILED( sc ) ) LogFail( "can't writemultiple cy %#x\n", sc ); }
// VT_ARRAY | VT_UINT
{ SAFEARRAYBOUND saBounds[3]; saBounds[0].lLbound = 1; saBounds[0].cElements = 3; saBounds[1].lLbound = 1; saBounds[1].cElements = 4; saBounds[2].lLbound = 1; saBounds[2].cElements = 2;
SAFEARRAY * psa = SafeArrayCreateEx( VT_UINT, 3, saBounds, 0 ); if ( 0 == psa ) LogFail( "can't create safearray of uint\n" );
vaUINT.vt = VT_UINT | VT_ARRAY; vaUINT.parray = psa;
for ( int x = 1; x <= 3; x++ ) for ( int y = 1; y <= 4; y++ ) for ( int z = 1; z <= 2; z++ ) { unsigned *p; LONG aDim[3]; aDim[0] = x; aDim[1] = y; aDim[2] = z; HRESULT hr = SafeArrayPtrOfIndex( psa, aDim, (void **) &p ); *p = (unsigned) ( (x-1) * 8 + (y-1) * 2 + (z-1) ); }
sc = ppstg->WriteMultiple( 1, &psSA_UINT, &vaUINT, 0x1000 ); if ( FAILED( sc ) ) LogFail( "can't writemultiple uint %#x\n", sc ); }
// VT_ARRAY | VT_INT
{ SAFEARRAYBOUND saBounds[3]; saBounds[0].lLbound = 1; saBounds[0].cElements = 3; saBounds[1].lLbound = 1; saBounds[1].cElements = 4; saBounds[2].lLbound = 1; saBounds[2].cElements = 2;
SAFEARRAY * psa = SafeArrayCreateEx( VT_INT, 3, saBounds, 0 ); if ( 0 == psa ) LogFail( "can't create safearray of int\n" );
vaINT.vt = VT_INT | VT_ARRAY; vaINT.parray = psa;
for ( int x = 1; x <= 3; x++ ) for ( int y = 1; y <= 4; y++ ) for ( int z = 1; z <= 2; z++ ) { int *p; LONG aDim[3]; aDim[0] = x; aDim[1] = y; aDim[2] = z; HRESULT hr = SafeArrayPtrOfIndex( psa, aDim, (void **) &p ); *p = (x-1) * 8 + (y-1) * 2 + (z-1); }
sc = ppstg->WriteMultiple( 1, &psSA_INT, &vaINT, 0x1000 ); if ( FAILED( sc ) ) LogFail( "can't writemultiple int %#x\n", sc ); }
// VT_ARRAY | VT_ERROR
{ SAFEARRAYBOUND saBounds[3]; saBounds[0].lLbound = 1; saBounds[0].cElements = 3; saBounds[1].lLbound = 1; saBounds[1].cElements = 4; saBounds[2].lLbound = 1; saBounds[2].cElements = 2;
SAFEARRAY * psa = SafeArrayCreateEx( VT_ERROR, 3, saBounds, 0 ); if ( 0 == psa ) LogFail( "can't create safearray of error\n" );
vaERROR.vt = VT_ERROR | VT_ARRAY; vaERROR.parray = psa;
for ( int x = 1; x <= 3; x++ ) for ( int y = 1; y <= 4; y++ ) for ( int z = 1; z <= 2; z++ ) { HRESULT *p; LONG aDim[3]; aDim[0] = x; aDim[1] = y; aDim[2] = z; HRESULT hr = SafeArrayPtrOfIndex( psa, aDim, (void **) &p ); *p = 0x80070000 + ( (x-1) * 8 + (y-1) * 2 + (z-1) ); }
sc = ppstg->WriteMultiple( 1, &psSA_ERROR, &vaERROR, 0x1000 ); if ( FAILED( sc ) ) LogFail( "can't writemultiple error %#x\n", sc ); }
ppstg->Release(); } //AddSafeArrays
//+-------------------------------------------------------------------------
//
// Function: AddPropsToStorage, public
//
// Synopsis: Add several props to a file
//
// Arguments: [fAlternate] -- TRUE to open alternate file
//
//--------------------------------------------------------------------------
typedef HRESULT (STDAPICALLTYPE * tdStgCreateStorage) ( const OLECHAR FAR* pwcsName, DWORD grfMode, DWORD dwStgFmt, LPSECURITY_ATTRIBUTES pssSecurity, IStorage FAR * FAR *ppstg);
tdStgCreateStorage pStgCreateStorage = 0;
static int fDidInitOfVariants = 0;
void AddPropsToStorage( BOOL fAlternate ) { SCODE sc;
if (! fDidInitOfVariants) { //
// Create a multi-dimensional safearray for an alternate value for
// property 8.
//
SAFEARRAYBOUND saBounds[3]; saBounds[0].lLbound = 1; saBounds[0].cElements = 50; saBounds[1].lLbound = 1; saBounds[1].cElements = 10; saBounds[2].lLbound = 1; saBounds[2].cElements = 10;
SAFEARRAY * psa = SafeArrayCreateEx( VT_I4, 3, saBounds, 0 ); LONG * plData; sc = SafeArrayAccessData( psa, (void **)&plData );
if ( FAILED(sc) ) { LogError( "SafeArrayAccessData returned 0x%x\n", sc ); CantRun(); } memcpy( plData, alProp8, sizeof alProp8 ); sc = SafeArrayUnaccessData( psa ); varProp8A.vt = VT_I4 | VT_ARRAY; varProp8A.parray = psa;
varProp11.vt = PROP11_TYPE; varProp11.bstrVal = SysAllocString( PROP11_VAL );
const unsigned cchProp11A = sizeof PROP11_LONGVAL/sizeof PROP11_LONGVAL[0]; for (unsigned i = 0; i + 25 + 25 < cchProp11A; i += 25) wcsncpy(&PROP11_LONGVAL[i+25], &PROP11_LONGVAL[i], 25); varProp11A.vt = PROP11_TYPE; varProp11A.bstrVal = SysAllocStringLen( PROP11_LONGVAL, wcslen(PROP11_LONGVAL) );
varProp12.vt = PROP12_TYPE; varProp12.cabstr.pElems = (BSTR *)CoTaskMemAlloc( PROP4_VAL.cElems * sizeof (BSTR) ); varProp12.cabstr.cElems = PROP4_VAL.cElems; for (i=0; i < PROP4_VAL.cElems; i++) varProp12.cabstr.pElems[i] = SysAllocString( PROP4_VAL.pElems[i] );
fDidInitOfVariants++; }
// Create a storage
IStorage * pstg; ULONG ulMode = STGM_DIRECT | STGM_SHARE_EXCLUSIVE; sc = StgCreateDocfile( wcsTestPath, // Name
ulMode | STGM_READWRITE | STGM_CREATE, 0, // reserved
&pstg ); // Result
if ( FAILED(sc) ) { LogError( "StgCreateDocfile %ws returned 0x%x\n", wcsTestPath, sc ); CantRun(); }
// Create a property set
IPropertySetStorage * ppsstg; sc = pstg->QueryInterface( IID_IPropertySetStorage, (void **)&ppsstg ); pstg->Release(); if ( FAILED(sc) ) { LogError( "QueryInterface(IPropertySetStorage) returned 0x%lx\n", sc ); CantRun(); }
AddSafeArrays( ppsstg );
IPropertyStorage * ppstg; sc = ppsstg->Create( guidMyPropSet, // Property set GUID
0, PROPSETFLAG_DEFAULT, ulMode | STGM_READWRITE, // Open mode
&ppstg ); // IProperty
if ( FAILED(sc) ) { LogError( "IPropertySetStorage::Create returned 0x%lx\n", sc ); CantRun(); }
// Add property values
PROPID pid=0x1000;
varProp1.vt = PROP1_TYPE; varProp1.lVal = fAlternate ? PROP1_VAL_Alternate : PROP1_VAL; sc = ppstg->WriteMultiple( 1, // Count
&psTestProperty1.GetPropSpec(), // Property
&varProp1, // Value
pid ); // Propid
if ( FAILED(sc) ) { LogError( "IPropertyStorage::WriteMultiple 1 returned 0x%lx\n", sc ); CantRun(); }
varProp2.vt = PROP2_TYPE; varProp2.pwszVal = (WCHAR *)PROP2_VAL; sc = ppstg->WriteMultiple( 1, // Count
&psTestProperty2.GetPropSpec(), // Property
&varProp2, // Value
pid ); // Propid
if ( FAILED(sc) ) { LogError( "IPropertyStorage::WriteMultiple 2 returned 0x%lx\n", sc ); CantRun(); }
varProp10.vt = PROP10_TYPE; varProp10.pwszVal = (WCHAR *)PROP10_VAL; sc = ppstg->WriteMultiple( 1, // Count
&psTestProperty10.GetPropSpec(), // Property
&varProp10, // Value
pid ); // Propid
if ( FAILED(sc) ) { LogError( "IPropertyStorage::WriteMultiple 10 returned 0x%lx\n", sc ); CantRun(); }
sc = ppstg->WriteMultiple( 1, // Count
&psTestProperty11.GetPropSpec(), // Property
fAlternate ? &varProp11A : &varProp11, // Value
pid ); // Propid
if ( FAILED(sc) ) { LogError( "IPropertyStorage::WriteMultiple 11 returned 0x%lx\n", sc ); CantRun(); }
sc = ppstg->WriteMultiple( 1, // Count
&psTestProperty12.GetPropSpec(), // Property
&varProp12, // Value
pid ); // Propid
if ( FAILED(sc) ) { LogError( "IPropertyStorage::WriteMultiple 12 returned 0x%lx\n", sc ); CantRun(); }
varProp5.vt = PROP5_TYPE; varProp5.cal = PROP5_VAL; sc = ppstg->WriteMultiple( 1, // Count
&psRelevantWords.GetPropSpec(), // Property
&varProp5, // Value
pid ); // Propid
if ( FAILED(sc) ) { LogError( "IPropertyStorage::WriteMultiple 5 returned 0x%lx\n", sc ); CantRun(); }
varProp6.vt = PROP6_TYPE; varProp6.blob = PROP6_VAL; sc = ppstg->WriteMultiple( 1, // Count
&psBlobTest.GetPropSpec(), // Property
&varProp6, // Value
pid ); // Propid
if ( FAILED(sc) ) { LogError( "IPropertyStorage::WriteMultiple 6 returned 0x%lx\n", sc ); CantRun(); }
varProp7.vt = PROP7_TYPE; varProp7.puuid = &PROP7_VAL; sc = ppstg->WriteMultiple( 1, // Count
&psGuidTest.GetPropSpec(), // Property
&varProp7, // Value
pid ); // Propid
if ( FAILED(sc) ) { LogError( "IPropertyStorage::WriteMultiple 7 returned 0x%lx\n", sc ); CantRun(); }
varProp8.vt = PROP8_TYPE; varProp8.cal = PROP8_VAL; sc = ppstg->WriteMultiple( 1, // Count
&psManyRW.GetPropSpec(), // Property
fAlternate ? &varProp8A : &varProp8, // Value
pid ); // Propid
if ( FAILED(sc) ) { LogError( "IPropertyStorage::WriteMultiple 8 returned 0x%lx\n", sc ); CantRun(); }
varProp13.vt = PROP13_TYPE; varProp13.bVal = PROP13_VAL; sc = ppstg->WriteMultiple( 1, // Count
&psTestProperty13.GetPropSpec(), // Property
&varProp13, // Value
pid ); // Propid
if ( FAILED(sc) ) { LogError( "IPropertyStorage::WriteMultiple 13 returned 0x%lx\n", sc ); CantRun(); }
varProp14.vt = PROP14_TYPE; varProp14.iVal = PROP14_VAL; sc = ppstg->WriteMultiple( 1, // Count
&psTestProperty14.GetPropSpec(), // Property
&varProp14, // Value
pid ); // Propid
if ( FAILED(sc) ) { LogError( "IPropertyStorage::WriteMultiple 14 returned 0x%lx\n", sc ); CantRun(); }
varProp15.vt = PROP15_TYPE; varProp15.uiVal = PROP15_VAL; sc = ppstg->WriteMultiple( 1, // Count
&psTestProperty15.GetPropSpec(), // Property
&varProp15, // Value
pid ); // Propid
if ( FAILED(sc) ) { LogError( "IPropertyStorage::WriteMultiple 13 returned 0x%lx\n", sc ); CantRun(); }
varProp16.vt = PROP16_TYPE; varProp16.lVal = PROP16_VAL; sc = ppstg->WriteMultiple( 1, // Count
&psTestProperty16.GetPropSpec(), // Property
&varProp16, // Value
pid ); // Propid
if ( FAILED(sc) ) { LogError( "IPropertyStorage::WriteMultiple 16 returned 0x%lx\n", sc ); CantRun(); }
varProp17.vt = PROP17_TYPE; varProp17.fltVal = PROP17_VAL; sc = ppstg->WriteMultiple( 1, // Count
&psTestProperty17.GetPropSpec(), // Property
&varProp17, // Value
pid ); // Propid
if ( FAILED(sc) ) { LogError( "IPropertyStorage::WriteMultiple 17 returned 0x%lx\n", sc ); CantRun(); }
if (fAlternate) { varProp18A.decVal.sign = 0; varProp18A.decVal.Hi32 = 0; varProp18A.decVal.Lo64 = 123412345678i64; varProp18A.decVal.scale = 8; varProp18A.vt = VT_DECIMAL;
//double dbl = 0.;
//VarR8FromDec( &varProp18A.decVal, &dbl );
//LogError("\tvarProp18A.decVal = %.8f\n", dbl );
} else { varProp18.vt = PROP18_TYPE; varProp18.dblVal = PROP18_VAL; } sc = ppstg->WriteMultiple( 1, // Count
&psTestProperty18.GetPropSpec(), // Property
fAlternate ? &varProp18A : &varProp18, // Value
pid ); // Propid
if ( FAILED(sc) ) { LogError( "IPropertyStorage::WriteMultiple 18 returned 0x%lx\n", sc ); CantRun(); }
varProp19.vt = PROP19_TYPE; varProp19.boolVal = PROP19_VAL; sc = ppstg->WriteMultiple( 1, // Count
&psTestProperty19.GetPropSpec(), // Property
&varProp19, // Value
pid ); // Propid
if ( FAILED(sc) ) { LogError( "IPropertyStorage::WriteMultiple 19 returned 0x%lx\n", sc ); CantRun(); }
varProp20.vt = PROP20_TYPE; varProp20.pszVal = PROP20_VAL; sc = ppstg->WriteMultiple( 1, // Count
&psTestProperty20.GetPropSpec(), // Property
&varProp20, // Value
pid ); // Propid
if ( FAILED(sc) ) { LogError( "IPropertyStorage::WriteMultiple 20 returned 0x%lx\n", sc ); CantRun(); }
varProp21.vt = PROP21_TYPE; varProp21.pclipdata = PROP21_VAL; sc = ppstg->WriteMultiple( 1, // Count
&psTestProperty21.GetPropSpec(), // Property
&varProp21, // Value
pid ); // Propid
if ( FAILED(sc) ) { LogError( "IPropertyStorage::WriteMultiple 21 returned 0x%lx\n", sc ); CantRun(); }
varProp22.vt = PROP22_TYPE; varProp22.caclipdata.pElems = PROP22_VAL; varProp22.caclipdata.cElems = PROP22_CVALS; sc = ppstg->WriteMultiple( 1, // Count
&psTestProperty22.GetPropSpec(), // Property
&varProp22, // Value
pid ); // Propid
if ( FAILED(sc) ) { LogError( "IPropertyStorage::WriteMultiple 22 returned 0x%lx\n", sc ); CantRun(); }
ppstg->Release();
// PROP3 and PROP4 are in a different propertyset!
sc = ppsstg->Create( guidDocument, // Property set GUID
0, PROPSETFLAG_DEFAULT, ulMode | STGM_READWRITE, // Open mode
&ppstg ); // IProperty
if ( FAILED(sc) ) { LogError( "IPropertySetStorage::Create returned 0x%lx\n", sc ); CantRun(); }
varProp3.vt = PROP3_TYPE; varProp3.pwszVal = (WCHAR *)PROP3_VAL; sc = ppstg->WriteMultiple( 1, // Count
&psAuthor.GetPropSpec(), // Property
&varProp3, // Value
pid ); // Propid
if ( FAILED(sc) ) { LogError( "IPropertyStorage::WriteMultiple 3 returned 0x%lx\n", sc ); CantRun(); }
varProp4.vt = PROP4_TYPE; varProp4.calpwstr = PROP4_VAL; sc = ppstg->WriteMultiple( 1, // Count
&psKeywords.GetPropSpec(), // Property
&varProp4, // Value
pid ); // Propid
if ( FAILED(sc) ) { LogError( "IPropertyStorage::WriteMultiple 4 returned 0x%lx\n", sc ); CantRun(); }
ppstg->Release();
/////////////////////// the secure prop plan 9
sc = ppsstg->Create( guidSecurityTest, 0, PROPSETFLAG_DEFAULT, ulMode | STGM_READWRITE, // Open mode
&ppstg ); // IProperty
if ( FAILED(sc) ) LogFail( "IPropertySetStorage::Create (security2) returned 0x%lx\n", sc );
// this value will be invisible to queries due to permissions...
varProp9.vt = VT_EMPTY; varProp9.lVal = 0;
ppstg->Release(); ppsstg->Release();
} //AddPropsToStorage
//+-------------------------------------------------------------------------
//
// Function: AddFiles, public
//
// Synopsis: Add several files to a directory.
//
// Arguments: [wszPath] - path name where files should be added
// [cFiles] - number of files to create
// [wszPattern] - wsprintf string to create file name
//
// History: 18 May 1995 AlanW Created
//
//--------------------------------------------------------------------------
void AddFiles( const WCHAR *wszPath, unsigned cFiles, const WCHAR *wszPattern) { WCHAR wszFileName[MAX_PATH]; const unsigned owcFile = wcslen( wszPath );
for (unsigned i=0; i < cFiles; i++) { wcscpy( wszFileName, wszPath ); swprintf( &wszFileName[ owcFile ], wszPattern, i );
BuildFile( wszFileName, szOFSFileData, strlen( szOFSFileData ) ); } }
//+-------------------------------------------------------------------------
//
// Function: Setup, public
//
// Synopsis: Clean up and initialize state
//
// History: 13-May-93 KyleP Created
//
//--------------------------------------------------------------------------
void Setup() { if ( 0 == wcsTestCatalog[0] ) wcscpy( wcsTestCatalog, wcsDefaultTestCatalog );
if ( GetEnvironmentVariable( L"TEMP", wcsTestPath, sizeof(wcsTestPath) / sizeof(wcsTestPath[0]) ) == 0 ) { LogError( "Unable to find test directory. Set TEMP variable.\n" ); CantRun(); }
wcscat( wcsTestPath, L"\\" ); int ccPath = wcslen( wcsTestPath );
wcscat( wcsTestPath, wcsTestDir );
if (Delnode( wcsTestPath )) { LogError("Delnode %ws failed\n", wcsTestPath); CantRun(); }
//
// Create test directory.
//
if ( !CreateDirectory( (WCHAR *)wcsTestPath, 0 ) ) { LogError( "Error 0x%lx creating directory %ws\n", GetLastError(), wcsTestPath ); CantRun(); }
//
// Add property file + properties
//
wcscpy( wcsTestPath + ccPath, wcsTestDir ); wcscat( wcsTestPath, L"\\" ); wcscat( wcsTestPath, wcsPropFile ); AddPropsToStorage( FALSE );
//
// Make a second (similar) file
//
wcscpy( wcsTestPath + ccPath, wcsTestDir ); wcscat( wcsTestPath, L"\\" ); wcscat( wcsTestPath, wcsPropFile2 ); AddPropsToStorage( TRUE );
wcscpy( wcsTestPath + ccPath, wcsTestDir );
//
// Add more files for the delete tests
//
wcscpy( wcsTestPath + ccPath, wcsTestDir ); wcscat( wcsTestPath, L"\\DeleteTest.1" ); if ( !CreateDirectory( (WCHAR *)wcsTestPath, 0 ) ) { LogError( "Error 0x%lx creating directory %ws\n", GetLastError(), wcsTestPath ); CantRun(); }
AddFiles( wcsTestPath, 20, L"\\\\F%04d.txt" );
wcscpy( wcsTestPath + ccPath, wcsTestDir ); wcscat( wcsTestPath, L"\\DeleteTest.2" ); if ( !CreateDirectory( (WCHAR *)wcsTestPath, 0 ) ) { LogError( "Error 0x%lx creating directory %ws\n", GetLastError(), wcsTestPath ); CantRun(); }
AddFiles( wcsTestPath, 20, L"\\\\F%04d.txt" );
//
// Add three files for content query tests
//
wcscpy( wcsTestPath + ccPath, wcsTestDir ); wcscat( wcsTestPath, L"\\" ); wcscat( wcsTestPath, wcsTestCiFile1 ); BuildFile( wcsTestPath, szCIFileData1, strlen( szCIFileData1 ) );
wcscpy( wcsTestPath + ccPath, wcsTestDir ); wcscat( wcsTestPath, L"\\" ); wcscat( wcsTestPath, wcsTestCiFile2 ); BuildFile( wcsTestPath, szCIFileData2, strlen( szCIFileData2 ) );
// make file 2 visible to both filter daemon and current user.
// (it was already, but this verifies the file3 code below really works)
#ifdef CAIRO_SECURITY_WORKS
DenyAllAccess( wcsTestPath ); GiveAccess( wcsTestPath, TRUE, GENERIC_READ ); GiveAccess( wcsTestPath, FALSE, GENERIC_READ ); #endif
//
// make a file that should show up in content queries.
// give it write access to current user, read access to filter daemon
// => in the content index, but the current user can't see hit
//
wcscpy( wcsTestPath + ccPath, wcsTestDir ); wcscat( wcsTestPath, L"\\" ); wcscat( wcsTestPath, wcsTestCiFile3 ); BuildFile( wcsTestPath, szCIFileData2, strlen( szCIFileData2 ) ); DenyAllAccess( wcsTestPath ); #ifdef CAIRO_SECURITY_WORKS
GiveAccess( wcsTestPath, TRUE, GENERIC_WRITE ); // just for kicks
GiveAccess( wcsTestPath, FALSE, GENERIC_READ ); #endif
//
// Back to just directory
//
wcscpy( wcsTestPath + ccPath, wcsTestDir );
} //Setup
//+-------------------------------------------------------------------------
//
// Function: Cleanup, public
//
// Synopsis: Clean up and initialize state
//
// History: 13-May-93 KyleP Created
//
//--------------------------------------------------------------------------
void Cleanup() { if (Delnode( wcsTestPath )) { LogError("Delnode %ws failed\n", wcsTestPath); CantRun(); }
if ( fDidInitOfVariants ) { PropVariantClear( &varProp8A ); PropVariantClear( &varProp11 ); PropVariantClear( &varProp11A ); PropVariantClear( &varProp12 ); }
char acSysDir[MAX_PATH]; if( !GetSystemDirectoryA( acSysDir, sizeof(acSysDir) ) ) { LogFail( "Unable to determine system directory.\n" ); }
#if defined( DO_NOTIFICATION )
char acCmd[MAX_PATH]; sprintf(acCmd,"del %s\\*.zzz",acSysDir); system(acCmd); #endif // DO_NOTIFICATION
} //Cleanup
//+---------------------------------------------------------------------------
//
// Function: FormQueryTree
//
// Synopsis: Forms a query tree consisting of the projection nodes,
// sort node(s), selection node and the restriction tree.
//
// Arguments: [pRst] - pointer to Restriction tree describing the query
// [Cols] - Columns in the resulting table
// [pSort] - pointer to sort set; may be null
// [aColNames] - pointer to column names; may be null
//
// Returns: A pointer to the query tree. It is the responsibility of
// the caller to later free it.
//
// History: 06 July 1995 AlanW Created
//
// Notes:
//
//----------------------------------------------------------------------------
CDbCmdTreeNode * FormQueryTree( CDbCmdTreeNode * pRst, CDbColumns & Cols, CDbSortSet * pSort, LPWSTR * aColNames ) { CDbCmdTreeNode * pTree = 0; // return value
if (pRst) { //
// First create a selection node and append the restriction tree to it
//
CDbSelectNode * pSelect = new CDbSelectNode(); if ( 0 == pSelect ) { LogFail("FormQueryTree: out of memory 0\n"); }
pTree = pSelect; if ( !pSelect->IsValid() ) { delete pTree; LogFail("FormQueryTree: out of memory 1\n"); }
//
// Clone the restriction and use it.
//
CDbCmdTreeNode * pExpr = pRst->Clone(); if ( 0 == pExpr ) { delete pTree; LogFail("FormQueryTree: out of memory 2\n"); }
//
// Now make the restriction a child of the selection node.
//
pSelect->AddRestriction( pExpr ); } else { //
// No restriction. Just use table ID node as start of tree.
//
pTree = new CDbTableId(); if ( 0 == pTree ) { LogFail("FormQueryTree: out of memory 3\n"); } }
//
// Next create the projection nodes
//
CDbProjectNode * pProject = new CDbProjectNode(); if ( 0 == pProject ) { delete pTree; LogFail("FormQueryTree: out of memory 4\n"); }
//
// Make the selection a child of the projection node.
//
pProject->AddTable( pTree ); pTree = pProject;
//
// Next add all the columns in the state.
//
unsigned int cCol = Cols.Count(); for ( unsigned int i = 0; i < cCol; i++ ) { if ( !pProject->AddProjectColumn( Cols.Get(i), aColNames ? aColNames[i] : 0 )) { delete pTree; LogFail("FormQueryTree: out of memory 5\n"); } }
//
// Next add a sort node and make the project node a child of the
// sort node
//
if (pSort && pSort->Count()) { unsigned int cSortProp = pSort->Count(); CDbSortNode * pSortNode = new CDbSortNode();
if ( 0 == pSortNode ) { delete pTree; LogFail("FormQueryTree: out of memory 6\n"); }
//
// Make the project node a child of the sort node.
//
pSortNode->AddTable( pTree ); pTree = pSortNode;
DWORD sd = QUERY_SORTASCEND; LCID lcid = 0; for( i = 0; i < cSortProp; i++ ) { //
// Add the sort column.
//
if ( !pSortNode->AddSortColumn(pSort->Get(i))) { delete pTree; LogFail("FormQueryTree: out of memory 7\n"); } } }
return pTree; }
void GetCommandTreeErrors(ICommandTree* pCmdTree) {
DBCOMMANDTREE * pTreeCopy = 0; SCODE sc = pCmdTree->GetCommandTree(&pTreeCopy); if (FAILED(sc)) { pCmdTree->Release(); LogFail("GetCommandTree failed, %08x\n", sc); }
ULONG cErrorNodes = 0; DBCOMMANDTREE ** rgpErrorNodes = 0;
sc = pCmdTree->FindErrorNodes(pTreeCopy, &cErrorNodes, &rgpErrorNodes); if (FAILED(sc)) { pCmdTree->FreeCommandTree(&pTreeCopy); pCmdTree->Release(); LogFail("FindErrorNodes failed, %08x\n", sc); }
for (unsigned i=0; i<cErrorNodes; i++) { DBCOMMANDTREE* pNode = rgpErrorNodes[i]; if (pNode->hrError != S_OK) { LogError("tree node %08x\top=%d\tOp Error=%x\n", pNode, pNode->op, pNode->hrError); } else LogError("tree node %x\top=%d\tNO ERROR!!\n", pNode, pNode->op); }
pCmdTree->FreeCommandTree(&pTreeCopy); }
//+---------------------------------------------------------------------------
//
// Function: InstantiateRowset
//
// Synopsis: Forms a query tree consisting of the projection nodes,
// sort node(s), selection node and the restriction tree.
//
// Arguments: [pQueryIn] - Input ICommand or NULL
// [dwDepth] - Query depth, one of QUERY_DEEP or QUERY_SHALLOW
// [pswzScope] - Query scope
// [pTree] - pointer to DBCOMMANDTREE for the query
// [riid] - Interface ID of the desired rowset interface
// [pUnkOuter] - pointer to outer unknown object
// [ppCmdTree] - if non-zero, ICommandTree will be returned here.
// [fExtendedTypes] - if TRUE, set property for extended variants
//
// Returns: IRowsetScroll* - a pointer to an instantiated rowset
//
// History: 22 July 1995 AlanW Created
// 01 July 1997 EmilyB Added outer unknown support for
// ICommand only.
//
// Notes: Although the returned pointer is to IRowsetScroll, the
// returned pointer may only support IRowset, depending
// upon the riid parameter.
//
// Ownership of the query tree is given to the ICommandTree
// object. The caller does not need to delete it.
//
// Use InstantiateMultipleRowsets for categorized queries.
//
//----------------------------------------------------------------------------
static g_cLocatable = 0;
IRowsetScroll * InstantiateRowset( ICommand *pQueryIn, DWORD dwDepth, LPWSTR pwszScope, CDbCmdTreeNode * pTree, REFIID riid, COuterUnk * pobjOuterUnk, ICommandTree **ppCmdTree, BOOL fExtendedTypes ) { // run the query
ICommand * pQuery = 0; if ( 0 == pQueryIn ) { IUnknown * pIUnknown; SCODE sc = CICreateCommand( &pIUnknown, (IUnknown *)pobjOuterUnk, IID_IUnknown, TEST_CATALOG, TEST_MACHINE );
if ( FAILED( sc ) ) LogFail( "InstantiateRowset - error 0x%x Unable to create ICommand\n", sc );
if (pobjOuterUnk) { pobjOuterUnk->Set(pIUnknown); }
if (pobjOuterUnk) sc = pobjOuterUnk->QueryInterface(IID_ICommand, (void **) &pQuery ); else sc = pIUnknown->QueryInterface(IID_ICommand, (void **) &pQuery );
pIUnknown->Release();
if ( FAILED( sc ) ) LogFail( "InstantiateRowset - error 0x%x Unable to QI ICommand\n", sc );
if ( 0 == pQuery ) LogFail( "InstantiateRowset - CICreateCommand succeeded, but returned null pQuery\n" );
sc = SetScopeProperties( pQuery, 1, &pwszScope, &dwDepth );
if ( FAILED( sc ) ) LogFail( "InstantiateRowset - error 0x%x Unable to set scope '%ws'\n", sc, pwszScope );
CheckPropertiesOnCommand( pQuery ); } else { pQuery = pQueryIn; }
ICommandTree *pCmdTree = 0; SCODE sc; if (pobjOuterUnk) sc = pobjOuterUnk->QueryInterface(IID_ICommandTree, (void **)&pCmdTree); else sc = pQuery->QueryInterface(IID_ICommandTree, (void **)&pCmdTree);
if (FAILED (sc) ) { if ( 0 == pQueryIn ) pQuery->Release();
LogFail("QI for ICommandTree failed\n"); }
DBCOMMANDTREE * pRoot = pTree->CastToStruct();
sc = pCmdTree->SetCommandTree( &pRoot, 0, FALSE); if (FAILED (sc) ) { if ( 0 == pQueryIn ) pQuery->Release();
pCmdTree->Release(); LogFail("SetCommandTree failed, %08x\n", sc); }
if (fExtendedTypes) { ICommandProperties *pCmdProp = 0; if (pobjOuterUnk) sc = pobjOuterUnk->QueryInterface(IID_ICommandProperties, (void **)&pCmdProp); else sc = pQuery->QueryInterface(IID_ICommandProperties, (void **)&pCmdProp);
if (FAILED (sc) ) { if ( 0 == pQueryIn ) pQuery->Release();
LogFail("QI for ICommandProperties failed\n"); }
//
// If we should NOT be using a enumerated query, notify pCommand
//
const unsigned MAX_PROPS = 6; DBPROPSET aPropSet[MAX_PROPS]; DBPROP aProp[MAX_PROPS]; ULONG cProp = 0;
aProp[cProp].dwPropertyID = DBPROP_USEEXTENDEDDBTYPES; aProp[cProp].dwOptions = DBPROPOPTIONS_OPTIONAL; aProp[cProp].dwStatus = 0; // Ignored
aProp[cProp].colid = dbcolNull; aProp[cProp].vValue.vt = VT_BOOL; aProp[cProp].vValue.boolVal = VARIANT_TRUE;
aPropSet[cProp].rgProperties = &aProp[cProp]; aPropSet[cProp].cProperties = 1; aPropSet[cProp].guidPropertySet = guidQueryExt;
cProp++;
if (riid == IID_IRowsetLocate) { aProp[cProp].dwPropertyID = DBPROP_IRowsetLocate; aProp[cProp].dwOptions = DBPROPOPTIONS_REQUIRED; aProp[cProp].dwStatus = 0; // Ignored
aProp[cProp].colid = dbcolNull; aProp[cProp].vValue.vt = VT_BOOL; aProp[cProp].vValue.boolVal = VARIANT_TRUE;
aPropSet[cProp].rgProperties = &aProp[cProp]; aPropSet[cProp].cProperties = 1; aPropSet[cProp].guidPropertySet = DBPROPSET_ROWSET;
cProp++;
aProp[cProp].dwPropertyID = DBPROP_BOOKMARKS; aProp[cProp].dwOptions = DBPROPOPTIONS_REQUIRED; aProp[cProp].dwStatus = 0; // Ignored
aProp[cProp].colid = dbcolNull; aProp[cProp].vValue.vt = VT_BOOL; aProp[cProp].vValue.boolVal = VARIANT_TRUE;
aPropSet[cProp].rgProperties = &aProp[cProp]; aPropSet[cProp].cProperties = 1; aPropSet[cProp].guidPropertySet = DBPROPSET_ROWSET;
cProp++;
g_cLocatable++; if (g_cLocatable % 2) { aProp[cProp].dwPropertyID = DBPROP_IDBAsynchStatus; aProp[cProp].dwOptions = DBPROPOPTIONS_REQUIRED; aProp[cProp].dwStatus = 0; // Ignored
aProp[cProp].colid = dbcolNull; aProp[cProp].vValue.vt = VT_BOOL; aProp[cProp].vValue.boolVal = VARIANT_TRUE;
aPropSet[cProp].rgProperties = &aProp[cProp]; aPropSet[cProp].cProperties = 1; aPropSet[cProp].guidPropertySet = DBPROPSET_ROWSET;
cProp++; } if ((g_cLocatable % 4) == 3) { aProp[cProp].dwPropertyID = DBPROP_IRowsetWatchAll; aProp[cProp].dwOptions = DBPROPOPTIONS_REQUIRED; aProp[cProp].dwStatus = 0; // Ignored
aProp[cProp].colid = dbcolNull; aProp[cProp].vValue.vt = VT_BOOL; aProp[cProp].vValue.boolVal = VARIANT_TRUE;
aPropSet[cProp].rgProperties = &aProp[cProp]; aPropSet[cProp].cProperties = 1; aPropSet[cProp].guidPropertySet = DBPROPSET_ROWSET;
cProp++; } } else if (riid == IID_IRowsetScroll) { aProp[cProp].dwPropertyID = DBPROP_IRowsetScroll; aProp[cProp].dwOptions = DBPROPOPTIONS_REQUIRED; aProp[cProp].dwStatus = 0; // Ignored
aProp[cProp].colid = dbcolNull; aProp[cProp].vValue.vt = VT_BOOL; aProp[cProp].vValue.boolVal = VARIANT_TRUE;
aPropSet[cProp].rgProperties = &aProp[cProp]; aPropSet[cProp].cProperties = 1; aPropSet[cProp].guidPropertySet = DBPROPSET_ROWSET;
cProp++;
g_cLocatable++; if (g_cLocatable % 2) { aProp[cProp].dwPropertyID = DBPROP_ROWSET_ASYNCH; aProp[cProp].dwOptions = DBPROPOPTIONS_OPTIONAL; aProp[cProp].dwStatus = 0; // Ignored
aProp[cProp].colid = dbcolNull; aProp[cProp].vValue.vt = VT_I4; aProp[cProp].vValue.lVal = DBPROPVAL_ASYNCH_RANDOMPOPULATION;
aPropSet[cProp].rgProperties = &aProp[cProp]; aPropSet[cProp].cProperties = 1; aPropSet[cProp].guidPropertySet = DBPROPSET_ROWSET;
cProp++; } if ((g_cLocatable % 4) == 3) { aProp[cProp].dwPropertyID = DBPROP_IRowsetWatchAll; aProp[cProp].dwOptions = DBPROPOPTIONS_REQUIRED; aProp[cProp].dwStatus = 0; // Ignored
aProp[cProp].colid = dbcolNull; aProp[cProp].vValue.vt = VT_BOOL; aProp[cProp].vValue.boolVal = VARIANT_TRUE;
aPropSet[cProp].rgProperties = &aProp[cProp]; aPropSet[cProp].cProperties = 1; aPropSet[cProp].guidPropertySet = DBPROPSET_ROWSET;
cProp++; } }
sc = pCmdProp->SetProperties( cProp, aPropSet ); pCmdProp->Release();
if ( FAILED(sc) || DB_S_ERRORSOCCURRED == sc ) { if ( 0 == pQueryIn ) pQuery->Release();
LogError("ICommandProperties::SetProperties failed\n"); } }
IRowset * pRowset = 0;
sc = pQuery->Execute( 0, // no aggr. IUnknown
(riid != IID_IRowset) ? IID_IRowsetIdentity : IID_IRowset, // IID for i/f to return
0, // disp. params
0, // count of rows affected
(IUnknown **)&pRowset); // Returned interface
if (SUCCEEDED (sc) && 0 == pRowset ) { LogError("ICommand::Execute returned success(%x), but pRowset is null\n", sc); if (DB_S_ERRORSOCCURRED == sc) { CheckPropertiesInError(pQuery); } pCmdTree->Release(); pQuery->Release(); Fail(); }
if ( 0 == pQueryIn ) pQuery->Release();
if (FAILED (sc) ) { LogError("ICommand::Execute failed, %08x\n", sc); if (DB_E_ERRORSINCOMMAND == sc) { GetCommandTreeErrors(pCmdTree); } if (DB_E_ERRORSOCCURRED == sc) { CheckPropertiesInError(pQuery); } pCmdTree->Release();
//
// This isn't really kosher, but it helps to avoid spurious (client-side) memory leaks.
//
pQuery->Release(); Fail(); }
if (riid != IID_IRowset) { IRowset * pRowset2 = 0;
sc = pRowset->QueryInterface(riid, (void **)&pRowset2);
if (FAILED (sc) ) { LogError("InstantiateRowset - QI to riid failed, %08x\n", sc); pCmdTree->Release(); Fail(); } pRowset->Release(); pRowset = pRowset2; }
if ( 0 == ppCmdTree ) { pCmdTree->Release(); } else { *ppCmdTree = pCmdTree; }
return (IRowsetScroll *)pRowset; }
//+---------------------------------------------------------------------------
//
// Function: InstantiateMultipleRowsets
//
// Synopsis: Forms a query tree consisting of the projection nodes,
// sort node(s), selection node and the restriction tree.
//
// Arguments: [dwDepth] - Query depth, one of QUERY_DEEP or QUERY_SHALLOW
// [pswzScope] - Query scope
// [pTree] - pointer to DBCOMMANDTREE for the query
// [riid] - Interface ID of the desired rowset interface
// [cRowsets] - Number of rowsets to be returned
// [ppRowsets] - Pointer to location where rowsets are returned
// [ppCmdTree] - if non-zero, ICommandTree will be returned here.
//
// Returns: Nothing
//
// History: 22 July 1995 AlanW Created
//
// Notes: Ownership of the query tree is given to the ICommandTree
// object. The caller does not need to delete it.
//
//----------------------------------------------------------------------------
void InstantiateMultipleRowsets( DWORD dwDepth, LPWSTR pwszScope, CDbCmdTreeNode * pTree, REFIID riid, unsigned cRowsets, IUnknown **ppRowsets, ICommandTree ** ppCmdTree ) { // run the query
ICommand * pQuery = 0; IUnknown * pIUnknown; SCODE scIC = CICreateCommand( &pIUnknown, 0, IID_IUnknown, TEST_CATALOG, TEST_MACHINE );
if (FAILED(scIC)) LogFail( "InstantiateMultipleRowsets - error 0x%x, Unable to create ICommand\n", scIC );
scIC = pIUnknown->QueryInterface(IID_ICommand, (void **) &pQuery ); pIUnknown->Release();
if ( FAILED( scIC ) ) LogFail( "InstantiateMultipleRowsets - error 0x%x Unable to QI ICommand\n", scIC );
if ( 0 == pQuery ) LogFail( "InstantiateMultipleRowsets - CICreateCommand succeeded, but returned null pQuery\n" );
scIC = SetScopeProperties( pQuery, 1, &pwszScope, &dwDepth );
if ( FAILED( scIC ) ) LogFail( "InstantiateMultipleRowsets - error 0x%x Unable to set scope '%ws'\n", scIC, pwszScope );
scIC = SetBooleanProperty( pQuery, DBPROP_CANHOLDROWS, VARIANT_TRUE );
if ( FAILED( scIC ) ) LogFail( "InstantiateMultipleRowsets - error 0x%x Unable to set HoldRows\n", scIC );
CheckPropertiesOnCommand( pQuery );
ICommandTree *pCmdTree = 0; SCODE sc = pQuery->QueryInterface(IID_ICommandTree, (void **)&pCmdTree);
if (FAILED (sc) ) { pQuery->Release(); LogFail("QI for ICommandTree failed\n"); }
DBCOMMANDTREE * pRoot = pTree->CastToStruct(); sc = pCmdTree->SetCommandTree( &pRoot, 0, FALSE); if (FAILED (sc) ) { pQuery->Release(); pCmdTree->Release(); LogFail("SetCommandTree failed, %08x\n", sc); }
sc = pQuery->Execute( 0, // no aggr. IUnknown
riid, // IID for i/f to return
0, // disp. params
0, // count of rows affected
(IUnknown **)ppRowsets); // Returned interface
pQuery->Release();
if (FAILED (sc) ) { LogError("ICommand::Execute failed, %08x\n", sc); if (DB_E_ERRORSINCOMMAND == sc) { GetCommandTreeErrors(pCmdTree); } pCmdTree->Release(); Fail(); }
// Get rowset pointers for all child rowsets
for (unsigned i=1; i<cRowsets; i++) { IUnknown * pRowset = ppRowsets[i-1]; IColumnsInfo * pColumnsInfo = 0; sc = pRowset->QueryInterface(IID_IColumnsInfo, (void **)&pColumnsInfo); if (FAILED (sc) ) { pCmdTree->Release(); LogFail("QI for IColumnsInfo failed\n"); } DBORDINAL iChaptOrdinal = 0; sc = pColumnsInfo->MapColumnIDs(1, &psChapt, &iChaptOrdinal); pColumnsInfo->Release(); if (FAILED (sc) ) { pCmdTree->Release(); LogFail("MapColumnIDs of chapter column failed, %x\n", sc); }
IRowsetInfo * pRowsetInfo = 0; sc = pRowset->QueryInterface(IID_IRowsetInfo, (void **)&pRowsetInfo); if (FAILED (sc) ) { pCmdTree->Release(); LogFail("QI for IRowsetInfo failed\n"); } sc = pRowsetInfo->GetReferencedRowset(iChaptOrdinal, riid, &ppRowsets[i]); pRowsetInfo->Release(); if (FAILED (sc) ) { pCmdTree->Release(); LogFail("GetReferencedRowset failed, %x\n", sc); } }
if ( 0 == ppCmdTree ) { pCmdTree->Release(); } else { *ppCmdTree = pCmdTree; }
return; }
//+-------------------------------------------------------------------------
//
// Function: ReleaseStaticHrows, public
//
// Synopsis: Release a caller allocated HROW array
//
// Arguments: [pRowset] - a pointer to IRowset
// [cRows] - nuumber of HROWs in the array
// [phRows] - a pointer to the HROWs array
//
// Returns: Nothing
//
// History: 03 Oct 1996 AlanW Created
//
//--------------------------------------------------------------------------
const unsigned MAX_ROWSTATUS = 20;
ULONG aRowRefcount[MAX_ROWSTATUS]; DBROWSTATUS aRowStatus[MAX_ROWSTATUS];
void ReleaseStaticHrows( IRowset * pRowset, DBCOUNTITEM cRows, HROW * phRows ) { ULONG *pRefCount = 0; DBROWSTATUS *pRowStatus = 0;
if (cRows <= MAX_ROWSTATUS) { pRefCount = aRowRefcount; pRowStatus = aRowStatus; }
SCODE sc = pRowset->ReleaseRows(cRows, phRows, 0, pRefCount, pRowStatus); if (sc != S_OK && sc != DB_S_ERRORSOCCURRED) { LogError("ReleaseStaticHrows: ReleaseRows failed, sc=%x\n", sc); cFailures++; } else if (cRows <= MAX_ROWSTATUS) { for (unsigned i=0; i<cRows; i++) { if ( pRowStatus[i] != DBROWSTATUS_S_OK && ! ( pRowStatus[i] == DBROWSTATUS_E_INVALID && phRows[i] == DB_NULL_HROW )) { LogError("ReleaseStaticHrows: ReleaseRows row status/refcount, " "hrow=%x ref=%d stat=%d\n", phRows[i], pRefCount[i], pRowStatus[i]); cFailures++; continue; } if ( pRowStatus[i] != DBROWSTATUS_S_OK && sc != DB_S_ERRORSOCCURRED ) { LogError("ReleaseStaticHrows: bad return status, sc = %x\n", sc); cFailures++; continue; } } } } //ReleaseStaticHrows
//+-------------------------------------------------------------------------
//
// Function: FreeHrowsArray, public
//
// Synopsis: Release and free a callee allocated HROW array
//
// Effects: Memory is freed; pointer is zeroed
//
// Arguments: [pRowset] - a pointer to IRowset
// [cRows] - nuumber of HROWs in the array
// [pphRows] - a pointer to pointer to the HROWs array
//
// History: 01 Feb 1995 AlanW Created
//
//--------------------------------------------------------------------------
void FreeHrowsArray( IRowset * pRowset, DBCOUNTITEM cRows, HROW ** pphRows ) { if (*pphRows) { ReleaseStaticHrows(pRowset, cRows, *pphRows); CoTaskMemFree(*pphRows); *pphRows = 0; } } //FreeHrowsArray
//+-------------------------------------------------------------------------
//
// Function: MapColumns, public
//
// Synopsis: Map column IDs in column bindings. Create an accessor
// for the binding array.
//
// Arguments: [pUnknown] -- Interface capable of returning IColumnsInfo and
// IAccessor
// [cCols] -- number of columns in arrays
// [pBindings] -- column data binding array
// [pDbCols] -- column IDs array
// [fByRef] -- true if byref/vector columns should be byref
//
// Returns: HACCESSOR - a read accessor for the column bindings.
//
// History: 18 May 1995 AlanW Created
//
//--------------------------------------------------------------------------
static DBORDINAL aMappedColumnIDs[20];
HACCESSOR MapColumns( IUnknown * pUnknown, DBORDINAL cCols, DBBINDING * pBindings, const DBID * pDbCols, BOOL fByRef ) { IColumnsInfo * pColumnsInfo = 0;
SCODE sc = pUnknown->QueryInterface( IID_IColumnsInfo, (void **)&pColumnsInfo); if ( FAILED( sc ) || pColumnsInfo == 0 ) { LogFail( "IUnknown::QueryInterface for IColumnsInfo returned 0x%lx\n", sc ); }
sc = pColumnsInfo->MapColumnIDs(cCols, pDbCols, aMappedColumnIDs); pColumnsInfo->Release();
if (S_OK != sc) { LogFail( "IColumnsInfo->MapColumnIDs returned 0x%lx\n",sc); }
for (ULONG i = 0; i < cCols; i++) { pBindings[i].iOrdinal = aMappedColumnIDs[i]; if ( fByRef && ( (pBindings[i].wType & (DBTYPE_BYREF|DBTYPE_VECTOR)) || pBindings[i].wType == DBTYPE_BSTR || pBindings[i].wType == VT_LPWSTR || pBindings[i].wType == VT_LPSTR ) && pBindings[i].dwMemOwner != DBMEMOWNER_PROVIDEROWNED) { LogError( "Test error -- MapColumns with fByref, bad accessor %d\n", i); }
if ( ! fByRef && ( (pBindings[i].wType & (DBTYPE_BYREF|DBTYPE_VECTOR)) || pBindings[i].wType == DBTYPE_BSTR || pBindings[i].wType == VT_LPWSTR || pBindings[i].wType == VT_LPSTR ) && pBindings[i].dwMemOwner != DBMEMOWNER_CLIENTOWNED) { LogError( "Test error -- MapColumns without fByref, bad accessor %d\n", i); } }
IAccessor * pIAccessor = 0;
sc = pUnknown->QueryInterface( IID_IAccessor, (void **)&pIAccessor); if ( FAILED( sc ) || pIAccessor == 0 ) { LogFail( "IRowset::QueryInterface for IAccessor returned 0x%lx\n", sc ); }
HACCESSOR hAcc; sc = pIAccessor->CreateAccessor( DBACCESSOR_ROWDATA, cCols, pBindings, 0, &hAcc, 0 ); pIAccessor->Release();
if (S_OK != sc) { LogFail( "IAccessor->CreateAccessor returned 0x%lx\n", sc); } return hAcc; }
//+-------------------------------------------------------------------------
//
// Function: ReleaseAccessor, public
//
// Synopsis: Release an accessor obtained from MapColumns
//
// Arguments: [pUnknown] -- Something that we can QI the IAccessor on
// [hAcc] -- Accessor handle to be released.
//
// Returns: nothing
//
// History: 14 June 1995 AlanW Created
//
//--------------------------------------------------------------------------
void ReleaseAccessor( IUnknown * pUnknown, HACCESSOR hAcc ) { IAccessor * pIAccessor = 0;
SCODE sc = pUnknown->QueryInterface( IID_IAccessor, (void **)&pIAccessor); if ( FAILED( sc ) || pIAccessor == 0 ) { LogFail( "IUnknown::QueryInterface for IAccessor returned 0x%lx\n", sc ); }
ULONG cRef; sc = pIAccessor->ReleaseAccessor( hAcc, &cRef ); pIAccessor->Release();
if (S_OK != sc) { LogFail( "IAccessor->ReleaseAccessor returned 0x%lx\n", sc); } if (0 != cRef) { LogFail( "IAccessor->ReleaseAccessor not last ref: %d\n", cRef); } }
#if defined( DO_NOTIFICATION )
class CNotifyAsynch : public IDBAsynchNotify { public: CNotifyAsynch() : _fChecking(FALSE), _fComplete(FALSE), _cRef(1) {}
~CNotifyAsynch() { if (_fChecking) { if (1 != _cRef) // NOTE: notify objects are static allocated
{ LogError( "Bad refcount on CNotifyAsynch.\n" ); } } }
void DoChecking(BOOL fChecking) { _fChecking = fChecking; }
//
// IUnknown methods.
//
STDMETHOD(QueryInterface) (THIS_ REFIID riid,LPVOID *ppiuk) { *ppiuk = (void **) this; // hold our breath and jump
AddRef(); return S_OK; }
STDMETHOD_(ULONG, AddRef) (THIS) { return ++_cRef; }
STDMETHOD_(ULONG, Release) (THIS) { return --_cRef; }
//
// IDBAsynchNotify methods
//
STDMETHOD(OnLowResource) (THIS_ DB_DWRESERVE dwReserved) { return S_OK; }
STDMETHOD(OnProgress) (THIS_ HCHAPTER hChap, DBASYNCHOP ulOp, DBCOUNTITEM ulProg, DBCOUNTITEM ulProgMax, DBASYNCHPHASE ulStat, LPOLESTR pwszStatus ) { if (ulProg == ulProgMax) _fComplete = TRUE; return S_OK; }
STDMETHOD(OnStop) (THIS_ HCHAPTER hChap, ULONG ulOp, HRESULT hrStat, LPOLESTR pwszStatus ) { return S_OK; }
BOOL IsComplete(void) { return _fComplete; }
private: ULONG _cRef; BOOL _fChecking; BOOL _fComplete; }; #endif //defined( DO_NOTIFICATION )
//+-------------------------------------------------------------------------
//
// Function: WaitForCompletion, public
//
// Synopsis: Loops until query is finished
//
// Arguments: [pRowset] -- Table cursor to wait for
//
// Returns: TRUE if successful
//
// History: 30 Jun 94 AlanW Created
//
//--------------------------------------------------------------------------
int WaitForCompletion( IRowset *pRowset, BOOL fQuiet ) { IDBAsynchStatus * pRowsetAsynch = 0;
SCODE sc = pRowset->QueryInterface( IID_IDBAsynchStatus, (void **)&pRowsetAsynch); if ( sc == E_NOINTERFACE ) return TRUE;
if ( FAILED( sc ) || pRowsetAsynch == 0 ) { LogError( "IRowset::QueryInterface for IDBAsynchStatus returned 0x%lx\n", sc ); return( FALSE ); }
if (! fQuiet) LogProgress( " Waiting for query to complete" );
time( &tstart ); ULONG ulSleep = 25;
BOOL fDone = FALSE;
#if defined( DO_NOTIFICATION )
IConnectionPoint *pConnectionPoint = 0; DWORD dwAdviseID = 0;
CNotifyAsynch Notify;
Notify.DoChecking(TRUE);
//
// Get the connection point container
//
IConnectionPointContainer *pConnectionPointContainer = 0; sc = pRowset->QueryInterface(IID_IConnectionPointContainer, (void **) &pConnectionPointContainer); if (FAILED(sc)) { LogError( "IRowset->QI for IConnectionPointContainer failed: 0x%x\n", sc ); pRowset->Release(); Fail(); }
//
// Make a connection point from the connection point container
//
sc = pConnectionPointContainer->FindConnectionPoint( IID_IDBAsynchNotify, &pConnectionPoint);
if (FAILED(sc) && CONNECT_E_NOCONNECTION != sc ) { LogError( "FindConnectionPoint failed: 0x%x\n",sc ); pRowset->Release(); Fail(); }
pConnectionPointContainer->Release();
if (0 != pConnectionPoint) { //
// Give a callback object to the connection point
//
sc = pConnectionPoint->Advise((IUnknown *) &Notify, &dwAdviseID); if (FAILED(sc)) { LogError( "IConnectionPoint->Advise failed: 0x%x\n",sc ); pConnectionPoint->Release(); pRowset->Release(); Fail(); } } #endif // DO_NOTIFICATION
do { #if defined( DO_NOTIFICATION )
fDone = Notify.IsComplete( ); #else // ! defined( DO_NOTIFICATION )
ULONG ulDen,ulNum,ulPhase; sc = pRowsetAsynch->GetStatus( DB_NULL_HCHAPTER, DBASYNCHOP_OPEN, &ulNum, &ulDen, &ulPhase, 0 );
if ( FAILED( sc ) ) { LogError( "IDBAsynchStatus::GetStatus returned 0x%lx\n", sc ); break; }
fDone = (ulDen == ulNum);
if ( fDone && ulPhase != DBASYNCHPHASE_COMPLETE || ! fDone && ulPhase != DBASYNCHPHASE_POPULATION ) { LogError( "IDBAsynchStatus::GetStatus returned invalid ulPhase %d\n", ulPhase ); break; } #endif // DO_NOTIFICATION
if (fDone) break;
if ( !CheckTime() ) { LogError( "\nQuery took too long to complete.\n" ); break; }
if (! fQuiet) LogProgress( "." ); Sleep( ulSleep ); #if 1
ulSleep *= 2; if (ulSleep > MAXWAITTIME * 1000) ulSleep = MAXWAITTIME * 1000; #else
ulSleep = 500; #endif
} while ( ! fDone );
#if defined( DO_NOTIFICATION )
if ( 0 != pConnectionPoint ) { //
// Clean up notification stuff
//
sc = pConnectionPoint->Unadvise(dwAdviseID);
if (S_OK != sc) { LogError( "IConnectionPoint->Unadvise returned 0x%lx\n",sc); pRowset->Release(); Fail(); }
pConnectionPoint->Release(); //Notify.Release();
} #endif // DO_NOTIFICATION
pRowsetAsynch->Release();
if (fVerbose && !fQuiet) { //
// Was it a long-running query? If so, report how long.
//
time_t tend; time( &tend );
if ( difftime( tend, tstart ) >= MINREPORTTIME ) LogProgress( "Query took %d seconds to complete.", (LONG)difftime(tend, tstart) ); LogProgress("\n"); } return fDone; } //WaitForCompletion
//+-------------------------------------------------------------------------
//
// Function: Delnode, private
//
// Synopsis: Deletes a directory recursively.
//
// Arguments: [wcsDir] -- Directory to kill
//
// Returns: ULONG - error code if failure
//
// History: 22-Jul-92 KyleP Created
// 06 May 1995 AlanW Made recursive, and more tolerant of
// errors in case of interactions with
// CI filtering.
//
//--------------------------------------------------------------------------
ULONG Delnode( WCHAR const * wcsDir ) { WIN32_FIND_DATA finddata; WCHAR wcsBuffer[MAX_PATH];
wcscpy( wcsBuffer, wcsDir ); wcscat( wcsBuffer, L"\\*.*" );
HANDLE hFindFirst = FindFirstFile( wcsBuffer, &finddata );
while( hFindFirst != INVALID_HANDLE_VALUE ) { //
// Look for . and ..
//
if ( ! (finddata.cFileName[0] == '.' && (finddata.cFileName[1] == 0 || (finddata.cFileName[1] == '.' && finddata.cFileName[2] == 0 ) ) ) ) { wcscpy( wcsBuffer, wcsDir ); wcscat( wcsBuffer, L"\\"); wcscat( wcsBuffer, finddata.cFileName );
if ( finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) Delnode( wcsBuffer); else if ( !DeleteFile( wcsBuffer ) ) { ULONG ulFailure = GetLastError(); LogError("Error 0x%lx deleting %ws\n", ulFailure, wcsBuffer); return (ulFailure == 0) ? 0xFFFFFFFF : ulFailure; } }
if ( !FindNextFile( hFindFirst, &finddata ) ) { FindClose( hFindFirst ); break; } }
RemoveDirectory( (WCHAR *)wcsDir );
// if racing with CI Filtering, retry after a short time
if (GetLastError() == ERROR_DIR_NOT_EMPTY) { Sleep(2 * 1000); RemoveDirectory( (WCHAR *)wcsDir ); }
//
// Make sure it's removed.
//
if ( FindFirstFile( (WCHAR *)wcsDir, &finddata ) != INVALID_HANDLE_VALUE ) { ULONG ulFailure = GetLastError(); LogError("Error 0x%lx removing directory %ws\n", ulFailure, wcsDir); return (ulFailure == 0) ? 0xFFFFFFFF : ulFailure; } return 0; } //Delnode
//+-------------------------------------------------------------------------
//
// Function: BuildFile, private
//
// Synopsis: Creates a file and fills it with data.
//
// Arguments: [wcsFile] -- Path to file.
// [data] -- Contents of file.
// [cb] -- Size in bytes of [data]
//
// History: 22-Jul-92 KyleP Created
//
//--------------------------------------------------------------------------
void BuildFile( WCHAR const * wcsFile, char const * data, ULONG cb ) { ULONG mode = CREATE_NEW;
HANDLE hFile = CreateFile( (WCHAR *)wcsFile, GENERIC_WRITE, 0, 0, mode, 0, 0 );
if ( hFile == INVALID_HANDLE_VALUE ) { LogError( "Error 0x%lx opening file %ws\n", GetLastError(), wcsFile ); CantRun(); }
ULONG ulWritten;
if ( !WriteFile( hFile, data, cb, &ulWritten, 0 ) || ulWritten != cb ) { LogError( "Error 0x%lx writing file %ws\n", GetLastError(), wcsFile ); CantRun(); }
if ( !CloseHandle( hFile ) ) { LogError( "Error 0x%lx closing file %ws\n", GetLastError(), wcsFile ); CantRun(); } } //BuildFile
//+-------------------------------------------------------------------------
//
// Function: CantRun, private
//
// Synopsis: Prints a "Can't Run" message and exits.
//
// History: 09 Oct 1995 Alanw Created
//
//--------------------------------------------------------------------------
void CantRun() { printf( "%s: CAN'T RUN\n", ProgName ); if (! _isatty(_fileno(stdout)) ) fprintf( stderr, "%s: CAN'T RUN\n", ProgName );
// CIShutdown();
CoUninitialize(); exit( 2 ); } //Fail
//+-------------------------------------------------------------------------
//
// Function: Fail, private
//
// Synopsis: Prints a failure message and exits.
//
// History: 22-Jul-92 KyleP Created
//
//--------------------------------------------------------------------------
void Fail() { printf( "%s: FAILED\n", ProgName ); if (! _isatty(_fileno(stdout)) ) fprintf( stderr, "%s: FAILED\n", ProgName );
// CIShutdown();
CoUninitialize(); exit( 1 ); } //Fail
//+-------------------------------------------------------------------------
//
// Function: LogProgress, public
//
// Synopsis: Prints a verbose-mode message.
//
// Arguments: [pszfmt] -- Format string
//
// History: 13-Jul-93 KyleP Created
//
//--------------------------------------------------------------------------
void LogProgress( char const * pszfmt, ... ) { if ( fVerbose ) { va_list pargs;
va_start(pargs, pszfmt); vprintf( pszfmt, pargs ); va_end(pargs); } } //LogProgress
//+-------------------------------------------------------------------------
//
// Function: LogError, public
//
// Synopsis: Prints a verbose-mode message.
//
// Arguments: [pszfmt] -- Format string
//
// History: 13-Jul-93 KyleP Created
//
//--------------------------------------------------------------------------
static fLogError = TRUE;
void LogError( char const * pszfmt, ... ) { if ( fVerbose || fLogError ) { fLogError = FALSE; // print only first error if non-verbose
va_list pargs;
va_start(pargs, pszfmt); vprintf( pszfmt, pargs ); va_end(pargs); } } //LogError
//+-------------------------------------------------------------------------
//
// Function: LogFail, public
//
// Synopsis: Prints a verbose-mode message and fails the drt
//
// Arguments: [pszfmt] -- Format string
//
// History: 3-Apr-95 dlee Created
//
//--------------------------------------------------------------------------
void LogFail( char const * pszfmt, ... ) { if ( fVerbose || fLogError ) { va_list pargs;
va_start(pargs, pszfmt); vprintf( pszfmt, pargs ); va_end(pargs); }
Fail(); } //LogFail
//+-------------------------------------------------------------------------
//
// Function: FormatGuid, public
//
// Synopsis: Formats a guid in standard form
//
// Arguments: [pszfmt] -- Format string
//
// Returns: PWSTR - pointer to formatted guid
//
// Notes: Return value points to static memory.
//
// History: 12 Sep 1997 AlanW Created
//
//--------------------------------------------------------------------------
WCHAR * FormatGuid( GUID const & guid ) { static WCHAR awchGuid[40]; StringFromGUID2( guid, awchGuid, sizeof awchGuid / sizeof WCHAR ); return awchGuid; } //FormatGuid
BOOL CheckTime() { if ( fTimeout ) { time_t tend;
//
// Did we run out of time?
//
time( &tend );
return ( difftime( tend, tstart ) <= MAXTIME );
} else { return( TRUE ); } } //CheckTime
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
#if defined(UNIT_TEST)
//+-------------------------------------------------------------------------
//
// Class: CCompareDBValues
//
// Purpose: Compares oledb values.
//
// History: 25-May-95 dlee Created
//
//--------------------------------------------------------------------------
class CCompareDBValues : INHERIT_UNWIND { INLINE_UNWIND( CCompareDBValues )
public:
CCompareDBValues() : _aColComp( 0 ), _cColComp( 0 ) { END_CONSTRUCTION( CCompareDBValues ); }
~CCompareDBValues() { delete _aColComp; }
void Init( int cCols, CSortSet const * psort, DBTYPEENUM * aTypes );
inline BOOL IsEmpty() { return( _aColComp == 0 ); }
BOOL IsLT( BYTE ** rows1, ULONG *acb1, BYTE **rows2, ULONG *acb2 ); BOOL IsGT( BYTE ** rows1, ULONG *acb1, BYTE **rows2, ULONG *acb2 ); BOOL IsEQ( BYTE ** rows1, ULONG *acb1, BYTE **rows2, ULONG *acb2 );
private:
struct SColCompare { ULONG _dir; // Direction
ULONG _pt; // Property type (matches fns below)
//
// LE/GE are a bit of a misnomer. If the sort order for a column
// is reversed ( large to small ) then LE is really GE and
// vice-versa.
//
FDBCmp _comp; int _DirMult; // -1 if directions reversed.
};
UINT _cColComp; SColCompare * _aColComp; };
//+-------------------------------------------------------------------------
//
// Member: CCompareDBValues::Init, public
//
// Synopsis: [Re] Initializes property comparator to use a different
// sort order.
//
// Arguments: [cCols] -- Count of columns
// [pSort] -- Sort keys
// [aTypes] -- Data types of each column to be compared
//
// History: 25-May-95 dlee Created
//
//--------------------------------------------------------------------------
void CCompareDBValues::Init( int cCols, CSortSet const * pSort, DBTYPEENUM * aTypes ) { delete _aColComp; _aColComp = 0;
if ( cCols > 0 ) { _cColComp = cCols; _aColComp = new SColCompare[ _cColComp ];
for ( unsigned i = 0; i < _cColComp; i++ ) { _aColComp[i]._dir = pSort->Get(i).dwOrder; _aColComp[i]._DirMult = ( ( _aColComp[i]._dir & QUERY_SORTDESCEND ) != 0 ) ? -1 : 1; _aColComp[i]._pt = aTypes[i]; _aColComp[i]._comp = VariantCompare.GetDBComparator( aTypes[i] ); } } } //Init
//+-------------------------------------------------------------------------
//
// Member: CCompareDBValues::IsLT, public
//
// Synopsis: Compares two rows (property sets).
//
// Arguments: [row1] -- First row.
// [row2] -- Second row.
//
// Returns: TRUE if [row1] < [row2].
//
// History: 25-May-95 dlee Created
//
//--------------------------------------------------------------------------
BOOL CCompareDBValues::IsLT( BYTE ** row1, ULONG * acb1, BYTE ** row2, ULONG * acb2 ) { //Win4Assert( !IsEmpty() );
int iLT = 0;
for ( unsigned i = 0; 0 == iLT && i < _cColComp; i++ ) { if ( 0 != _aColComp[i]._comp ) iLT = _aColComp[i]._comp( row1[i], acb1[i], row2[i], acb2[i] ) * _aColComp[i]._DirMult; else LogFail("islt has no comparator!\n"); }
return ( iLT < 0 ); } //IsLT
//+-------------------------------------------------------------------------
//
// Member: CCompareDBValues::IsGT, public
//
// Synopsis: Compares two rows (property sets).
//
// Arguments: [row1] -- First row.
// [row2] -- Second row.
//
// Returns: TRUE if [row1] > [row2].
//
// History: 25-May-95 dlee Created
//
//--------------------------------------------------------------------------
BOOL CCompareDBValues::IsGT( BYTE ** row1, ULONG * acb1, BYTE ** row2, ULONG * acb2 ) { //Win4Assert( !IsEmpty() );
int iGT = 0;
for ( unsigned i = 0; 0 == iGT && i < _cColComp; i++ ) { if ( 0 != _aColComp[i]._comp ) iGT = _aColComp[i]._comp( row1[i], acb1[i], row2[i], acb2[i] ) * _aColComp[i]._DirMult; }
return ( iGT > 0 ); } //IsGT
//+-------------------------------------------------------------------------
//
// Member: CCompareDBValues::IsEQ, public
//
// Synopsis: Compares two rows (property sets).
//
// Arguments: [row1] -- First row.
// [row2] -- Second row.
//
// Returns: TRUE if [row1] == [row2].
//
// History: 25-May-95 dlee Created
//
//--------------------------------------------------------------------------
BOOL CCompareDBValues::IsEQ( BYTE ** row1, ULONG * acb1, BYTE ** row2, ULONG * acb2 ) { //Win4Assert( !IsEmpty() );
int iEQ = 0;
for ( unsigned i = 0; 0 == iEQ && i < _cColComp; i++ ) { if ( 0 != _aColComp[i]._comp ) iEQ = _aColComp[i]._comp( row1[i], acb1[i], row2[i], acb2[i] ); }
return ( iEQ == 0 ); } //IsEQ
struct SSortTestRow { PROPVARIANT vI4; // variant: i4
PROPVARIANT vV_I4; // variant: i4 vector
DBVECTOR aI4; // dbvector: i4
WCHAR aWSTR[20]; // inline: wstr
WCHAR * pWSTR; // inline: byref wstr
PROPVARIANT vLPWSTR; // variant: lpwstr
PROPVARIANT vV_LPWSTR; // variant: lpwstr vector
DBVECTOR aLPWSTR; // dbvector: byref wstr
int i; // inline: i4
};
long ai4[] = { 3, 7, 9 }; LPWSTR alpwstr[] = { L"one", L"two", L"three" };
void InitTest( SSortTestRow &s ) { s.vI4.vt = VT_I4; s.vI4.lVal = 4;
s.vV_I4.vt = VT_VECTOR | VT_I4; s.vV_I4.cal.cElems = 3; s.vV_I4.cal.pElems = ai4;
s.aI4.size = 3; s.aI4.ptr = ai4;
s.aWSTR[0] = L'h'; s.aWSTR[1] = L'e'; s.aWSTR[2] = L'l';
s.pWSTR = L"yello";
s.vLPWSTR.vt = VT_LPWSTR; s.vLPWSTR.pwszVal = L"green";
s.vV_LPWSTR.vt = VT_VECTOR | VT_LPWSTR; s.vV_LPWSTR.calpwstr.cElems = 3; s.vV_LPWSTR.calpwstr.pElems = alpwstr;
s.aLPWSTR.size = 3; s.aLPWSTR.ptr = alpwstr; } //InitTest
SSortTestRow sr1,sr2,sr3;
BYTE * apr1[] = { { (BYTE *) & sr1.vI4 }, { (BYTE *) & sr1.vV_I4 }, { (BYTE *) & sr1.aI4 }, { (BYTE *) & sr1.aWSTR }, { (BYTE *) & sr1.pWSTR }, { (BYTE *) & sr1.vLPWSTR }, { (BYTE *) & sr1.vV_LPWSTR }, { (BYTE *) & sr1.aLPWSTR }, { (BYTE *) & sr1.i }, };
BYTE * apr2[] = { { (BYTE *) & sr2.vI4 }, { (BYTE *) & sr2.vV_I4 }, { (BYTE *) & sr2.aI4 }, { (BYTE *) & sr2.aWSTR }, { (BYTE *) & sr2.pWSTR }, { (BYTE *) & sr2.vLPWSTR }, { (BYTE *) & sr2.vV_LPWSTR }, { (BYTE *) & sr2.aLPWSTR }, { (BYTE *) & sr2.i }, };
BYTE * apr3[] = { { (BYTE *) & sr3.vI4 }, { (BYTE *) & sr3.vV_I4 }, { (BYTE *) & sr3.aI4 }, { (BYTE *) & sr3.aWSTR }, { (BYTE *) & sr3.pWSTR }, { (BYTE *) & sr3.vLPWSTR }, { (BYTE *) & sr3.vV_LPWSTR }, { (BYTE *) & sr3.aLPWSTR }, { (BYTE *) & sr3.i }, };
DBTYPEENUM aEnum[] = { { DBTYPE_VARIANT }, { DBTYPE_VARIANT }, { (DBTYPEENUM) (DBTYPE_VECTOR | DBTYPE_I4) }, { DBTYPE_WSTR }, { (DBTYPEENUM) (DBTYPE_BYREF | DBTYPE_WSTR) }, { DBTYPE_VARIANT }, { DBTYPE_VARIANT }, { (DBTYPEENUM) (DBTYPE_VECTOR | DBTYPE_BYREF | DBTYPE_WSTR) }, { DBTYPE_I4 }, };
ULONG aLen[] = { 0, 0, 0, 6, 0, 0, 0, 0, };
const ULONG cArray = sizeof aEnum / sizeof DBTYPEENUM;
void DBSortTest() { InitTest( sr1 ); sr1.i = 1;
InitTest( sr2 ); sr2.i = 2;
InitTest( sr3 ); sr3.i = 3;
CSortSet ss( cArray );
SSortKey sk = { 0, 0, 0 };
for (unsigned x = 0; x < cArray; x++) ss.Add( sk, x );
CCompareDBValues c;
c.Init( cArray, &ss, aEnum );
BOOL fLT = c.IsLT( apr1, aLen, apr2, aLen );
if (!fLT) LogFail("compare test 1 failed\n");
fLT = c.IsLT( apr2, aLen, apr1, aLen );
if (fLT) LogFail("compare test 2 failed\n");
} //DBSortTest
#endif // UNIT_TEST
BOOL SetBooleanProperty ( ICommand * pCmd, DBPROPID dbprop, VARIANT_BOOL f ) { ICommandProperties * pCmdProp;
SCODE sc = pCmd->QueryInterface( IID_ICommandProperties, (void **) &pCmdProp );
if ( FAILED( sc ) ) { LogError( "Error 0x%x from QI for ICommandProperties\n", sc ); return sc; }
DBPROPSET aPropSet[1]; DBPROP aProp[1];
aProp[0].dwPropertyID = dbprop; aProp[0].dwOptions = DBPROPOPTIONS_REQUIRED; aProp[0].dwStatus = 0; // Ignored
aProp[0].colid = dbcolNull; aProp[0].vValue.vt = VT_BOOL; aProp[0].vValue.boolVal = f;
aPropSet[0].rgProperties = &aProp[0]; aPropSet[0].cProperties = 1; aPropSet[0].guidPropertySet = DBPROPSET_ROWSET;
sc = pCmdProp->SetProperties( 1, aPropSet ); pCmdProp->Release();
if ( FAILED(sc) ) LogError( "ICommandProperties::SetProperties returned 0x%x\n", sc );
return sc; }
SCODE SetScopeProperties( ICommand * pCmd, unsigned cDirs, WCHAR const * const * apDirs, ULONG const * aulFlags, WCHAR const * const * apCats, WCHAR const * const * apMachines ) { ICommandProperties * pCmdProp;
SCODE sc = pCmd->QueryInterface( IID_ICommandProperties, (void **) &pCmdProp );
if ( FAILED( sc ) ) { LogError( "Error 0x%x from QI for ICommandProperties\n", sc ); return sc; }
BSTR abDirs[10]; if ( 0 != apDirs ) for ( unsigned i = 0; i < cDirs; i++ ) abDirs[i] = SysAllocString( apDirs[i] );
BSTR abCats[10]; if ( 0 != apCats ) for ( unsigned i = 0; i < cDirs; i++ ) abCats[i] = SysAllocString( apCats[i] );
BSTR abMachines[10]; if ( 0 != apMachines ) for ( unsigned i = 0; i < cDirs; i++ ) abMachines[i] = SysAllocString( apMachines[i] );
//
// Cheating here. Big time. These aren't really BSTRs, but I also know the
// size before the string won't be referenced. By ::SetProperties.
//
SAFEARRAY saScope = { 1, // Dimension
FADF_AUTO | FADF_BSTR, // Flags: on stack, contains BSTRs
sizeof(BSTR), // Size of an element
1, // Lock count. 1 for safety.
(void *)abDirs, // The data
{ cDirs, 0 } }; // Bounds (element count, low bound)
SAFEARRAY saDepth = { 1, // Dimension
FADF_AUTO, // Flags: on stack
sizeof(LONG), // Size of an element
1, // Lock count. 1 for safety.
(void *)aulFlags, // The data
{ cDirs, 0 } }; // Bounds (element count, low bound)
SAFEARRAY saCatalog = { 1, // Dimension
FADF_AUTO | FADF_BSTR,// Flags: on stack, contains BSTRs
sizeof(BSTR), // Size of an element
1, // Lock count. 1 for safety.
(void *)abCats, // The data
{ cDirs, 0 } }; // Bounds (element count, low bound)
SAFEARRAY saMachine = { 1, // Dimension
FADF_AUTO | FADF_BSTR,// Flags: on stack, contains BSTRs
sizeof(BSTR), // Size of an element
1, // Lock count. 1 for safety.
(void *)abMachines, // The data
{ cDirs, 0 } }; // Bounds (element count, low bound)
DBPROP aQueryPropsScopeOnly[2] = { { DBPROP_CI_INCLUDE_SCOPES, 0, DBPROPSTATUS_OK, {0, 0, 0}, { VT_BSTR | VT_ARRAY, 0, 0, 0, (LONG_PTR)&saScope } }, { DBPROP_CI_DEPTHS , 0, DBPROPSTATUS_OK, {0, 0, 0}, { VT_I4 | VT_ARRAY, 0, 0, 0, (LONG_PTR)&saDepth } } };
DBPROPSET QueryPropsetScopeOnly = { aQueryPropsScopeOnly, 2, DBPROPSET_FSCIFRMWRK_EXT };
DBPROP aQueryProps[3] = { { DBPROP_CI_INCLUDE_SCOPES , 0, DBPROPSTATUS_OK, {0, 0, 0}, { VT_BSTR | VT_ARRAY, 0, 0, 0, (LONG_PTR)&saScope } }, { DBPROP_CI_DEPTHS , 0, DBPROPSTATUS_OK, {0, 0, 0}, { VT_I4 | VT_ARRAY, 0, 0, 0, (LONG_PTR)&saDepth } }, { DBPROP_CI_CATALOG_NAME , 0, DBPROPSTATUS_OK, {0, 0, 0}, { VT_BSTR | VT_ARRAY, 0, 0, 0, (LONG_PTR)&saCatalog } } };
DBPROP aCoreProps[1] = { { DBPROP_MACHINE , 0, DBPROPSTATUS_OK, {0, 0, 0}, { VT_BSTR | VT_ARRAY, 0, 0, 0, (LONG_PTR)&saMachine } } };
DBPROPSET aAllPropsets[2] = { {aQueryProps, 3, DBPROPSET_FSCIFRMWRK_EXT } , {aCoreProps , 1, DBPROPSET_CIFRMWRKCORE_EXT } };
if ( 0 == apCats || 0 == apMachines ) sc = pCmdProp->SetProperties( 1, &QueryPropsetScopeOnly ); else sc = pCmdProp->SetProperties( 2, aAllPropsets );
if ( 0 != apMachines ) for ( unsigned i = 0; i < cDirs; i++ ) SysFreeString( abMachines[i] );
if ( 0 != apCats ) for ( unsigned i = 0; i < cDirs; i++ ) SysFreeString( abCats[i] );
if ( 0 != apDirs ) for ( unsigned i = 0; i < cDirs; i++ ) SysFreeString( abDirs[i] );
pCmdProp->Release();
if ( FAILED(sc) ) LogError( "ICommandProperties::SetProperties returned 0x%x\n", sc );
return sc; }
|