You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
13291 lines
407 KiB
13291 lines
407 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// 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;
|
|
}
|
|
|