//-------------------------------------------------------------------- // Microsoft OLE DB Test // // Copyright 1995-2000 Microsoft Corporation. // // @doc // // @module IDBSCHMR.CPP | Source file for IDBSchemaRowset test // //-------------------------------------------------------------------- #include "modstandard.hpp" #include "IDBSchmR.h" #include "extralib.h" #define CLEANUP(x) if(x) goto CLEANUP; #define TERMINATE(x) if(x) return FALSE; #define CONTINUE(x) if (x) return TRUE; #define PI (IUnknown *) #define PPI (IUnknown **) #define PPPI (IUnknown ***) #define WC (WCHAR *) #define INIT Init_Stuff(); #define FREE Free_Stuff(); // free other pointer #define RESTRICTNOTSUPPORTED(x) if(!(m_currentBitMask & x))m_fAtLeast1UnsupportedRestrictionIsSet=TRUE; IDBSchemaRowset * g_pIDBSchemaRowset=NULL; BOOL g_fKagera; // Track whether running against Kagera BOOL g_fSQLServer; // Track whether the backend is SQL Server // Initially use Sql Server provider specific guid and prop value GUID g_guidHistogramRowset = DBGUID_HISTOGRAM_ROWSET; DBPROPID g_propTableStatistics = DBPROP_TABLESTATISTICS; ULONG cSchemas; GUID * rgSchemas; ULONG * rgRestrictions=NULL; // Global strings for primary and foreign keys. WCHAR *g_pwszAddPrimaryKeyOnTable1=NULL; WCHAR *g_pwszAddPrimaryKeyOnTable2=NULL; WCHAR *g_pwszAddForeignKeyOnTable1=NULL; WCHAR *g_pwszDropPrimaryKeyConstraint1=NULL; WCHAR *g_pwszDropForeignKeyConstraint1=NULL; WCHAR *g_pwszDropPrimaryKeyConstraint2=NULL; CTable *g_pKeyTable1=NULL; CTable *g_pKeyTable2=NULL; BOOL g_fKeysOnTable=FALSE; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // CErrorCache // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #define CCHECK(ErrObj, hrAct, hrExp, ulErr, pwszMsg, fWarn) (ErrObj.CCheck((hrAct), \ (hrExp), (ulErr), (pwszMsg), (fWarn), LONGSTRING(__FILE__), (__LINE__))) #define CCOMPARE(ErrObj, fResult, ulErr, pwszMsg, fWarn) (ErrObj.CCompare((fResult), \ (ulErr), (pwszMsg), (fWarn), LONGSTRING(__FILE__), (__LINE__))) enum ERROR_CACHE_ENUM { // DBSCHEMA_TABLE_STATISTICS cached errors EC_EXTRA_COLUMN = 1, EC_BAD_COL_OR_TUPLE_CARD, EC_BAD_TABLE_CARDINALITY, EC_BAD_HR_OPENHISTOGRAM, EC_NULL_RANGE_COUNT, EC_BAD_RANGE_ROWS, EC_BAD_EQ_ROWS, EC_BAD_DISTINCT_RANGE_ROWS, // DBSCHEMA_COLUMNS cached errors EC_BAD_COLUMN_FLAGS, EC_BAD_CHARACTER_MAXIMUM_LENGTH, EC_BAD_CHARACTER_OCTET_LENGTH, EC_BAD_DATETIME_PRECISION, EC_COLUMNS_NULL_NUMERIC_SCALE, EC_COLUMNS_BAD_NUMERIC_PRECISION, // DBSCHEMA_INDEXES cached errors EC_INDEXES_NULLS_ISNULL, EC_INDEXES_INDEX_NAME_ISNULL, EC_INDEXES_UNIQUE_ISNULL, EC_INDEXES_AUTO_UPDATE_ISNULL, // DBSCHEMA_PROCEDURES cached errors EC_PROCEDURES_PROC_DEF_ISNULL, // DBSCHEMA_PROCEDURE_COLUMNS cached errors EC_PROC_COLS_IS_NULLABLE_ISNULL, EC_INVALID_IS_NULLABLE, // DBSCHEMA_PROVIDER_TYPES cached errors EC_INCORRECT_SORT, EC_MAX_ERROR_NUMBER // Must always be last enum }; LPWSTR g_ppwszErrorStrings[] = { // DBSCHEMA_TABLE_STATISTICS cached errors L"EC_EXTRA_COLUMN", L"EC_BAD_COL_OR_TUPLE_CARD", L"EC_BAD_TABLE_CARDINALITY", L"EC_BAD_HR_OPENHISTOGRAM", L"EC_NULL_RANGE_COUNT", L"EC_BAD_RANGE_ROWS", L"EC_BAD_EQ_ROWS", L"EC_BAD_DISTINCT_RANGE_ROWS", // DBSCHEMA_COLUMNS cached errors L"EC_BAD_COLUMN_FLAGS", L"EC_BAD_CHARACTER_MAXIMUM_LENGTH", L"EC_BAD_CHARACTER_OCTET_LENGTH", L"EC_BAD_DATETIME_PRECISION", L"EC_COLUMNS_NULL_NUMERIC_SCALE", L"EC_COLUMNS_BAD_NUMERIC_PRECISION", // DBSCHEMA_INDEXES cached errors L"EC_INDEXES_NULLS_ISNULL", L"EC_INDEXES_INDEX_NAME_ISNULL", L"EC_INDEXES_UNIQUE_ISNULL", L"EC_INDEXES_AUTO_UPDATE_ISNULL", // DBSCHEMA_PROCEDURES cached errors L"EC_PROCEDURES_PROC_DEF_ISNULL", // DBSCHEMA_PROCEDURE_COLUMNS cached errors L"EC_PROC_COLS_IS_NULLABLE_ISNULL", L"EC_INVALID_IS_NULLABLE", // DBSCHEMA_PROVIDER_TYPES cached errors L"EC_INCORRECT_SORT", }; class CErrorCache { private: ULONG m_ulDebugMode; ULONG m_ulMaxCachedErrors; ULONG * m_pulErrorCache; ULONG m_cErrorsCached; BOOL IsErrorCached(ULONG ulError); public: CErrorCache(void); ~CErrorCache(void); BOOL Init(ULONG ulDebugMode); BOOL CCheck(HRESULT hrActual, HRESULT hrExpected, ULONG ulError = 0, LPWSTR pwszMessage = NULL, BOOL fWarning = FALSE, LPWSTR pwszFile = NULL, ULONG ulLine = 0); BOOL CCompare(BOOL fResult, ULONG ulError = 0, LPWSTR pwszMessage = NULL, BOOL fWarning = FALSE, LPWSTR pwszFile = NULL, ULONG ulLine = 0); }; CErrorCache::CErrorCache(void) { m_ulDebugMode = 0; m_ulMaxCachedErrors = EC_MAX_ERROR_NUMBER-1; m_pulErrorCache = NULL; m_cErrorsCached = 0; } CErrorCache::~CErrorCache(void) { // Print summary of errors cached if there is at least one // error cached. if (m_cErrorsCached) { odtLog << L"\n\nThe following errors were cached:\n\n"; for (ULONG iErr = 0; iErr < m_ulMaxCachedErrors; iErr++) if (m_pulErrorCache[iErr]) odtLog << L"\t" << g_ppwszErrorStrings[iErr] << L"\t\t" << m_pulErrorCache[iErr] << L"\n"; odtLog << L"\n\n"; odtLog << L"To see error details instead of this summary please add 'DEBUGMODE=FULL;' to the init string.\n\n"; } SAFE_FREE(m_pulErrorCache); } BOOL CErrorCache::Init(ULONG ulDebugMode) { BOOL fResult = FALSE; m_ulDebugMode = ulDebugMode; // Allocate memory for error cache. Since we don't expect this to be more than // a few 10's of items just use a static array. SAFE_ALLOC(m_pulErrorCache, ULONG, m_ulMaxCachedErrors); // Init all cache locations to 0, no error cached memset(m_pulErrorCache, 0, m_ulMaxCachedErrors*sizeof(ULONG)); fResult = TRUE; CLEANUP: return fResult; } BOOL CErrorCache::IsErrorCached(ULONG ulError) { ASSERT(ulError <= m_ulMaxCachedErrors); // In case this gets called before init. if (!m_pulErrorCache) return FALSE; // If the cache has a value other than 0 then it's been cached return m_pulErrorCache[ulError-1]; } BOOL CErrorCache::CCheck(HRESULT hrActual, HRESULT hrExpected, ULONG ulError, LPWSTR pwszMessage, BOOL fWarning, LPWSTR pwszFile, ULONG ulLine) { BOOL fReturn = hrActual == hrExpected; // Check for valid error number if (ulError == 0 || ulError > m_ulMaxCachedErrors) return FALSE; // If this error is already cached then we allow it to pass unless debugmode is full. if (IsErrorCached(ulError) && !(m_ulDebugMode & DEBUGMODE_FULL)) { if (!fReturn) // Update the cache m_pulErrorCache[ulError-1]++; return fReturn; } // Otherwise we have to perform the comparison. Note we can't just return the // value from PrivLibValidate because on warning it always returns TRUE even on // a miscompare PrivlibValidate(hrActual, hrExpected, fWarning, pwszFile, ulLine); // If the comparison failed, then print failure message if (!fReturn) { // Update the cache if (!(m_ulDebugMode & DEBUGMODE_FULL)) { m_pulErrorCache[ulError-1]++; m_cErrorsCached++; } if (pwszMessage) odtLog << pwszMessage << L"\n"; } return fReturn; } BOOL CErrorCache::CCompare(BOOL fResult, ULONG ulError, LPWSTR pwszMessage, BOOL fWarning, LPWSTR pwszFile, ULONG ulLine) { // Check for valid error number if (ulError == 0 || ulError > m_ulMaxCachedErrors) return FALSE; // If this error is already cached then we allow it to pass unless debugmode is full. if (IsErrorCached(ulError) && !(m_ulDebugMode & DEBUGMODE_FULL)) { if (!fResult) // Update the cache m_pulErrorCache[ulError-1]++; return fResult; } // Otherwise we have to perform the comparison. Note we can't just return the // value from PrivLibValidate because on warning it always returns TRUE even on // a miscompare PrivlibCompare(fResult, fWarning, pwszFile, ulLine); // If the comparison failed, then print failure message if (!fResult) { if (!(m_ulDebugMode & DEBUGMODE_FULL)) { m_pulErrorCache[ulError-1]++; m_cErrorsCached++; } if (pwszMessage) odtLog << pwszMessage << L"\n"; } return fResult; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // TraceSchemaName // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ULONG TraceSchemaName ( GUID guid, BOOL fToScreen, BOOL fAddNewLine ) { LPWSTR pwszSchemaName = L""; // Find the schema if(IsEqualGUID(DBSCHEMA_ASSERTIONS,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_ASSERTIONS; else if(IsEqualGUID(DBSCHEMA_CATALOGS,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_CATALOGS; else if(IsEqualGUID(DBSCHEMA_CHARACTER_SETS,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_CHARACTER_SETS; else if(IsEqualGUID(DBSCHEMA_CHECK_CONSTRAINTS,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_CHECK_CONSTRAINTS; else if(IsEqualGUID(DBSCHEMA_COLLATIONS,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_COLLATIONS; else if(IsEqualGUID(DBSCHEMA_COLUMN_DOMAIN_USAGE,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_COLUMN_DOMAIN_USAGE; else if(IsEqualGUID(DBSCHEMA_COLUMN_PRIVILEGES,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_COLUMN_PRIVILEGES; else if(IsEqualGUID(DBSCHEMA_COLUMNS,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_COLUMNS; else if(IsEqualGUID(DBSCHEMA_CONSTRAINT_COLUMN_USAGE,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_CONSTRAINT_COLUMN_USAGE; else if(IsEqualGUID(DBSCHEMA_CONSTRAINT_TABLE_USAGE,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_CONSTRAINT_TABLE_USAGE; else if(IsEqualGUID(DBSCHEMA_FOREIGN_KEYS,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_FOREIGN_KEYS; else if(IsEqualGUID(DBSCHEMA_INDEXES,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_INDEXES; else if(IsEqualGUID(DBSCHEMA_KEY_COLUMN_USAGE,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_KEY_COLUMN_USAGE; else if(IsEqualGUID(DBSCHEMA_PRIMARY_KEYS,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_PRIMARY_KEYS; else if(IsEqualGUID(DBSCHEMA_PROCEDURE_COLUMNS,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_PROCEDURE_COLUMNS; else if(IsEqualGUID(DBSCHEMA_PROCEDURE_PARAMETERS, guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_PROCEDURE_PARAMETERS; else if(IsEqualGUID(DBSCHEMA_PROCEDURES,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_PROCEDURES; else if(IsEqualGUID(DBSCHEMA_PROVIDER_TYPES,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_PROVIDER_TYPES; else if(IsEqualGUID(DBSCHEMA_REFERENTIAL_CONSTRAINTS,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_REFERENTIAL_CONSTRAINTS; else if(IsEqualGUID(DBSCHEMA_SCHEMATA,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_SCHEMATA; else if(IsEqualGUID(DBSCHEMA_SQL_LANGUAGES,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_SQL_LANGUAGES; else if(IsEqualGUID(DBSCHEMA_STATISTICS,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_STATISTICS; else if(IsEqualGUID(DBSCHEMA_TABLES,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_TABLES; else if(IsEqualGUID(DBSCHEMA_TABLES_INFO,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_TABLES_INFO; else if(IsEqualGUID(DBSCHEMA_TABLE_CONSTRAINTS,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_TABLE_CONSTRAINTS; else if(IsEqualGUID(DBSCHEMA_TABLE_PRIVILEGES,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_TABLE_PRIVILEGES; else if(IsEqualGUID(DBSCHEMA_TABLE_STATISTICS,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_TABLE_STATISTICS; else if(IsEqualGUID(DBSCHEMA_TRANSLATIONS,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_TRANSLATIONS; else if(IsEqualGUID(DBSCHEMA_TRUSTEE,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_TRUSTEE; else if(IsEqualGUID(DBSCHEMA_USAGE_PRIVILEGES,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_USAGE_PRIVILEGES; else if(IsEqualGUID(DBSCHEMA_VIEW_COLUMN_USAGE,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_VIEW_COLUMN_USAGE; else if(IsEqualGUID(DBSCHEMA_VIEW_TABLE_USAGE,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_VIEW_TABLE_USAGE; else if(IsEqualGUID(DBSCHEMA_VIEWS,guid)) pwszSchemaName = (LPWSTR)wszDBSCHEMA_VIEWS; else pwszSchemaName = (LPWSTR)wszDBSCHEMA_GUID; PRVTRACE(L"%s",pwszSchemaName); if(fAddNewLine) PRVTRACE(L"\n"); if(fToScreen) { odtLog << pwszSchemaName; if(fAddNewLine) odtLog <0); TESTC(ulStrLen > 0); TESTC(strlen(szBuf) < sizeof(szBuf)-1); // May have been truncation if this fails // Convert to Unicode pwszBuf = ConvertToWCHAR(szBuf); CLEANUP: return pwszBuf; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Base Class Section // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class CSchemaTest : public CSessionObject { public: // Static variables. (Set once but wont change values). // @todo change them to real static variable. ULONG m_cRowsetPropSet; DBPROPSET * m_rgRowsetPropSet; BOOL m_fAtLeast1UnsupportedRestrictionIsSet; BOOL m_fPrintedSchemasAndRestrictions; BOOL m_PrintSchemaName; // Capture restrictions for this provider BOOL m_fDontCaptureRestrictions; // @cmember Pass all restrictions as init'd variants BOOL m_fRestrictionsAsInitVariants; // @cmember Do I want to pass in restriction when I know restriction is not supported? BOOL m_fPassUnsupportedRestrictions; // @cmember Global hresult HRESULT m_HR; // @cmember Variation level return BOOL m_fResult; // @cmember Was a bookmark requested for rowset BOOL m_fBOOKMARK_REQUESTED; // @cmember Was a bookmark found on rowset BOOL m_fBOOKMARK_FOUND; // @cmember Use first restriction BOOL m_fRes1; // @cmember Use second restriciton BOOL m_fRes2; // @cmember Use third restriciton BOOL m_fRes3; // @cmember Use fourth restriciton BOOL m_fRes4; // @cmember Use FIFTH restriction BOOL m_fRes5; // @cmember use sixth restriciton BOOL m_fRes6; // @cmember use seventh restriciton BOOL m_fRes7; // @cmember If catalog is found BOOL m_fMyTableCatalogFound; // @cmember If Schema is found BOOL m_fMyTableSchemaFound; // @cmember If first table name is found BOOL m_MyTableName1Found; // @cmember If second table name is found BOOL m_MyTableName2Found; // @cmember If column is found BOOL m_MyColumnNameFound; // @cmember If data type is found BOOL m_MyTableTypeFound; // @cmember Count of restrictions used ULONG m_cErrors; // @cmember Expect count of column in schema ULONG m_cColumns; // @cmember Expected count of restrictions in schema ULONG m_cRestrictions; // @cmember Count of restrictions being tested ULONG m_cRestrictionsCurrent; // @cmember Count of schemas provider supports ULONG m_cSchemasSupported; // @cmember Enum giving provider's OLEDB version ULONG m_ulOLEDBVer; // @cmember Count of Bindings DBCOUNTITEM m_cDBBINDING; // @cmember Count of Property Sets ULONG m_cDBPROPSET; // @cmember Count of DBPROPINFOSETs ULONG m_cDBPROPINFOSET; // @cmember Count of rowset DBPROPINFOSETs, including provider specific ULONG m_cRowsetDBPROPINFOSET; // @cmember Count of columns in rowset DBORDINAL m_cDBCOLUMNINFO; // @cmember Current schema being tested GUID m_guid; // @cmember Interface pointer I want returned IID m_iid; // Bitmask of which restrictions are requested RESTRICTIONS m_restrict; // Array of FIRST property DBPROP m_rgDBPROP[MAXPROP]; // @cmember Array of Property Sets DBPROPSET m_rgDBPROPSET[MAXPROP]; // @cmember CCol object CCol m_col; // @cmember First restriction WCHAR * m_wszR1; // @cmember Second restriction WCHAR * m_wszR2; // @cmember Third restriction WCHAR * m_wszR3; // @cmember Fourth restriction WCHAR * m_wszR4; // @cmember Fifth restriction WCHAR * m_wszR5; // @cmember Sixth restriction WCHAR * m_wszR6; // @cmember Seventh restriciton WCHAR * m_wszR7; // @cmember Non-string restriction (Currently only for Provider Type) ULONG m_ulR; // @cmember Bool restriction (Currently only for Best Match in Provider Types) TYPE_BOOL m_fR; // @cmember Rowset pointer should be NULL BOOL m_fRowsetPointerNULL; // @cmember Count of Restrictions should be 0 BOOL m_fCountRestrictionsNULL; // @cmember Range of Restrictions shoulbd be NULL BOOL m_fRangeRestrictionsNULL; // @cmember Count of Property Sets should be 0 BOOL m_fCountPropSetNULL; // @cmember Range of Property Sets should be NULL BOOL m_fRangePropSetNULL; // Array of restrictions, according to spec, no schema has more than 7 VARIANT m_rgvarRestrict[MAXRESTRICTION]; // Do I want to copy the restriction strings into my class members BOOL m_fCaptureRestrictions; // Print Supported Schemas prior to Testing BOOL m_fPrintSupportedSchemas; // DBTYPE DBTYPE m_DataTypeRestriction; // Object Type SHORT m_ProcedureTypeRestriction; // BEST MATCH TYPE_BOOL m_BestMatchRestriction; // Structure of guid and restrictions on guid ULONG m_currentBitMask; // if backend is sql server BOOL m_bSqlServer; /////////////// // Dynamic ////////////// // @cmember Supported Property sets DBPROP * m_rgSupportedProperties; // @cmember Count of supported property sets ULONG m_cSupportedProperties; // @cmember Range of Restrictions that are supported ULONG * m_rgRestrictionSupport; // @cmember Expected column names WCHAR ** m_rgColumnNames; // @cmember Expected column types DBTYPE * m_rgColumnTypes; // @cmember Array of schemas provider supports GUID * m_rgSchemas; // @cmember Interface pointer IDBSchemaRowset * m_pIDBSchemaRowset; // @cmember Rowset pointer IRowset * m_pIRowset; // @cmember Count of DBPROPINFOSETs DBPROPINFOSET * m_rgDBPROPINFOSET; // @cmember Rowset property sets, including provider specific DBPROPINFOSET * m_rgRowsetDBPROPINFOSET; // @cmember Description Buffer WCHAR * m_pDescBuffer; LPWSTR m_pRowsetDescBuffer; // @cmember Array of column information in rowset DBCOLUMNINFO * m_rgDBCOLUMNINFO; // @cmember Buffer of strings for column information WCHAR * m_pStringsBuffer; // @cmember Array of Bindings DBBINDING * m_rgDBBINDING; // @cmember Aggregation Pointer IUnknown * m_punkOuter; // @cmember IAccessor pointer IAccessor * m_pIAccessor; // @cmember IRowsetInfo pointer IRowsetInfo * m_pIRowsetInfo; // @cmember IColumnsInfo pointer IColumnsInfo * m_pIColumnsInfo; // @cmember IRowsetChange IRowsetChange * m_pIRowsetChange; // @cmember IUnknown IUnknown * m_pIUnknown; // @cmember m_pwszDropProc WCHAR * m_pwszDropProc; // @cmember m_eRowCount - how to interpret row count below ROW_COUNT m_eRowCount; // @cmember m_lRowCount - count of rows to expect from schema rowset DBORDINAL m_ulRowCount; // @cmember Restrictions // If I can't find pubs for sql server or nwind for access, // I'll take first catalog I find. WCHAR * m_pwszCatalogRestriction; WCHAR * m_pwszSchemaRestriction; WCHAR * m_pwszTableRestriction; WCHAR * m_pwszColumnRestriction; WCHAR * m_pwszAssertion_ConstraintRestriction; WCHAR * m_pwszCheck_ConstraintRestriction; WCHAR * m_pwszKey_Column_Usage_ConstraintRestriction; WCHAR * m_pwszReferential_ConstraintRestriction; WCHAR * m_pwszTable_ConstraintRestriction; WCHAR * m_pwszCharacter_SetRestriction; WCHAR * m_pwszCollationRestriction; WCHAR * m_pwszDomainRestriction; WCHAR * m_pwszGrantorRestriction; WCHAR * m_pwszGranteeRestriction; WCHAR * m_pwszPK_TableRestriction; WCHAR * m_pwszFK_TableRestriction; WCHAR * m_pwszIndexRestriction; WCHAR * m_pwszProcedureRestriction; WCHAR * m_pwszProcedureColumnsRestriction; WCHAR * m_pwszParameterRestriction; TYPE_UI2 m_uiProcedureType; WCHAR * m_pwszSchema_OwnerRestriction; WCHAR * m_pwszTable_TypeRestriction; WCHAR * m_pwszConstraint_TypeRestriction; WCHAR * m_pwszTranslationReplace; WCHAR * m_pwszObjectRestriction; WCHAR * m_pwszObject_TypeRestriction; WCHAR * m_pwszViewRestriction; WCHAR * m_pwszStatisticsCatalogRestriction; WCHAR * m_pwszStatisticsSchemaRestriction; WCHAR * m_pwszStatisticsNameRestriction; TYPE_UI2 m_uiStatisticsTypeRestriction; LPWSTR m_pwszUpdateStatsFormat; LPWSTR m_pwszSortSetting; //-------------------- // Functions //-------------------- // @cmember Constructor CSchemaTest(const LPWSTR wszTestCaseName = NULL): CSessionObject(wszTestCaseName) { INIT m_bSqlServer = FALSE; m_rgDBPROPINFOSET=NULL; m_pDescBuffer=NULL; m_pRowsetDescBuffer = NULL; m_cDBPROPINFOSET=0; m_rgSupportedProperties=NULL; m_cSupportedProperties=0; m_fAtLeast1UnsupportedRestrictionIsSet=FALSE; m_fPrintedSchemasAndRestrictions=FALSE; m_currentBitMask = 0; m_fDontCaptureRestrictions = FALSE; m_rgColumnNames=NULL; m_rgColumnTypes=NULL; m_rgSchemas=NULL; m_pDescBuffer=NULL; m_pRowsetDescBuffer = NULL; m_rgDBCOLUMNINFO=NULL; m_pStringsBuffer=NULL; m_rgDBBINDING=NULL; m_punkOuter=NULL; m_pIAccessor=NULL; m_pIRowset=NULL; m_pIRowsetInfo=NULL; m_pIColumnsInfo=NULL; m_pIRowsetChange=NULL; m_pIOpenRowset = NULL; m_pIDBSchemaRowset=NULL; m_pIUnknown = NULL; m_PrintSchemaName=TRUE; m_pwszCatalogRestriction=NULL; m_pwszSchemaRestriction=NULL; m_pwszTableRestriction=NULL; m_pwszColumnRestriction=NULL; m_pwszAssertion_ConstraintRestriction=NULL; m_pwszCheck_ConstraintRestriction=NULL; m_pwszKey_Column_Usage_ConstraintRestriction=NULL; m_pwszReferential_ConstraintRestriction=NULL; m_pwszTable_ConstraintRestriction=NULL; m_pwszCharacter_SetRestriction=NULL; m_pwszCollationRestriction=NULL; m_pwszDomainRestriction=NULL; m_pwszGrantorRestriction=NULL; m_pwszGranteeRestriction=NULL; m_pwszPK_TableRestriction=NULL; m_pwszFK_TableRestriction=NULL; m_pwszIndexRestriction=NULL; m_pwszProcedureRestriction=NULL; m_pwszParameterRestriction=NULL; m_pwszProcedureColumnsRestriction=NULL; m_pwszStatisticsCatalogRestriction = NULL; m_pwszStatisticsSchemaRestriction = NULL; m_pwszStatisticsNameRestriction = NULL; m_pwszUpdateStatsFormat = NULL; m_pwszSortSetting = NULL; m_uiProcedureType=0; m_uiStatisticsTypeRestriction=0; m_pwszSchema_OwnerRestriction=NULL; m_pwszConstraint_TypeRestriction=NULL; m_pwszTable_TypeRestriction=NULL; m_pwszTranslationReplace=NULL; m_pwszObjectRestriction=NULL; m_pwszObject_TypeRestriction=NULL; m_pwszViewRestriction=NULL; m_rgRestrictionSupport=NULL; m_rgRestrictionSupport=NULL; m_pwszProcedureColumnsRestriction=NULL; m_fPrintSupportedSchemas=TRUE; m_fBOOKMARK_REQUESTED=FALSE; m_fBOOKMARK_FOUND=FALSE; m_fRes1=TRUE; m_fRes2=TRUE; m_fRes3=TRUE; m_fRes4=TRUE; m_fRes5=TRUE; m_fRes6=TRUE; m_fRes7=TRUE; m_fMyTableCatalogFound=FALSE; m_fMyTableSchemaFound=FALSE; m_MyTableName1Found=FALSE; m_MyTableName2Found=FALSE; m_MyColumnNameFound=FALSE; m_MyTableTypeFound=FALSE; m_cErrors=0; m_cColumns=0; m_cRestrictions=0; m_cRestrictionsCurrent=0; m_cSchemasSupported=0; m_cDBBINDING=0; m_cDBPROPSET=0; m_cDBCOLUMNINFO=0; m_iid=IID_NULL; m_guid=GUID_NULL; m_restrict=0; m_HR=E_FAIL; m_fResult=FALSE; m_fCaptureRestrictions=FALSE; m_DataTypeRestriction=0; m_ProcedureTypeRestriction=0; m_fRowsetPointerNULL=FALSE; m_fCountRestrictionsNULL=FALSE; m_fRangeRestrictionsNULL=FALSE; m_fCountPropSetNULL=FALSE; m_fRangePropSetNULL=FALSE; m_fPassUnsupportedRestrictions=FALSE; m_fRestrictionsAsInitVariants=FALSE; m_wszR1=NULL; m_wszR2=NULL; m_wszR3=NULL; m_wszR4=NULL; m_wszR5=NULL; m_wszR6=NULL; m_wszR7=NULL; m_ulR=0; m_fR = FALSE; m_cRowsetDBPROPINFOSET = 0; m_rgRowsetDBPROPINFOSET = NULL; m_cRowsetPropSet=0; m_rgRowsetPropSet=NULL; m_eRowCount = MIN_VALUE; m_ulRowCount = 1; m_pwszTableName = NULL; m_pwszStatName = NULL; m_iOrdinalExpected = 0; m_fDetailCheck = FALSE; m_prgColInfo = NULL; m_cColInfo = 0; m_pwszStringsBuffer = NULL; m_fPrimaryKey=FALSE; m_fForeignKey=FALSE; for(ULONG index=0;indexGetDebugMode()); if(COLEDB::Init()) { WCHAR * pwszOLEDBVER = NULL; m_pwszDropProc=NULL; // Set DSO pointer if(m_pThisTestModule->m_pIUnknown) { m_pIDBInitialize = (IDBInitialize *)m_pThisTestModule->m_pIUnknown; m_pIDBInitialize->AddRef(); } // Set CSession pointer SetDBSession((IDBCreateCommand *)m_pThisTestModule->m_pIUnknown2); // Set Table pointer SetTable((CTable *)m_pThisTestModule->m_pVoid, DELETETABLE_NO); // Get IDBSchemaRowset pointer if(m_pIOpenRowset) { if(FAILED(m_pIOpenRowset->QueryInterface( IID_IDBSchemaRowset, (void **) &m_pIDBSchemaRowset))) return FALSE; } else //(m_pIDBCreateCommand) { if(FAILED(m_pIDBCreateCommand->QueryInterface( IID_IDBSchemaRowset, (void **) &m_pIDBSchemaRowset))) return FALSE; } // First check for support for alter table syntax. ULONG_PTR ulSQLSupport = 0; GetProperty(DBPROP_SQLSUPPORT, DBPROPSET_DATASOURCEINFO, m_pIDBInitialize, &ulSQLSupport); if( ulSQLSupport & DBPROPVAL_SQL_ANSI89_IEF ) InitKeysOnTable(); // Get Supported Schemas if(FAILED(m_pIDBSchemaRowset->GetSchemas( &m_cSchemasSupported, &m_rgSchemas, &m_rgRestrictionSupport))) { m_pIDBSchemaRowset->Release(); m_pIDBSchemaRowset = NULL; return FALSE; } if(m_cSchemasSupported==0) { odtLog << L"No schemas supported\n"; return FALSE; } if(FAILED(GetAllPropertySets())) return FALSE; if(FAILED(GetRowsetPropertySet())) return FALSE; // Get DBPROP_PROVIDEROLEDBVER for use in setting correct column count for each schema if (GetProperty(DBPROP_PROVIDEROLEDBVER, DBPROPSET_DATASOURCEINFO, m_pIDBInitialize, &pwszOLEDBVER)) { if (!wcscmp(pwszOLEDBVER, L"02.00")) m_ulOLEDBVer = VER_20; else if (!wcscmp(pwszOLEDBVER, L"02.10")) m_ulOLEDBVer = VER_21; else if (!wcscmp(pwszOLEDBVER, L"02.50")) m_ulOLEDBVer = VER_25; else if (!wcscmp(pwszOLEDBVER, L"02.60")) m_ulOLEDBVer = VER_26; else if (!wcscmp(pwszOLEDBVER, L"02.70")) m_ulOLEDBVer = VER_27; else ASSERT(!L"Unknown schema version."); SAFE_FREE(pwszOLEDBVER); } // Call the GetProperty for the DBMS Name if(GetProperty(DBPROP_DBMSNAME, DBPROPSET_DATASOURCEINFO, m_pIDBInitialize, &pwszDBMSName)) { if (!wcscmp(pwszDBMSName, L"Microsoft SQL Server")) m_bSqlServer = TRUE; // Get the DBMS specific command to create/update statistics and set sorts for (iDBMS = 0; iDBMS < NUMELEM(g_DBMSList); iDBMS++) { if (!wcscmp(pwszDBMSName, g_DBMSList[iDBMS].pwszDBMSName)) { m_pwszUpdateStatsFormat = g_DBMSList[iDBMS].pwszUpdateStatsFormat; m_pwszSortSetting = g_DBMSList[iDBMS].pwszSortSetting; break; } } } // Set the sort sequence desired if (m_pwszSortSetting) { CHECK(m_pTable->BuildCommand(m_pwszSortSetting, IID_IRowset, EXECUTE_IFNOERROR, 0, NULL, NULL, NULL, NULL, NULL), S_OK); } // if(!m_fDontCaptureRestrictions) // CaptureRestrictions(); PROVIDER_FREE(pwszDBMSName); return TRUE; } return FALSE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Terminate // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::Terminate() { // Release everything from the init SAFE_RELEASE(m_pIDBSchemaRowset); // Free the memory PROVIDER_FREE(m_rgSchemas); PROVIDER_FREE(m_rgRestrictionSupport); PROVIDER_FREE(m_rgSupportedProperties); // Free the Properties FreeProperties(&m_cDBPROPINFOSET, &m_rgDBPROPINFOSET, &m_pDescBuffer); FreeProperties(&m_cRowsetDBPROPINFOSET, &m_rgRowsetDBPROPINFOSET, &m_pRowsetDescBuffer); FreeProperties(&m_cRowsetPropSet, &m_rgRowsetPropSet); FreeRestrictions(); ULONG_PTR ulSQLSupport = 0; if (m_pIDBInitialize) GetProperty(DBPROP_SQLSUPPORT, DBPROPSET_DATASOURCEINFO, m_pIDBInitialize, &ulSQLSupport); if( ulSQLSupport & DBPROPVAL_SQL_ANSI89_IEF ) TerminateKeysOnTable(); ReleaseDBSession(); SAFE_RELEASE(m_pIDBInitialize); if(!COLEDB::Terminate()) return FALSE; return(CTestCases::Terminate()); } // Is the property set GUID one of the Rowset property GUIDs BOOL CSchemaTest::IsRowsetPropertySet(GUID guidPropset) { // Loop through all the Rowset property info from the DBPROPSET_ROWSETALL // Includes provider specific for (ULONG iPropertyInfoSet=0; iPropertyInfoSet < m_cRowsetDBPROPINFOSET; iPropertyInfoSet++ ) if (m_rgRowsetDBPROPINFOSET[iPropertyInfoSet].guidPropertySet == guidPropset) return TRUE; return FALSE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Is rowset property supported by temp table // // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::IsRowsetPropertySupported(DBPROPID propid) { ULONG i,j; ULONG iRowsetSet=0; for(i=0;iGetRowset( NULL, DBSCHEMA_PROVIDER_TYPES, 0, NULL, IID_IRowsetInfo, 0, NULL, (IUnknown **) &pIRowsetInfo))) goto CLEANUP; if(FAILED(hr=pIRowsetInfo->GetProperties( 0, NULL, &m_cRowsetPropSet, &m_rgRowsetPropSet))) goto CLEANUP; CLEANUP: if(pIRowsetInfo) pIRowsetInfo->Release(); return hr; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Is Property a VT_BOOL // // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::PropIsBool(DBPROPID prop) { if (( prop == DBPROP_ABORTPRESERVE) || (prop == DBPROP_APPENDONLY) || (prop == DBPROP_BLOCKINGSTORAGEOBJECTS) || (prop == DBPROP_BOOKMARKS) || (prop == DBPROP_BOOKMARKSKIPPED) || (prop == DBPROP_CACHEDEFERRED) || (prop == DBPROP_CANFETCHBACKWARDS) || (prop == DBPROP_CANHOLDROWS) || (prop == DBPROP_CANSCROLLBACKWARDS) || (prop == DBPROP_CHANGEINSERTEDROWS) || (prop == DBPROP_COLUMNRESTRICT) || (prop == DBPROP_COMMITPRESERVE) || (prop == DBPROP_DEFERRED) || (prop == DBPROP_DELAYSTORAGEOBJECTS) || (prop == DBPROP_IMMOBILEROWS) || (prop == DBPROP_LITERALBOOKMARKS) || (prop == DBPROP_LITERALIDENTITY) || (prop == DBPROP_MAYWRITECOLUMN) || (prop == DBPROP_ORDEREDBOOKMARKS) || (prop == DBPROP_OTHERINSERT) || (prop == DBPROP_OTHERUPDATEDELETE) || (prop == DBPROP_OWNINSERT) || (prop == DBPROP_OWNUPDATEDELETE) || (prop == DBPROP_QUICKRESTART) || (prop == DBPROP_REENTRANTEVENTS) || (prop == DBPROP_REMOVEDELETED) || (prop == DBPROP_REPORTMULTIPLECHANGES) || (prop == DBPROP_RETURNPENDINGINSERTS) || (prop == DBPROP_ROWRESTRICT) || (prop == DBPROP_SERVERCURSOR) || (prop == DBPROP_STRONGIDENTITY) || (prop == DBPROP_TRANSACTEDOBJECT) || (prop == DBPROP_OTHERINSERT) || (prop == DBPROP_IAccessor) || (prop == DBPROP_IColumnsInfo) || (prop == DBPROP_IColumnsRowset) || (prop == DBPROP_IConnectionPointContainer) || (prop == DBPROP_IRowset) || (prop == DBPROP_IRowsetChange) || (prop == DBPROP_IRowsetIdentity) || (prop == DBPROP_IRowsetInfo) || (prop == DBPROP_IRowsetLocate) || (prop == DBPROP_IRowsetResynch) || (prop == DBPROP_IRowsetScroll) || (prop == DBPROP_IRowsetUpdate) || (prop == DBPROP_ISupportErrorInfo) || (prop == DBPROP_ILockBytes) || (prop == DBPROP_ISequentialStream) || (prop == DBPROP_IStorage) || (prop == DBPROP_IStream)) return TRUE; else return FALSE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // // // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - HRESULT CSchemaTest::GetAllPropertySets() { HRESULT hr=E_FAIL; ULONG index1=0; ULONG index2=0; IDBProperties * pIDBProperties=NULL; // make sure I have a DSO object if(!m_pIDBInitialize) goto CLEANUP; // get necessary pointer if(!CHECK(hr=m_pIDBInitialize->QueryInterface(IID_IDBProperties,(void**)&pIDBProperties),S_OK)) goto CLEANUP; // get property info if(FAILED(hr=pIDBProperties->GetPropertyInfo(0,NULL,&m_cDBPROPINFOSET,&m_rgDBPROPINFOSET,&m_pDescBuffer))) goto CLEANUP; // Get all the rowset properties DBPROPIDSET rgRowsetIDSET[1]; rgRowsetIDSET[0].rgPropertyIDs=NULL; rgRowsetIDSET[0].cPropertyIDs=0; rgRowsetIDSET[0].guidPropertySet=DBPROPSET_ROWSETALL; if(FAILED(hr=pIDBProperties->GetPropertyInfo(1,rgRowsetIDSET,&m_cRowsetDBPROPINFOSET,&m_rgRowsetDBPROPINFOSET,&m_pRowsetDescBuffer))) goto CLEANUP; for(index1=0;index1Release(); return hr; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // ShouldTestSchemaRestriction // // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - HRESULT CSchemaTest::ShouldTestSchemaRestriction(GUID schema,ULONG restrictions) { // Figure out the return code for(ULONG index=0; index < m_cSchemasSupported; index++) { if(IsEqualGUID(schema,m_rgSchemas[index])) { if( (ALLRES & restrictions) || (m_rgRestrictionSupport[index] & restrictions) ) return S_OK; if(restrictions <= NumberofRestrictions(schema)) return E_INVALIDARG; break; } } return E_INVALIDARG; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // NumberofRestrictions // // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ULONG CSchemaTest::NumberofRestrictions(GUID schema) { // all schemas with 0 restrictions // don't need to check schemas anyway if(IsEqualGUID(schema,DBSCHEMA_SQL_LANGUAGES)) return 0; // all schemas with 1 retriction if(IsEqualGUID(schema,DBSCHEMA_CATALOGS)) return 1; // all schemas with 2 restrictions if(IsEqualGUID(schema,DBSCHEMA_PROVIDER_TYPES)) return 3; // all schemas with 3 restrictions if(IsEqualGUID(schema,DBSCHEMA_ASSERTIONS) || IsEqualGUID(schema,DBSCHEMA_CHARACTER_SETS) || IsEqualGUID(schema,DBSCHEMA_CHECK_CONSTRAINTS) || IsEqualGUID(schema,DBSCHEMA_COLLATIONS) || IsEqualGUID(schema,DBSCHEMA_CONSTRAINT_TABLE_USAGE) || IsEqualGUID(schema,DBSCHEMA_PRIMARY_KEYS) || IsEqualGUID(schema,DBSCHEMA_REFERENTIAL_CONSTRAINTS) || IsEqualGUID(schema,DBSCHEMA_SCHEMATA) || IsEqualGUID(schema,DBSCHEMA_STATISTICS) || IsEqualGUID(schema,DBSCHEMA_TRANSLATIONS) || IsEqualGUID(schema,DBSCHEMA_VIEW_COLUMN_USAGE) || IsEqualGUID(schema,DBSCHEMA_VIEW_TABLE_USAGE) || IsEqualGUID(schema,DBSCHEMA_VIEWS)) return 7; // all schemas with 4 restrictions if(IsEqualGUID(schema,DBSCHEMA_COLUMN_DOMAIN_USAGE) || IsEqualGUID(schema,DBSCHEMA_COLUMNS) || IsEqualGUID(schema,DBSCHEMA_CONSTRAINT_COLUMN_USAGE) || IsEqualGUID(schema,DBSCHEMA_PROCEDURE_COLUMNS) || IsEqualGUID(schema,DBSCHEMA_PROCEDURE_PARAMETERS) || IsEqualGUID(schema,DBSCHEMA_PROCEDURES) || IsEqualGUID(schema,DBSCHEMA_TABLES) || IsEqualGUID(schema,DBSCHEMA_TABLES_INFO)) return 15; // all schemas with 5 restrictions if(IsEqualGUID(schema,DBSCHEMA_INDEXES) || IsEqualGUID(schema,DBSCHEMA_TABLE_PRIVILEGES)) return 31; // all schemas with 6 restrictions if(IsEqualGUID(schema,DBSCHEMA_COLUMN_PRIVILEGES) || IsEqualGUID(schema,DBSCHEMA_FOREIGN_KEYS) || IsEqualGUID(schema,DBSCHEMA_USAGE_PRIVILEGES)) return 63; // all schemas with 7 restrictions if(IsEqualGUID(schema,DBSCHEMA_KEY_COLUMN_USAGE) || IsEqualGUID(schema,DBSCHEMA_TABLE_CONSTRAINTS)|| IsEqualGUID(schema,DBSCHEMA_TABLE_STATISTICS)) return 127; return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Set Bit // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CSchemaTest::SetRestriction(ULONG bit) { m_restrict |= bit; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Clear Bit // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CSchemaTest::ClearRestriction(ULONG bit) { m_restrict &= ~(bit); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Test Schema Restrictions // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::TestSchemaRestrictions(GUID schema, ULONG bit, ROW_COUNT eRowCount, ULONG cExpRows) { HRESULT hr = E_FAIL; HRESULT ExpHR = S_OK; // Initialize the needed pointers INIT; // This is not initialized on purpose ExpHR=ShouldTestSchemaRestriction(schema,bit); if(FAILED(ExpHR)) { odtLog <=1), TRUE)) || (!COMPARE(pColumn->sStatus, DBSTATUS_S_OK)) || ((m_restrict & bit) && ((!COMPARE(pColumn->ulLength, wcslen(wszRes)*2)) || (!COMPARE(0, RelCompareString(wszRes, (TYPE_WSTR)pColumn->bValue)))))) ) *fRes = fResults = FALSE; } else { COMPARE(pColumn->sStatus, DBSTATUS_S_ISNULL); // COMPARE(pColumn->ulLength, 0); // Spec does not require this. Length should be ignored for NULL. } return fResults; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Test the Restriction for IDBSchemaRowset // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CSchemaTest::SetRestriction(RESTRICTIONSENUM bit, ULONG ulRestriction, WCHAR ** pwszR, WCHAR * wszRestriction) { // Check if the restriction is supported if((m_currentBitMask & bit) || m_fPassUnsupportedRestrictions) { if((m_restrict & bit) || (m_restrict & ALLRES)) { // if NULL set to a bogus restriction m_rgvarRestrict[ulRestriction-1].bstrVal = SysAllocString(wszRestriction ? wszRestriction : L"BogusRestriction"); *pwszR = wcsDuplicate(wszRestriction ? wszRestriction : L"BogusRestriction"); m_rgvarRestrict[ulRestriction-1].vt = VT_BSTR; m_cRestrictionsCurrent ++; SetRestriction(bit); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Init_Stuff // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CSchemaTest::Init_Stuff(void) { ULONG index; m_fBOOKMARK_REQUESTED=FALSE; m_fBOOKMARK_FOUND=FALSE; m_fRes1=TRUE; m_fRes2=TRUE; m_fRes3=TRUE; m_fRes4=TRUE; m_fRes5=TRUE; m_fRes6=TRUE; m_fRes7=TRUE; m_fMyTableCatalogFound=FALSE; m_fMyTableSchemaFound=FALSE; m_MyTableName1Found=FALSE; m_MyTableName2Found=FALSE; m_MyColumnNameFound=FALSE; m_MyTableTypeFound=FALSE; m_cErrors=0; m_cColumns=0; m_cRestrictions=0; m_cRestrictionsCurrent=0; m_cDBBINDING=0; m_cDBPROPSET=0; m_cDBCOLUMNINFO=0; m_iid=IID_NULL; m_guid=GUID_NULL; m_restrict=0; m_HR=E_FAIL; m_fResult=FALSE; m_fAtLeast1UnsupportedRestrictionIsSet=FALSE; m_fRowsetPointerNULL=FALSE; m_fCountRestrictionsNULL=FALSE; m_fRangeRestrictionsNULL=FALSE; m_fCountPropSetNULL=FALSE; m_fRangePropSetNULL=FALSE; m_fPassUnsupportedRestrictions=FALSE; m_fRestrictionsAsInitVariants=FALSE; m_wszR1=NULL; m_wszR2=NULL; m_wszR3=NULL; m_wszR4=NULL; m_wszR5=NULL; m_wszR6=NULL; m_wszR7=NULL; m_ulR=0; for(index=0;indexGetRowset( m_punkOuter, m_guid, (m_fCountRestrictionsNULL ? 0 : m_cRestrictions), (m_fRangeRestrictionsNULL ? NULL : m_rgvarRestrict), m_iid, (m_fCountPropSetNULL ? 0 : m_cDBPROPSET), (m_fRangePropSetNULL ? 0 : m_rgDBPROPSET), (m_fRowsetPointerNULL ? NULL : ppIUnknown)); if (SUCCEEDED(m_HR)) CheckResults(*ppIUnknown, m_iid); if (fFreeRowset && ppIUnknown) SAFE_RELEASE(*ppIUnknown); return m_HR; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // This routine should be called when the information for the next schema (guid) is needed // I either want the next supported schema or a specific schema. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::GetSchemaInfo ( REQUESTED_SCHEMA schemaType, // [IN] if I want the schema supported, or not, or I have a specific schema in mind ULONG ulIndexOfSchemaRequesting, // [IN] Index of supported Schema GUID schema // [IN] specific schema ) { BOOL fResult = FALSE; m_cRestrictionsCurrent = 0; // Set default row count information to expect 1 row but only // warn if we get less SetRowCount(MIN_VALUE, 1); // Initialize Variants VariantInit(&m_rgvarRestrict[0]); VariantInit(&m_rgvarRestrict[1]); VariantInit(&m_rgvarRestrict[2]); VariantInit(&m_rgvarRestrict[3]); VariantInit(&m_rgvarRestrict[4]); VariantInit(&m_rgvarRestrict[5]); VariantInit(&m_rgvarRestrict[6]); // grab schema from list of supported schemas if(schemaType==SUPPORTED) memcpy(&m_guid,&(m_rgSchemas[ulIndexOfSchemaRequesting]),sizeof(GUID)); else if(schemaType==SPECIFIC) memcpy(&m_guid,&schema,sizeof(GUID)); else return FALSE; for(ULONG index=0;indexGetIndexName()) { PROVIDER_FREE(m_pwszIndexRestriction); m_pwszIndexRestriction = wcsDuplicate(m_pTable->GetIndexName()); } // Get Table Name if(m_pTable->GetTableName()) { VARIANT Variant; PROVIDER_FREE(m_pwszTableRestriction); m_pwszTableRestriction = wcsDuplicate(m_pTable->GetTableName()); m_pwszTable_TypeRestriction = wcsDuplicate(L"TABLE"); // Adjust for identifier case VariantInit(&Variant); GetProperty(DBPROP_IDENTIFIERCASE, DBPROPSET_DATASOURCEINFO, m_pIDBInitialize, &Variant); switch(Variant.lVal) { case DBPROPVAL_IC_UPPER: _wcsupr(m_pwszTableRestriction); break; case DBPROPVAL_IC_LOWER: _wcslwr(m_pwszTableRestriction); break; } } // Get Column Name CCol col; DBORDINAL m_cOrdinals = m_pTable->CountColumnsOnTable(); for(ULONG ulIndex = 1; m_cOrdinals >= ulIndex; ulIndex++) { if(SUCCEEDED(m_pTable->GetColInfo(1,col)) && col.GetColName()) { // Copy the new values m_DataTypeRestriction = col.GetProviderType(); PROVIDER_FREE(m_pwszColumnRestriction); m_pwszColumnRestriction = wcsDuplicate(col.GetColName()); break; } } FREE; return TRUE; } //-------------------------------------------------------------------- // Release Tables // // With DBSCHEMA_TABLES, will free m_pwszTableRestriction, m_pwszColumnRestriction, and m_pwszIndexRestriction //-------------------------------------------------------------------- BOOL CSchemaTest::Release_TableInfo() { // Free the memory PROVIDER_FREE(m_pwszTableRestriction); PROVIDER_FREE(m_pwszTable_TypeRestriction); PROVIDER_FREE(m_pwszColumnRestriction); PROVIDER_FREE(m_pwszIndexRestriction); return TRUE; } //-------------------------------------------------------------------- // Find Assertion Constraint // // With DBSCHEMA_ASSERTIONS, will fill m_pwszAssertion_ConstraintRestriction //-------------------------------------------------------------------- BOOL CSchemaTest::Find_Assertion_Constraint() { // Initialize the needed pointers INIT; // no properties m_fCountPropSetNULL = TRUE; m_fRangePropSetNULL = TRUE; if(!IsSchemaSupported(DBSCHEMA_ASSERTIONS)) return FALSE; m_restrict |= FIRST; m_restrict |= SECOND; m_iid = IID_IRowset; // If this is a schema I want then get information for schema if(GetSchemaInfo(SPECIFIC,0,DBSCHEMA_ASSERTIONS)) GetRowset(); FREE; return TRUE; } //-------------------------------------------------------------------- // Find Assertion Constraint // // With DBSCHEMA_ASSERTIONS, will fill m_pwszAssertion_ConstraintRestriction //-------------------------------------------------------------------- BOOL CSchemaTest::Release_Assertion_Constraint() { // Free the memory PROVIDER_FREE(m_pwszAssertion_ConstraintRestriction); return TRUE; } //-------------------------------------------------------------------- // Find Character Set // // With DBSCHEMA_CHARACTER_SETS, will fill m_pwszCharacter_SetRestriction //-------------------------------------------------------------------- BOOL CSchemaTest::Find_Character_Set() { // Initialize the needed pointers INIT; // no properties m_fCountPropSetNULL = TRUE; m_fRangePropSetNULL = TRUE; if(!IsSchemaSupported(DBSCHEMA_CHARACTER_SETS)) return FALSE; m_restrict |= FIRST; m_restrict |= SECOND; m_iid = IID_IRowset; // if this is a schema I want then get information for schema if(GetSchemaInfo(SPECIFIC,0,DBSCHEMA_CHARACTER_SETS)) GetRowset(); FREE; return TRUE; } //-------------------------------------------------------------------- // Find Character Set // // With DBSCHEMA_CHARACTER_SETS, will fill m_pwszCharacter_SetRestriction //-------------------------------------------------------------------- BOOL CSchemaTest::Release_Character_Set() { // Free the memory PROVIDER_FREE(m_pwszCharacter_SetRestriction); return TRUE; } //-------------------------------------------------------------------- // Find Check Constraint // // With DBSCHEMA_CHECK_CONSTRAINTS, will fill m_pwszCheck_ConstraintRestriction //-------------------------------------------------------------------- BOOL CSchemaTest::Find_Check_Constraint() { INIT // no properties m_fCountPropSetNULL = TRUE; m_fRangePropSetNULL = TRUE; if(!IsSchemaSupported(DBSCHEMA_CHECK_CONSTRAINTS)) return FALSE; m_restrict |= FIRST; m_restrict |= SECOND; m_iid = IID_IRowset; // if this is a schema I want then get information for schema if(GetSchemaInfo(SPECIFIC,0,DBSCHEMA_CHECK_CONSTRAINTS)) GetRowset(); FREE return TRUE; } //-------------------------------------------------------------------- // Find Check Constraint // // With DBSCHEMA_CHECK_CONSTRAINTS, will fill m_pwszCheck_ConstraintRestriction //-------------------------------------------------------------------- BOOL CSchemaTest::Release_Check_Constraint() { // Free the memory PROVIDER_FREE(m_pwszCheck_ConstraintRestriction); return TRUE; } //-------------------------------------------------------------------- // Find Collation // // With DBSCHEMA_COLLATIONS, will fill m_pwszCollationRestriction //-------------------------------------------------------------------- BOOL CSchemaTest::Find_Collation() { INIT // no properties m_fCountPropSetNULL = TRUE; m_fRangePropSetNULL = TRUE; if(!IsSchemaSupported(DBSCHEMA_COLLATIONS)) return FALSE; m_restrict |= FIRST; m_restrict |= SECOND; m_iid = IID_IRowset; // if this is a schema I want then get information for schema if(GetSchemaInfo(SPECIFIC,0,DBSCHEMA_COLLATIONS)) GetRowset(); FREE return TRUE; } //-------------------------------------------------------------------- // Find Collation // // With DBSCHEMA_COLLATIONS, will fill m_pwszCollationRestriction //-------------------------------------------------------------------- BOOL CSchemaTest::Release_Collation() { // Free the memory PROVIDER_FREE(m_pwszCollationRestriction); return TRUE; } //-------------------------------------------------------------------- // Find Domain // // With DBSCHEMA_COLUMN_DOMAIN_USAGE, will fill m_pwszDomainRestriction //-------------------------------------------------------------------- BOOL CSchemaTest::Find_Domain() { INIT; // no properties m_fCountPropSetNULL = TRUE; m_fRangePropSetNULL = TRUE; if(!IsSchemaSupported(DBSCHEMA_COLUMN_DOMAIN_USAGE)) return FALSE; m_restrict |= FIRST; m_restrict |= SECOND; m_restrict |= FOURTH; m_iid = IID_IRowset; // if this is a schema I want then get information for schema if(GetSchemaInfo(SPECIFIC,0,DBSCHEMA_COLUMN_DOMAIN_USAGE)) GetRowset(); FREE; return TRUE; } //-------------------------------------------------------------------- // Find Domain // // With DBSCHEMA_COLUMN_DOMAIN_USAGE, will fill m_pwszDomainRestriction //-------------------------------------------------------------------- BOOL CSchemaTest::Release_Domain() { // Free the memory PROVIDER_FREE(m_pwszDomainRestriction); return TRUE; } //-------------------------------------------------------------------- // Find Grantor and Grantee // // With DBSCHEMA_COLUMN_PRIVILEGES, will fill m_pwszGrantorRestriction and m_pwszGranteeRestriction //-------------------------------------------------------------------- BOOL CSchemaTest::Find_Grantor_and_Grantee() { INIT // no properties m_fCountPropSetNULL = TRUE; m_fRangePropSetNULL = TRUE; if(!IsSchemaSupported(DBSCHEMA_COLUMN_PRIVILEGES)) return FALSE; m_restrict |= FIRST; m_restrict |= SECOND; m_restrict |= THIRD; m_restrict |= FOURTH; m_iid = IID_IRowset; // if this is a schema I want then get information for schema if(GetSchemaInfo(SPECIFIC,0,DBSCHEMA_COLUMN_PRIVILEGES)) { // Since we're restricting COLUMN_PRIVILEGES to a single column // we need to adjust expected row count to one row minimum SetRowCount(MIN_REQUIRED, 1); GetRowset(); } FREE return TRUE; } //-------------------------------------------------------------------- // Find Grantor and Grantee // // With DBSCHEMA_COLUMN_PRIVILEGES, will fill m_pwszGrantorRestriction and m_pwszGranteeRestriction //-------------------------------------------------------------------- BOOL CSchemaTest::Release_Grantor_and_Grantee() { // Free the memory PROVIDER_FREE(m_pwszGrantorRestriction); PROVIDER_FREE(m_pwszGranteeRestriction); return TRUE; } //-------------------------------------------------------------------- // Find Table Statistics Restrictions // // Uses DBSCHEMA_TABLE_STATISTICS to fill restrictions on // STATISTICS_CATALOG, STATISTICS_SCHEMA, STATISTICS_NAME, and // STATISTICS_TYPE //-------------------------------------------------------------------- BOOL CSchemaTest::Find_Table_Statistics_Restrictions() { INIT // no properties m_fCountPropSetNULL = TRUE; m_fRangePropSetNULL = TRUE; if(!IsSchemaSupported(DBSCHEMA_TABLE_STATISTICS)) return FALSE; m_restrict |= FIRST; m_restrict |= SECOND; m_restrict |= THIRD; m_iid = IID_IRowset; // if this is a schema I want then get information for schema if(GetSchemaInfo(SPECIFIC,0,DBSCHEMA_TABLE_STATISTICS)) { // Execute the provider-specific statement to update statistics // for our test table COMPARE(UpdateStatistics(), TRUE); // We need at least one row in TABLE_STATISTICS rowset SetRowCount(MIN_REQUIRED, 1); GetRowset(); } FREE return TRUE; } //-------------------------------------------------------------------- // Release Table Statistics Restrictions // //-------------------------------------------------------------------- BOOL CSchemaTest::Release_Table_Statistics_Restrictions() { // Free the memory PROVIDER_FREE(m_pwszStatisticsCatalogRestriction); PROVIDER_FREE(m_pwszStatisticsSchemaRestriction); PROVIDER_FREE(m_pwszStatisticsNameRestriction); return TRUE; } //-------------------------------------------------------------------- // Update Statistics // //-------------------------------------------------------------------- BOOL CSchemaTest::UpdateStatistics(void) { LPWSTR pwszUpdateStats = NULL; size_t ccUpdateStats = 0; BOOL fReturn = FALSE; if (m_pwszUpdateStatsFormat) { ccUpdateStats = wcslen(m_pwszUpdateStatsFormat) + wcslen(m_pTable->GetTableName() +1); SAFE_ALLOC(pwszUpdateStats, WCHAR, ccUpdateStats); swprintf(pwszUpdateStats, m_pwszUpdateStatsFormat, m_pTable->GetTableName()); TESTC_(m_pTable->BuildCommand(pwszUpdateStats, IID_IRowset, EXECUTE_IFNOERROR, 0, NULL, NULL, NULL, NULL), S_OK); } fReturn = TRUE; CLEANUP: SAFE_FREE(pwszUpdateStats); return fReturn; } //-------------------------------------------------------------------- // Find Key Column Usage Constraint // // With DBSCHEMA_KEY_COLUMN_USAGE, will fill m_pwszKey_Column_Usage_ConstraintRestriction //-------------------------------------------------------------------- BOOL CSchemaTest::Find_Key_Column_Usage_Constraint() { INIT // no properties m_fCountPropSetNULL = TRUE; m_fRangePropSetNULL = TRUE; if(!IsSchemaSupported(DBSCHEMA_KEY_COLUMN_USAGE)) return FALSE; m_restrict |= FIRST; m_restrict |= SECOND; m_restrict |= FOURTH; m_restrict |= FIFTH; m_restrict |= SIXTH; m_restrict |= SEVENTH; m_iid = IID_IRowset; // if this is a schema I want then get information for schema if(GetSchemaInfo(SPECIFIC,0,DBSCHEMA_KEY_COLUMN_USAGE)) GetRowset(); FREE return TRUE; } //-------------------------------------------------------------------- // Find Key Column Usage Constraint // // With DBSCHEMA_KEY_COLUMN_USAGE, will fill m_pwszKey_Column_Usage_ConstraintRestriction //-------------------------------------------------------------------- BOOL CSchemaTest::Release_Key_Column_Usage_Constraint() { // Free the memory PROVIDER_FREE(m_pwszKey_Column_Usage_ConstraintRestriction); return TRUE; } //-------------------------------------------------------------------- // Find Procedure // // With DBSCHEMA_PROCEDURE, will fill in // m_pwszProcedureRestriction and m_pwszProcedure_Type, //-------------------------------------------------------------------- BOOL CSchemaTest::Find_Procedure() { BOOL fSucceed = FALSE; ICommandText * pICommandText = NULL; WCHAR * pwszProcName = NULL; WCHAR * pSQL = NULL; // Initialize the needed pointers INIT; if(!m_pIDBInitialize) { odtLog << L"m_pIDBInitialize is null\n"; return TEST_FAIL; } if (!m_bSqlServer) { // odtLog << L"Not a sql server so can't test stored proc restrictions\n"; goto CLEANUP; } if(!(m_pTable->get_ICommandPTR())) goto CLEANUP; if(!CHECK(m_pTable->get_ICommandPTR()->QueryInterface(IID_ICommandText,(void**)&pICommandText),S_OK)) goto CLEANUP; pwszProcName = (WCHAR *) PROVIDER_ALLOC( (wcslen(m_pTable->GetTableName()) + wcslen(wszProcDesignator)+1) * sizeof(WCHAR)); if(!pwszProcName) { odtLog << L"out of memory\n"; goto CLEANUP; } wcscpy(pwszProcName, m_pTable->GetTableName()); wcscat(pwszProcName, wszProcDesignator); m_pwszDropProc = (WCHAR *) PROVIDER_ALLOC( (wcslen(wszDropProc) + wcslen(pwszProcName)+1) * sizeof(WCHAR)); if(!m_pwszDropProc) { odtLog << L"out of memory\n"; goto CLEANUP; } swprintf(m_pwszDropProc, wszDropProc, pwszProcName); pSQL = (WCHAR *) PROVIDER_ALLOC( (wcslen(wszCreateProc) + wcslen(pwszProcName) + wcslen(m_pTable->GetTableName()) + 1) * sizeof(WCHAR)); if(!pSQL) { COMPARE(pSQL,NULL); odtLog << L"out of memory\n"; goto CLEANUP; } swprintf(pSQL, wszCreateProc, pwszProcName, m_pTable->GetTableName()); //CREATE PROCEDURE (@IntIn int =1, @IntOut int =2 OUTPUT) AS Select * from %s RETURN (1)"; // will give me: // 1 input // 1 output // 1 return if(!CHECK(pICommandText->SetCommandText(DBGUID_DBSQL,m_pwszDropProc),S_OK)) goto CLEANUP; pICommandText->Execute(NULL,IID_NULL,NULL,NULL,NULL); if(!CHECK(pICommandText->SetCommandText(DBGUID_DBSQL,pSQL),S_OK)) goto CLEANUP; if(!CHECK(pICommandText->Execute(NULL,IID_NULL,NULL,NULL,NULL),S_OK)) goto CLEANUP; // fill these in m_pwszProcedureRestriction = (WCHAR *) PROVIDER_ALLOC( (wcslen(pwszProcName) + 1) * sizeof(WCHAR*)); if(!m_pwszProcedureRestriction) { COMPARE(m_pwszProcedureRestriction,NULL); odtLog << L"out of memory\n"; goto CLEANUP; } swprintf(m_pwszProcedureRestriction, pwszProcName); //WCHAR * m_pwszProcedureColumnsRestriction; // since we are doing select * from table we can use the // column we found previously m_pwszProcedureColumnsRestriction = (WCHAR *) PROVIDER_ALLOC( (wcslen(m_pwszColumnRestriction) + 1) * sizeof(WCHAR*)); if(!m_pwszProcedureColumnsRestriction) { COMPARE(m_pwszProcedureColumnsRestriction,NULL); odtLog << L"out of memory\n"; goto CLEANUP; } swprintf(m_pwszProcedureColumnsRestriction, m_pwszColumnRestriction); //WCHAR * m_pwszParameterRestriction; m_pwszParameterRestriction = (WCHAR *) PROVIDER_ALLOC( (wcslen(L"IntIn") + 1) * sizeof(WCHAR*)); if(!m_pwszParameterRestriction) { COMPARE(m_pwszParameterRestriction,NULL); odtLog << L"out of memory\n"; goto CLEANUP; } swprintf(m_pwszParameterRestriction, L"IntIn"); //WCHAR * m_pwszProcedureType; // default will be return value but I'll have // to add more variations in the Procedure Parameter class // to test all 4 types. m_ProcedureTypeRestriction = DBPARAMTYPE_RETURNVALUE; m_uiProcedureType = DBPARAMTYPE_RETURNVALUE; fSucceed = TRUE; CLEANUP: FREE; SAFE_RELEASE(pICommandText); // Free the memory PROVIDER_FREE(pSQL); PROVIDER_FREE(pwszProcName); return fSucceed; } //-------------------------------------------------------------------- // Find Procedure // // With DBSCHEMA_PROCEDURE, will fill in m_pwszProcedureRestriction and m_pwszProcedure_Type //-------------------------------------------------------------------- BOOL CSchemaTest::Release_Procedure() { BOOL fSucceed=FALSE; ICommandText * pICommandText=NULL; if(m_bSqlServer) { if(!(m_pTable->get_ICommandPTR())) goto CLEANUP; if(!CHECK(m_pTable->get_ICommandPTR()->QueryInterface(IID_ICommandText,(void**)&pICommandText),S_OK)) goto CLEANUP; if (m_pwszDropProc) { if(!CHECK(pICommandText->SetCommandText(DBGUID_DBSQL,m_pwszDropProc),S_OK)) goto CLEANUP; if(!CHECK(pICommandText->Execute(NULL,IID_NULL,NULL,NULL,NULL),S_OK)) goto CLEANUP; } CLEANUP: SAFE_RELEASE(pICommandText); // Free the memory PROVIDER_FREE(m_pwszDropProc); PROVIDER_FREE(m_pwszProcedureRestriction); PROVIDER_FREE(m_pwszProcedureColumnsRestriction); PROVIDER_FREE(m_pwszParameterRestriction); } return TRUE; } //-------------------------------------------------------------------- // Find Find_ProcedureColumn // // With DBSCHEMA_PROCEDURE_COLUMNS, will fill in // m_pwszProcedureColumnRestriction //-------------------------------------------------------------------- BOOL CSchemaTest::Find_ProcedureColumn() { INIT // no properties m_fCountPropSetNULL = TRUE; m_fRangePropSetNULL = TRUE; if(!IsSchemaSupported(DBSCHEMA_PROCEDURE_COLUMNS)) return FALSE; m_restrict |= FIRST; m_restrict |= SECOND; m_restrict |= THIRD; m_iid = IID_IRowset; // if this is a schema I want then get information for schema if(GetSchemaInfo(SPECIFIC,0,DBSCHEMA_PROCEDURE_COLUMNS)) GetRowset(); FREE return TRUE; } //-------------------------------------------------------------------- // Find Procedure // // With DBSCHEMA_PROCEDURE, will fill in m_pwszProcedureRestriction and m_pwszProcedure_Type //-------------------------------------------------------------------- BOOL CSchemaTest::Release_ProcedureColumn() { // Free the memory PROVIDER_FREE(m_pwszProcedureColumnsRestriction); return TRUE; } //-------------------------------------------------------------------- // Find Parameter // // With DBSCHEMA_PROCEDURE_PARAMETER, will fill in m_pwszParameterRestriction //-------------------------------------------------------------------- BOOL CSchemaTest::Find_Parameter() { INIT // no properties m_fCountPropSetNULL = TRUE; m_fRangePropSetNULL = TRUE; if(!IsSchemaSupported(DBSCHEMA_PROCEDURE_PARAMETERS)) return FALSE; m_restrict |= FIRST; m_restrict |= SECOND; m_restrict |= THIRD; m_iid = IID_IRowset; // if this is a schema I want then get information for schema if(GetSchemaInfo(SPECIFIC,0,DBSCHEMA_PROCEDURE_PARAMETERS)) GetRowset(); FREE return TRUE; } //-------------------------------------------------------------------- // Find Parameter // // With DBSCHEMA_PROCEDURE_PARAMETER, will fill in m_pwszParameterRestriction //-------------------------------------------------------------------- BOOL CSchemaTest::Release_Parameter() { // Free the memory PROVIDER_FREE(m_pwszParameterRestriction); return TRUE; } //-------------------------------------------------------------------- // Find Referential Constraint // // With DBSCHEMA_REFERENTIAL_CONSTRAINTS, will fill m_pwszReferential_ConstraintRestriction //-------------------------------------------------------------------- BOOL CSchemaTest::Find_Referential_Constraint() { INIT // no properties m_fCountPropSetNULL = TRUE; m_fRangePropSetNULL = TRUE; if(!IsSchemaSupported(DBSCHEMA_REFERENTIAL_CONSTRAINTS)) return FALSE; m_restrict |= FIRST; m_restrict |= SECOND; m_iid = IID_IRowset; // if this is a schema I want then get information for schema if(GetSchemaInfo(SPECIFIC,0,DBSCHEMA_REFERENTIAL_CONSTRAINTS)) GetRowset(); FREE return TRUE; } //-------------------------------------------------------------------- // Find Referential Constraint // // With DBSCHEMA_REFERENTIAL_CONSTRAINTS, will fill m_pwszReferential_ConstraintRestriction //-------------------------------------------------------------------- BOOL CSchemaTest::Release_Referential_Constraint() { // Free the memory PROVIDER_FREE(m_pwszReferential_ConstraintRestriction); return TRUE; } //-------------------------------------------------------------------- // Find Table Constraint // // With DBSCHEMA_TABLE_CONSTRAINTS, will fill m_pwszTable_ConstraintRestriction // and m_pwszTable_Constraint_Type //-------------------------------------------------------------------- BOOL CSchemaTest::Find_Constraint_Type() { INIT // no properties m_fCountPropSetNULL = TRUE; m_fRangePropSetNULL = TRUE; if(!IsSchemaSupported(DBSCHEMA_TABLE_CONSTRAINTS)) return FALSE; m_restrict |= FIRST; m_restrict |= SECOND; m_restrict |= FOURTH; m_restrict |= FIFTH; // m_restrict |= SIXTH; // No restriction on table name because we didn't add one m_iid = IID_IRowset; // if this is a schema I want then get information for schema if(GetSchemaInfo(SPECIFIC,0,DBSCHEMA_TABLE_CONSTRAINTS)) GetRowset(); FREE return TRUE; } //-------------------------------------------------------------------- // Find Table Constraint // // With DBSCHEMA_TABLE_CONSTRAINTS, will fill m_pwszTable_ConstraintRestriction // and m_pwszTable_Constraint_Type //-------------------------------------------------------------------- BOOL CSchemaTest::Release_Constraint_Type() { // Free the memory PROVIDER_FREE(m_pwszTable_ConstraintRestriction); PROVIDER_FREE(m_pwszConstraint_TypeRestriction); return TRUE; } //-------------------------------------------------------------------- // Find Translation // // With DBSCHEMA_TRANSLATIONS, will fill in m_pwszTranslationReplace // // While the translation should be the same as the // character set, I'm not taking any chances //-------------------------------------------------------------------- BOOL CSchemaTest::Find_Translation() { INIT // no properties m_fCountPropSetNULL = TRUE; m_fRangePropSetNULL = TRUE; if(!IsSchemaSupported(DBSCHEMA_TRANSLATIONS)) return FALSE; m_restrict |= FIRST; m_restrict |= SECOND; m_iid = IID_IRowset; // if this is a schema I want then get information for schema if(GetSchemaInfo(SPECIFIC,0,DBSCHEMA_TRANSLATIONS)) GetRowset(); FREE return TRUE; } //-------------------------------------------------------------------- // Find Translation // // With DBSCHEMA_TRANSLATIONS, will fill in m_pwszTranslationReplace // // While the translation should be the same as the // character set, I'm not taking any chances //-------------------------------------------------------------------- BOOL CSchemaTest::Release_Translation() { // Free the memory PROVIDER_FREE(m_pwszTranslationReplace); return TRUE; } //-------------------------------------------------------------------- // Find View // // With DBSCHEMA_VIEW_TABLE_USAGE, will fill in m_pwszViewRestriction //-------------------------------------------------------------------- BOOL CSchemaTest::Find_View() { INIT // no properties m_fCountPropSetNULL = TRUE; m_fRangePropSetNULL = TRUE; if(!IsSchemaSupported(DBSCHEMA_VIEW_TABLE_USAGE)) return FALSE; m_restrict |= FIRST; m_restrict |= SECOND; m_iid = IID_IRowset; // if this is a schema I want then get information for schema if(GetSchemaInfo(SPECIFIC,0,DBSCHEMA_VIEW_TABLE_USAGE)) GetRowset(); FREE return TRUE; } //-------------------------------------------------------------------- // Find View // // With DBSCHEMA_VIEW_TABLE_USAGE, will fill in m_pwszViewRestriction //-------------------------------------------------------------------- BOOL CSchemaTest::Release_View() { // Free the memory PROVIDER_FREE(m_pwszViewRestriction); return TRUE; } //-------------------------------------------------------------------- // Find BestMatch for DBSCHEMA_PROVIDER_TYPES // // With DBSCHEMA_VIEW_TABLE_USAGE, will fill in m_pwszViewRestriction //-------------------------------------------------------------------- BOOL CSchemaTest::Find_BestMatch() { INIT // no properties m_fCountPropSetNULL = TRUE; m_fRangePropSetNULL = TRUE; if(!IsSchemaSupported(DBSCHEMA_PROVIDER_TYPES)) return FALSE; m_restrict |= FIRST; m_iid = IID_IRowset; // if this is a schema I want then get information for schema if(GetSchemaInfo(SPECIFIC,0,DBSCHEMA_PROVIDER_TYPES)) GetRowset(); FREE return TRUE; } //-------------------------------------------------------------------- // Find BestMatch for DBSCHEMA_PROVIDER_TYPES // // With DBSCHEMA_FOREIGN_KEYS, // m_pwszPK_TableRestriction, m_pwszFK_TableRestriction; //-------------------------------------------------------------------- BOOL CSchemaTest::Find_PK_and_FK() { INIT // no properties m_fCountPropSetNULL = TRUE; m_fRangePropSetNULL = TRUE; if(!IsSchemaSupported(DBSCHEMA_FOREIGN_KEYS)) return FALSE; m_restrict |= FIRST; m_restrict |= SECOND; m_restrict |= FOURTH; m_restrict |= FIFTH; m_iid = IID_IRowset; if(m_fCaptureRestrictions) { // PK TABLE_NAME if ((g_pKeyTable2) && (g_pKeyTable2->GetTableName())) { m_pwszPK_TableRestriction = (WCHAR *) PROVIDER_ALLOC ((wcslen((WCHAR *) g_pKeyTable2->GetTableName())*sizeof(WCHAR)) + sizeof(WCHAR)); if(m_pwszPK_TableRestriction) wcscpy(m_pwszPK_TableRestriction,(TYPE_WSTR) g_pKeyTable2->GetTableName()); } if ((g_pKeyTable1) && (g_pKeyTable1->GetTableName())) { // FK TABLE_NAME m_pwszFK_TableRestriction = (WCHAR *) PROVIDER_ALLOC ((wcslen((WCHAR *) g_pKeyTable1->GetTableName())*sizeof(WCHAR)) + sizeof(WCHAR)); if(m_pwszFK_TableRestriction) wcscpy(m_pwszFK_TableRestriction,(TYPE_WSTR)g_pKeyTable1->GetTableName()); } } FREE return TRUE; } //-------------------------------------------------------------------- // Find BestMatch for DBSCHEMA_PROVIDER_TYPES // // With DBSCHEMA_VIEW_TABLE_USAGE, will fill in m_pwszViewRestriction //-------------------------------------------------------------------- BOOL CSchemaTest::Release_PK_and_FK() { // Free the memory PROVIDER_FREE(m_pwszPK_TableRestriction); PROVIDER_FREE(m_pwszFK_TableRestriction); return TRUE; } //-------------------------------------------------------------------- // ASSERTIONS // 1. Constraint Catalog // 2. Constraint Schema // 3. Constraint Name //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_ASSERTIONS() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **) rgwszASSERTIONS; m_rgColumnTypes = (DBTYPE *) rgtypeASSERTIONS; // Set the count of columns and restrictions m_cColumns = cASSERTIONS; m_cRestrictions = cASSERTIONS_RESTRICTIONS; // Set Constraint Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszAssertion_ConstraintRestriction); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowASSERTIONS // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_ASSERTIONS(DBCOUNTITEM iRow, BYTE * pData) { ULONG iBind=0; // Binding Count DATA * pColumn=NULL; // Data Structure CCol col; BOOL fResults=TRUE; // don't need to go farther if I have what I'm looking for if(m_fCaptureRestrictions && m_pwszAssertion_ConstraintRestriction) return FALSE; // Check the count of columns returned if(iRow == 1) COMPARE(cASSERTIONS <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"Row[%lu],Col[%s]:ASSERTIONS:", iRow,m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1:// CONSTRAINT CATALOG if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR) pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_ASSERTIONS:CONSTRAINT CATALOG restriction failed\n"; m_fRes1 = FALSE; fResults = FALSE; } } } PRVTRACE(L"= %s\n",(TYPE_WSTR)pColumn->bValue); break; case 2://CONSTRAINT SCHEMA if(m_restrict & SECOND) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR2,(TYPE_WSTR) pColumn->bValue))) { if(m_fRes2) { odtLog << L"VerifyRow_ASSERTIONS:CONSTRAINT SCHEMA restriction failed\n"; m_fRes1 = FALSE; fResults = FALSE; } } } PRVTRACE(L"= %s\n",(TYPE_WSTR)pColumn->bValue); break; case 3://CONSTRAINT NAME if(m_restrict & THIRD) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR3,(TYPE_WSTR) pColumn->bValue))) { if(m_fRes3) { odtLog << L"VerifyRow_ASSERTIONS:CONSTRAINT NAME restriction failed\n"; m_fRes3 = FALSE; fResults = FALSE; } } } if(m_fCaptureRestrictions) { m_pwszAssertion_ConstraintRestriction = (TYPE_WSTR) PROVIDER_ALLOC ((wcslen((TYPE_WSTR) pColumn->bValue)*sizeof(WCHAR)) + sizeof(WCHAR)); if(m_pwszAssertion_ConstraintRestriction) wcscpy(m_pwszAssertion_ConstraintRestriction,(TYPE_WSTR) pColumn->bValue); } PRVTRACE(L"= %s\n",(WCHAR *)pColumn->bValue); break; case 4: //IS_DEFERRABLE case 5: //INITIALLY_DEFERRED if(*(TYPE_BOOL *)pColumn->bValue==VARIANT_TRUE) PRVTRACE(L"TRUE\n"); else PRVTRACE(L"FALSE\n"); break; case 6: // DESCRIPTION PRVTRACE(L"= %s\n",(TYPE_WSTR)pColumn->bValue ); break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"ASSERTIONS: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - ASSERTIONS provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } break; } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else { PRVTRACE(L"%s=",m_rgDBCOLUMNINFO[iBind].pwszName); RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // CATALOGS // 1. Catalog Name //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_CATALOGS() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **) rgwszCATALOGS; m_rgColumnTypes = (DBTYPE *) rgtypeCATALOGS; // Set the count of columns and restrictions m_cColumns = cCATALOGS; m_cRestrictions = cCATALOGS_RESTRICTIONS; // Set Catalog Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowCATALOGS // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_CATALOGS(DBCOUNTITEM iRow, BYTE * pData) { ULONG iBind=0; // Binding Count DATA * pColumn=NULL; // Data Structure CCol col; BOOL fResults=TRUE; // Check the count of columns returned if(iRow == 1) COMPARE(cCATALOGS <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"CATALOGS:Row[%lu],Col[%d,%s]:", // iRow, // m_rgDBCOLUMNINFO[iBind].iOrdinal, // m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1:// CATALOG_NAME if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR) pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_CATALOGS:CATALOG_NAME restriction failed\n"; m_fRes1 = FALSE; fResults = FALSE; } } } PRVTRACE(L"= %s\n",(TYPE_WSTR)pColumn->bValue); break; case 2://DESCRIPTION PRVTRACE(L"= %s\n",(TYPE_WSTR)pColumn->bValue ); break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"CATALOGS: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - CATALOGS provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } break; } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } return fResults; } //-------------------------------------------------------------------- // CHARACTER_SETS // 1. Character Set Catalog // 2. Character Set Schema // 3. Character Set Name //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_CHARACTER_SETS() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszCHARACTER_SETS; m_rgColumnTypes = (DBTYPE *)rgtypeCHARACTER_SETS; // Set the count of columns and restrictions m_cColumns = cCHARACTER_SETS; m_cRestrictions = cCHARACTER_SETS_RESTRICTIONS; // Set Character Sets Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszCharacter_SetRestriction); PRVTRACE(L"GetSchemaInfo::CHARACTER_SETS\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowCHARACTER_SETS // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_CHARACTER_SETS(DBCOUNTITEM iRow, BYTE * pData) { ULONG iBind=0; // Binding Count DATA * pColumn=NULL; // Data Structure CCol col; BOOL fResults=TRUE; // don't need to go farther if I have what I'm looking for if(m_fCaptureRestrictions && m_fCaptureRestrictions) return FALSE; // Check the count of columns returned if(iRow == 1) COMPARE(cCHARACTER_SETS <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"Row[%lu],Col[%s]:CHARACTER_SETS:", iRow, m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1:// CHARACTER SET CATALOG if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_CHARACTER_SETS:CHARACTER SET CATALOG restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2:// CHARACTER SET SCHEMA if(m_restrict & SECOND) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR2,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes2) { odtLog << L"VerifyRow_CHARACTER_SETS:CHARACTER SET SCHEMA restriction failed\n"; m_fRes2=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 3:// CHARACTER_SET_NAME if(m_restrict & THIRD) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR3,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes3) { odtLog << L"VerifyRow_CHARACTER_SETS:CHARACTER SET NAME restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } if(m_fCaptureRestrictions) { m_pwszCharacter_SetRestriction = (WCHAR *) PROVIDER_ALLOC((wcslen((WCHAR *) pColumn->bValue)*sizeof(WCHAR)) + sizeof(WCHAR)); if(m_pwszCharacter_SetRestriction) wcscpy(m_pwszCharacter_SetRestriction,(TYPE_WSTR) pColumn->bValue); } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 4:// FORM_OF_USE case 6:// DEFAULT_COLLATE_CATALOG case 7:// DEFAULT_COLLATE_SCHEMA case 8:// DEFAULT_COLLATE_NAME PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 5:// NUMBER OF CHARACTERS PRVTRACE(L"%d\n",*(TYPE_I8 *)pColumn->bValue); break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"CHARACTER SETS: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - CHARACTER SETS provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else { PRVTRACE(L"%s=",m_rgDBCOLUMNINFO[iBind].pwszName); RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // CHECK_CONSTRAINTS // 1. Constraint Catalog // 2. Constraint Schema // 3. Constraint Name //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_CHECK_CONSTRAINTS() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszCHECK_CONSTRAINTS; m_rgColumnTypes = (DBTYPE *)rgtypeCHECK_CONSTRAINTS; // Set the count of columns and restrictions m_cColumns = cCHECK_CONSTRAINTS; m_cRestrictions = cCHECK_CONSTRAINTS_RESTRICTIONS; // Set Constraint Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszCheck_ConstraintRestriction); PRVTRACE(L"GetSchemaInfo::CHECK_CONSTRAINTS\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowCHECK_CONSTRAINTS // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_CHECK_CONSTRAINTS(DBCOUNTITEM iRow, BYTE * pData) { ULONG iBind=0; // Binding Count DATA * pColumn=NULL; // Data Structure CCol col; BOOL fResults=TRUE; // don't need to go farther if I have what I'm looking for if(m_fCaptureRestrictions && m_pwszCheck_ConstraintRestriction) return FALSE; // Check the count of columns returned if(iRow == 1) COMPARE(cCHECK_CONSTRAINTS <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"Row[%lu],Col[%s]:CHECK_CONSTRAINTS:", iRow, m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1:// CHECK_CONSTRAINTS CATALOG if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_CHECK_CONSTRAINTS:CHECK_CONSTRAINTS CATALOG restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2:// CHECK_CONSTRAINTS SCHEMA if(m_restrict & SECOND) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR2,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes2) { odtLog << L"VerifyRow_CHECK_CONSTRAINTS:CHECK_CONSTRAINTS SCHEMA restriction failed\n"; m_fRes2=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 3:// CHECK_CONSTRAINTS NAME if(m_restrict & THIRD) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR3,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes3) { odtLog <bValue)*sizeof(WCHAR)) + sizeof(WCHAR)); if(m_pwszCheck_ConstraintRestriction) wcscpy(m_pwszCheck_ConstraintRestriction,(TYPE_WSTR) pColumn->bValue); } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 4:// CHECK_CLAUSE case 5:// DESCRIPTION PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"CHECK CONSTRAINTS: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - CHECK CONSTRAINTS provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else { PRVTRACE(L"%s=",m_rgDBCOLUMNINFO[iBind].pwszName); RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // COLLATIONS // 1. Collation Catalog // 2. Collation Schema // 3. Collation Name //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_COLLATIONS() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszCOLLATIONS; m_rgColumnTypes = (DBTYPE *)rgtypeCOLLATIONS; // Set the count of columns and restrictions m_cColumns = cCOLLATIONS; m_cRestrictions = cCOLLATIONS_RESTRICTIONS; // Set Collation Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszCollationRestriction); PRVTRACE(L"GetSchemaInfo::COLLATIONS\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowCOLLATIONS // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_COLLATIONS(DBCOUNTITEM iRow, BYTE * pData) { ULONG iBind=0; // Binding Count DATA * pColumn=NULL; // Data Structure CCol col; BOOL fResults=TRUE; // don't need to go farther if I have what I'm looking for if(m_fCaptureRestrictions && m_pwszCollationRestriction) return FALSE; // Check the count of columns returned if(iRow == 1) COMPARE(cCOLLATIONS <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"Row[%lu],Col[%s]:COLLATIONS:", iRow, m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1:// COLLATIONS CATALOG if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_COLLATIONS:COLLATIONS CATALOG restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2:// COLLATIONS SCHEMA if(m_restrict & SECOND) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR2,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes2) { odtLog << L"VerifyRow_COLLATIONS:COLLATIONS SCHEMA restriction failed\n"; m_fRes2=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 3:// COLLATIONS_NAME if(m_restrict & THIRD) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR3,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes3) { odtLog << L"VerifyRow_COLLATIONS:COLLATIONS NAME restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } if(m_fCaptureRestrictions) { m_pwszCollationRestriction = (WCHAR *) PROVIDER_ALLOC((wcslen((WCHAR *) pColumn->bValue)*sizeof(WCHAR)) + sizeof(WCHAR)); if(m_pwszCollationRestriction) wcscpy(m_pwszCollationRestriction,(TYPE_WSTR) pColumn->bValue); } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 4:// CHARACTER SET CATALOG case 5:// CHARACTER SET SCHEMA case 6:// CHARACTER SET NAME PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 7:// PAD ATTRIBUTE if( (!COMPARE(0, wcscmp((TYPE_WSTR)pColumn->bValue,L"NO PAD")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"PAD SPACE")))) { odtLog << L"VerifyRow_COLLATIONS:PAD ATTRIBUTE expected NO PAD or PAD SPACE but recieved " << (TYPE_WSTR)pColumn->bValue << ENDL; fResults = FALSE; } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"COLLATIONS: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - COLLATIONS provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else { PRVTRACE(L"%s=",m_rgDBCOLUMNINFO[iBind].pwszName); RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // COLUMN_DOMAIN_USAGE // 1. Domain Catalog // 2. Domain Schema // 3. Domain Name // 4. Column Name //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_COLUMN_DOMAIN_USAGE() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszCOLUMN_DOMAIN_USAGE; m_rgColumnTypes = (DBTYPE *)rgtypeCOLUMN_DOMAIN_USAGE; // Set the count of columns and restrictions m_cColumns = cCOLUMN_DOMAIN_USAGE; m_cRestrictions = cCOLUMN_DOMAIN_USAGE_RESTRICTIONS; // Set Domain Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszDomainRestriction); SetRestriction(FOURTH,4, &m_wszR4, m_pwszColumnRestriction); PRVTRACE(L"GetSchemaInfo::COLUMN_DOMAIN_USAGE\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowDOMAIN_COLUMN_USAGE // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_COLUMN_DOMAIN_USAGE(DBCOUNTITEM iRow, BYTE * pData) { ULONG iBind=0; // Binding Count DATA * pColumn=NULL; // Data Structure CCol col; BOOL fResults=TRUE; // don't need to go farther if I have what I'm looking for if(m_fCaptureRestrictions && m_pwszDomainRestriction) return FALSE; // Check the count of columns returned if(iRow == 1) COMPARE(cCOLUMN_DOMAIN_USAGE <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"Row[%lu],Col[%s]:COLUMN_DOMAIN_USAGE:", iRow, m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1:// DOMAIN CATALOG if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_COLUMN_DOMAIN_USAGE:DOMAIN CATALOG restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2:// DOMAIN SCHEMA if(m_restrict & SECOND) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR2,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes2) { odtLog << L"VerifyRow_COLUMN_DOMAIN_USAGE:DOMAIN SCHEMA restriction failed\n"; m_fRes2=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 3:// DOMAIN_NAME if(m_restrict & THIRD) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR3,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes3) { odtLog << L"VerifyRow_COLUMN_DOMAIN_USAGE:DOMAIN NAME restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } if(m_fCaptureRestrictions) { m_pwszDomainRestriction = (WCHAR *) PROVIDER_ALLOC((wcslen((WCHAR *) pColumn->bValue)*sizeof(WCHAR)) + sizeof(WCHAR)); if(m_pwszDomainRestriction) wcscpy(m_pwszDomainRestriction,(TYPE_WSTR) pColumn->bValue); } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 4:// TABLE CATALOG case 5:// TABLE SCHEMA case 6:// TABLE NAME case 7:// COLUMN NAME PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 8:// COLUMN GUID PRVTRACE(L"\n"); case 9:// COLUMN PROPID PRVTRACE(L"%d\n",*(TYPE_UI4 *)pColumn->bValue); break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"COLUMN DOMAIN USAGE: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - COLUMN DOMAIN USAGE provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else { PRVTRACE(L"%s=",m_rgDBCOLUMNINFO[iBind].pwszName); RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // COLUMN_PRIVILEGES // 1. Table Catalog // 2. Table Schema // 3. Table Name // 4. Column Name // 5. Grantor // 6. Grantee //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_COLUMN_PRIVILEGES() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszCOLUMN_PRIVILEGES; m_rgColumnTypes = (DBTYPE *)rgtypeCOLUMN_PRIVILEGES; // Set the count of columns and restrictions m_cColumns = cCOLUMN_PRIVILEGES; m_cRestrictions = cCOLUMN_PRIVILEGES_RESTRICTIONS; // Set Table Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszTableRestriction); SetRestriction(FOURTH,4, &m_wszR4, m_pwszColumnRestriction); SetRestriction(FIFTH, 5, &m_wszR5, m_pwszGrantorRestriction); SetRestriction(SIXTH, 6, &m_wszR6, m_pwszGranteeRestriction); // Set expected row count. Since we create a table and we know // how many columns there are we must have at least that number of // rows, unless restricted to a given column. if (!m_wszR4) SetRowCount(MIN_REQUIRED, m_pTable->CountColumnsOnTable()); PRVTRACE(L"GetSchemaInfo::COLUMN_PRIVILEGES\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowCOLUMN_PRIVILEGES // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_COLUMN_PRIVILEGES(DBCOUNTITEM iRow, BYTE * pData) { ULONG iBind=0; // Binding Count DATA * pColumn=NULL; // Data Structure CCol col; BOOL fResults=TRUE; int test=0; // don't need to go farther if I have what I'm looking for if(m_fCaptureRestrictions && m_pwszGrantorRestriction && m_pwszGranteeRestriction) return FALSE; // Check the count of columns returned if(iRow == 1) COMPARE(cCOLUMN_PRIVILEGES <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"COLUMN_PRIVILEGES:Row[%lu],Col[%d,%s]:", // iRow, // m_rgDBCOLUMNINFO[iBind].iOrdinal, // m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1:// GRANTOR if(m_restrict & FIFTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR5,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes5) { odtLog << L"VerifyRow_COLUMN_PRIVILEGES:GRANTOR 5 restriction failed\n"; m_fRes5=FALSE; fResults = FALSE; } } } if(m_fCaptureRestrictions) { m_pwszGrantorRestriction = (WCHAR *) PROVIDER_ALLOC((wcslen((WCHAR *) pColumn->bValue)*sizeof(WCHAR)) + sizeof(WCHAR)); if(m_pwszGrantorRestriction) wcscpy(m_pwszGrantorRestriction,(TYPE_WSTR) pColumn->bValue); } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2:// GRANTEE if(m_restrict & SIXTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR6,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes6) { odtLog << L"VerifyRow_COLUMN_PRIVILEGES:GRANTEE 6 restriction failed\n"; m_fRes6=FALSE; fResults = FALSE; } } } if(m_fCaptureRestrictions) { m_pwszGranteeRestriction = (WCHAR *) PROVIDER_ALLOC((wcslen((WCHAR *) pColumn->bValue)*sizeof(WCHAR)) + sizeof(WCHAR)); if(m_pwszGranteeRestriction) wcscpy(m_pwszGranteeRestriction,(TYPE_WSTR) pColumn->bValue); } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 3:// TABLE_CATALOG if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_COLUMN_PRIVILEGES:TABLE_CATALOG 1 restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 4:// TABLE_SCHEMA if(m_restrict & SECOND) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR2,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes2) { odtLog << L"VerifyRow_COLUMN_PRIVILEGES:TABLE_SCHEMA 2 restriction failed\n"; m_fRes2=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 5:// TABLE_NAME if(m_restrict & THIRD) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR3,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes3) { odtLog << L"VerifyRow_COLUMN_PRIVILEGES:TABLE_NAME 3 restriction failed\n"; m_fRes3=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 6:// COLUMN_NAME if(m_restrict & FOURTH) { test=_wcsicmp((TYPE_WSTR)m_wszR4,(TYPE_WSTR)pColumn->bValue); if(!COMPARE(0, _wcsicmp((WCHAR *)m_wszR4,(WCHAR *)pColumn->bValue))) { if(m_fRes4) { odtLog << L"VerifyRow_COLUMN_PRIVILEGES:COLUMN_NAME 4 restriction failed\n"; m_fRes4 = FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 7:// COLUMN_GUID // TODO: Can I do anything interesting with a GUID? PRVTRACE(L"\n"); break; case 8:// COLUMN_PROPID PRVTRACE(L"%ul\n",*(TYPE_UI4 *)pColumn->bValue); break; case 9:// PRIVILEGE_TYPE if( (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"SELECT")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"DELETE")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"INSERT")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"UPDATE")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"REFERENCES"))) { odtLog << L"VerifyRow_COLUMN_PRIVILEGES:PRIVILEGE_TYPE expected SELECT,DELETE,INSERT,UPDATE, or REFERENCES but received " << (TYPE_WSTR)pColumn->bValue << ENDL; fResults = FALSE; } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 10:// IS_GRANTABLE if((*(TYPE_BOOL *)pColumn->bValue)==VARIANT_TRUE) PRVTRACE(L"YES\n"); else PRVTRACE(L"NO\n"); break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"COLUMN PRIVILEGES: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - COLUMN PRIVILEGES provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else { RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // COLUMNS // 1. Table Catalog // 2. Table Schema // 3. Table Name // 4. Column Name //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_COLUMNS() { // Set the Schema column Names and Types m_cColumns = cCOLUMNS; m_rgColumnNames = (WCHAR **)rgwszCOLUMNS; m_rgColumnTypes = (DBTYPE *)rgtypeCOLUMNS; // Set the count of columns and restrictions m_cRestrictions = cCOLUMNS_RESTRICTIONS; // Set Table Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszTableRestriction); SetRestriction(FOURTH,4, &m_wszR4, m_pwszColumnRestriction); // Set an Invalid Table Restriction if(m_restrict & FIFTH) { SetRestriction(FIFTH,5, &m_wszR5, m_pwszTableRestriction); m_cRestrictions = 5; } // Set expected row count. Since we create a table and we know // how many columns there are we must have at least that number of // rows SetRowCount(MIN_REQUIRED, m_pTable->CountColumnsOnTable()); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowCOLUMNS // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_COLUMNS(DBCOUNTITEM iRow, BYTE * pData) { ULONG iBind=0; // Binding Count ULONG iIndex = 0; // Index into rgColInfo array CCol col; BOOL fResults=TRUE; ULONG cColumns = 0; ULONG iOrdinalBinding = 6+!m_rgDBCOLUMNINFO[0].iOrdinal; // Per spec, the columns rowset must list columns a user has access to, therefore the user // must have access to the associated table. Retrieve columns info for the table if this is a new // table. if (S_OK != GetColumnInfo(pData, m_rgDBBINDING)) return FALSE; // If we don't have an m_prgColInfo array, then GetColumnInfo returns S_FALSE above. // Make our best guess of the index iIndex = m_ulTableOrdinal-1+!m_prgColInfo[0].iOrdinal; // If the provider returned the data out of order we have to find the ordinal ASSERT(m_rgDBBINDING[iOrdinalBinding].iOrdinal == 7); if (STATUS_BINDING(m_rgDBBINDING[iOrdinalBinding], pData) == DBSTATUS_S_OK) { DBORDINAL iOrdinal = (ULONG_PTR)VALUE_BINDING(m_rgDBBINDING[iOrdinalBinding], pData); // If this isn't the right index ordinals won't match if (m_prgColInfo[iIndex].iOrdinal != iOrdinal) { // Find the ordinal value in m_prgColInfo array as this row may not be in order for (ULONG iColInfo = 0; iColInfo < m_cColumns; iColInfo++) { if (m_prgColInfo[iColInfo].iOrdinal == iOrdinal) { iIndex = iColInfo; break; } } } } // Make sure we don't crash, but this will cause lots of errors if (!COMPARE(iIndex <= m_cColInfo - !m_prgColInfo[0].iOrdinal, TRUE)) iIndex = 0; // Check the count of columns returned if(iRow == 1) COMPARE(cCOLUMNS <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { DBBINDING * pBind = &m_rgDBBINDING[iBind]; DBORDINAL iOrdinal = m_rgDBCOLUMNINFO[iBind].iOrdinal; DBSTATUS ulStatus = STATUS_BINDING(*pBind, pData); DATA * pColumn=(DATA *) (pData + pBind->obStatus); BYTE * pValue = pColumn->bValue; if (m_fRes4 && m_fCaptureRestrictions) { m_fCaptureRestrictions = FALSE; return FALSE; } switch(iOrdinal) { // TABLE_CATALOG case 1: fResults &= TestReturnData(iRow,pColumn,FIRST,&m_fRes1,m_wszR1); break; // TABLE_SCHEMA case 2: fResults &= TestReturnData(iRow,pColumn,SECOND,&m_fRes2,m_wszR2); break; // TABLE_NAME case 3: fResults &= TestReturnData(iRow,pColumn,THIRD,&m_fRes3,m_wszR3); break; // COLUMN_NAME case 4: fResults &= TestReturnData(iRow,pColumn,FOURTH,&m_fRes4,m_wszR4); break; case 5: // COLUMN_GUID break; case 13:// TYPE_GUID break; case 6: //COLUMN_PROPID break; case 7: // ORDINAL_POSITION if (ulStatus == DBSTATUS_S_OK) { // Status is OK, warning if ordinals don't match // Providers are not required to return results in ordinal order, since // sort is only on catalog, schema, and name, so only a warning. // If restriction is only on column then the ordinal may not match anyway. if (!m_fRes4) { COMPAREW(m_ulTableOrdinal, (ULONG)(ULONG_PTR)VALUE_BINDING(*pBind, pData)); if (m_ulTableOrdinal != (ULONG)(ULONG_PTR)VALUE_BINDING(*pBind, pData)) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Ordinal didn't match expected value.\n"; } else { // We will assume if the index for the matching ordinal contains // the proper column name that it was the right ordinal. if (RelCompareString(m_wszR4, m_prgColInfo[iIndex].pwszName)) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Ordinal didn't match expected value.\n"; } } else if (ulStatus == DBSTATUS_S_ISNULL) { // Status is NULL. While this is allowed, it's not normally the case, so warn COMPAREW(ulStatus, DBSTATUS_S_OK); odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"DBSTATUS_S_ISNULL returned.\n"; } else { // Otherwise this is a failure. if (!COMPARE(ulStatus, DBSTATUS_S_OK)) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Invalid value returned.\n"; } break; case 10:// COLUMN FLAGS // This column cannot contain NULL if (COMPARE(ulStatus, DBSTATUS_S_OK)) CCOMPARE(m_EC, m_prgColInfo[iIndex].dwFlags == *(DBCOLUMNFLAGS *)pValue, EC_BAD_COLUMN_FLAGS, L"COLUMN_FLAGS value did not match GetColumnInfo", FALSE); break; case 14:// CHARACTER_MAXIMUM_LENGTH switch(m_prgColInfo[iIndex].wType) { // case DBTYPE_BOOL: // We assume BOOL is not a "bit" column per spec. case DBTYPE_BYTES: case DBTYPE_STR: case DBTYPE_WSTR: if (COMPARE(ulStatus, DBSTATUS_S_OK)) { if (m_prgColInfo[iIndex].ulColumnSize == ~0 && !COMPARE(*(ULONG *)pValue, 0)) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Must be 0 for column without defined max length.\n"; else CCOMPARE(m_EC, *(ULONG *)pValue == m_prgColInfo[iIndex].ulColumnSize, EC_BAD_CHARACTER_MAXIMUM_LENGTH, L"CHARACTER_MAXIMUM_LENGTH value did not match GetColumnInfo", FALSE); } else odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Cannot be NULL for variable length column.\n"; break; // NULL for all other data types default: if (!COMPARE(ulStatus, DBSTATUS_S_ISNULL)) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Status was not DBSTATUS_S_ISNULL for non-char, binary, or bit column\n"; } break; case 15:// CHARACTER_OCTET_LENGTH switch(m_prgColInfo[iIndex].wType) { case DBTYPE_BYTES: case DBTYPE_STR: case DBTYPE_WSTR: if (COMPARE(ulStatus, DBSTATUS_S_OK)) { if (m_prgColInfo[iIndex].ulColumnSize == ~0 && !COMPARE(*(ULONG *)pValue, 0)) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Must be 0 for column without defined max length.\n"; else { DBLENGTH ulOctetLen = m_prgColInfo[iIndex].ulColumnSize; if (m_prgColInfo[iIndex].wType == DBTYPE_WSTR) ulOctetLen *= sizeof(WCHAR); CCOMPARE(m_EC, ulOctetLen == *(ULONG *)pValue, EC_BAD_CHARACTER_OCTET_LENGTH, L"CHARACTER_OCTET_LENGTH value did not match GetColumnInfo", FALSE); } } break; // NULL for all other data types default: if (!COMPARE(ulStatus, DBSTATUS_S_ISNULL)) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Status was not DBSTATUS_S_ISNULL for non-char, binary, or bit column\n"; } break; case 18:// DATETIME_PRECISION switch(m_prgColInfo[iIndex].wType) { case DBTYPE_DBTIMESTAMP: if (COMPARE(ulStatus, DBSTATUS_S_OK)) CCOMPARE(m_EC, *(ULONG *)pValue == (ULONG)m_prgColInfo[iIndex].bScale, EC_BAD_DATETIME_PRECISION, L"DATETIME_PRECISION value did not match GetColumnInfo", FALSE); break; // NULL for all other data types default: if (!COMPARE(ulStatus, DBSTATUS_S_ISNULL)) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Status was not DBSTATUS_S_ISNULL for non-char, binary, or bit column\n"; } break; case 8: // COLUMN_HASDEFAULT // We can't actually try the default value except for our test table, so we don't know // if it actually would work or not for other tables. // Note that COLUMN_DEFAULT may be NULL even if HASDEFAULT is TRUE but the converse // is not true. if (COMPARE(ulStatus, DBSTATUS_S_OK)) { // Make sure we know the proper binding for DBCOLUMN_DEFAULT ASSERT (m_rgDBBINDING[8+!m_rgDBCOLUMNINFO[0].iOrdinal].iOrdinal == 9); DBSTATUS ulDefaultStatus = STATUS_BINDING(m_rgDBBINDING[8+!m_rgDBCOLUMNINFO[0].iOrdinal], pData); // If the COLUMN_DEFAULT is non-NULL, then HASDEFAULT should be TRUE, otherwise // we're not sure if (S_OK == ulDefaultStatus && !COMPARE(*(VARIANT_BOOL *)pValue, VARIANT_TRUE)) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Invalid value returned.\n"; // TODO: If the current table is the automaketable for this test try to use the default // value and make sure it matches expected. } else odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Invalid status returned.\n"; break; case 9: // COLUMN DEFAULT if (ulStatus == DBSTATUS_S_OK) { // For now, just make sure the length is right so we read the default value if (!COMPARE(wcslen((WCHAR *)pValue)*sizeof(WCHAR), LENGTH_BINDING(m_rgDBBINDING[iBind], pData))) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Default value has the wrong length.\n"; // TODO: If the current table is the automaketable for this test try to use the default // value and make sure it matches expected. } else if (!COMPARE(ulStatus, DBSTATUS_S_ISNULL)) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Invalid status returned.\n"; break; case 11:// IS_NULLABLE { VARIANT_BOOL fNullable = m_prgColInfo[iIndex].dwFlags & DBCOLUMNFLAGS_ISNULLABLE ? VARIANT_TRUE : VARIANT_FALSE; if (!COMPARE(fNullable, *(VARIANT_BOOL *)pValue)) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Invalid value returned.\n"; break; } case 12:// DATA_TYPE // This column cannot contain NULL if (COMPARE(ulStatus, DBSTATUS_S_OK) && !COMPARE(m_prgColInfo[iIndex].wType, *(DBTYPE *)pValue)) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Invalid value returned.\n"; break; case 16:// NUMERIC_PRECISION if (IsNumericType(m_prgColInfo[iIndex].wType)) { if (COMPARE(ulStatus, DBSTATUS_S_OK) && !COMPARE(*(USHORT *)pValue, (USHORT)m_prgColInfo[iIndex].bPrecision)) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Invalid value returned.\n"; } // NULL for all other data types else if (!COMPARE(ulStatus, DBSTATUS_S_ISNULL)) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Status was not DBSTATUS_S_ISNULL for non-numeric column\n"; break; case 17:// NUMERIC_SCALE if (m_prgColInfo[iIndex].wType == DBTYPE_DECIMAL || m_prgColInfo[iIndex].wType == DBTYPE_NUMERIC || m_prgColInfo[iIndex].wType == DBTYPE_VARNUMERIC) { if (COMPARE(ulStatus, DBSTATUS_S_OK)) { SHORT sScale = (SHORT)m_prgColInfo[iIndex].bScale; // Account for negative scale values if (m_prgColInfo[iIndex].dwFlags & DBCOLUMNFLAGS_SCALEISNEGATIVE) sScale = -sScale; if (!COMPARE(*(SHORT *)pValue, sScale)) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Invalid value returned.\n"; } } // NULL for all other data types else if (!COMPARE(ulStatus, DBSTATUS_S_ISNULL)) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Status was not DBSTATUS_S_ISNULL for non-DECIMAL, NUMERIC column\n"; break; case 19:// CHARACTER_SET_CATALOG case 20:// CHARACTER_SET_SCHEMA case 21:// CHARACTER_SET_NAME case 22:// COLLATION_CATALOG case 23:// COLLATION_SCHEMA case 24:// COLLATION_NAME case 25:// DOMAIN_CATALOG case 26:// DOMAIN_SCHEMA case 27:// DOMAIN_NAME if (ulStatus == DBSTATUS_S_OK) { // For now, just make sure the length is right so we read the value if (!COMPARE(wcslen((WCHAR *)pValue)*sizeof(WCHAR), LENGTH_BINDING(m_rgDBBINDING[iBind], pData))) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Length is incorrect.\n"; // We really don't expect empty strings for any of these if (!COMPARE(wcslen((WCHAR *)pValue) > 0, TRUE)) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Empty string returned.\n"; } else if (!COMPARE(ulStatus, DBSTATUS_S_ISNULL)) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Invalid status returned.\n"; break; case 28:// DESCRIPTION // If Description is valid it may still be an empty string. All we test // here is if it's null terminated properly. if (ulStatus == DBSTATUS_S_OK) { if (!COMPARE(wcslen((WCHAR *)pValue)*sizeof(WCHAR), LENGTH_BINDING(m_rgDBBINDING[iBind], pData))) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Length is incorrect.\n"; } // Description is allowed to be NULL else if (!COMPARE(ulStatus, DBSTATUS_S_ISNULL)) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Unexpected status value found.\n"; break; // PROVIDER SPECIFIC default: if (iRow == 1) { if(!m_rgDBCOLUMNINFO[iBind].iOrdinal) { if(!COMPARE(GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset), TRUE)) odtLog << L"COLUMNS: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - COLUMNS provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } // We expect to retrieve the column successfully if (ulStatus != DBSTATUS_S_OK && ulStatus != DBSTATUS_S_ISNULL && !COMPARE(ulStatus, DBSTATUS_S_OK)) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Invalid status returned.\n"; break; } } return fResults; } //-------------------------------------------------------------------- // CONSTRAINT_COLUMN_USAGE // 1. Table Catalog // 2. Table Schema // 3. Table Name // 4. Column Name //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_CONSTRAINT_COLUMN_USAGE() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszCONSTRAINT_COLUMN_USAGE; m_rgColumnTypes = (DBTYPE *)rgtypeCONSTRAINT_COLUMN_USAGE; // Set the count of columns and restrictions m_cColumns = cCONSTRAINT_COLUMN_USAGE; m_cRestrictions = cCONSTRAINT_COLUMN_USAGE_RESTRICTIONS; // Set Table Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszTableRestriction); SetRestriction(FOURTH,4, &m_wszR4, m_pwszColumnRestriction); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowCONSTRAINT_COLUMN_USAGE // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_CONSTRAINT_COLUMN_USAGE ( DBCOUNTITEM iRow, BYTE * pData ) { ULONG iBind; // Binding Count DATA * pColumn; // Data Structure CCol col; BOOL fResults = TRUE; // Check the count of columns returned if(iRow == 1) COMPARE(cCONSTRAINT_COLUMN_USAGE <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"Row[%lu],Col[%s]:CONSTRAINT_COLUMN_USAGE:", iRow, m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1:// TABLE_CATALOG if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_CONSTRAINT_COLUMN_USAGE:TABLE_CATALOG restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2:// TABLE_SCHEMA if(m_restrict & SECOND) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR2,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes2) { odtLog << L"VerifyRow_CONSTRAINT_COLUMN_USAGE:TABLE_SCHEMA restriction failed\n"; m_fRes2=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(WCHAR *)pColumn->bValue); break; case 3: // TABLE_NAME if(m_restrict & THIRD) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR3,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes3) { odtLog << L"VerifyRow_CONSTRAINT_COLUMN_USAGE:TABLE_NAME restriction failed\n"; m_fRes3=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 4:// COLUMN_NAME if(m_restrict & FOURTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR4,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes4) { odtLog << L"VerifyRow_CONSTRAINT_COLUMN_USAGE:COLUMN_NAME restriction failed\n"; m_fRes4=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 5: // COLUMN_GUID PRVTRACE(L"\n"); break; case 6: //COLUMN_PROPID PRVTRACE(L"%d\n",*(TYPE_UI4 *)pColumn->bValue); break; case 7: // CONSTRAINT CATALOG case 8: // CONSTRAINT SCHEMA case 9: // CONSTRAINT NAME PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"CONSTRAINT COLUMN USAGE: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - CONSTRAINT COLUMN USAGE provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } break; } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else { PRVTRACE(L"%s=",m_rgDBCOLUMNINFO[iBind].pwszName); RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // CONSTRAINT_TABLE_USAGE // 1. Table Catalog // 2. Table Schema // 3. Table Name //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_CONSTRAINT_TABLE_USAGE() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszCONSTRAINT_TABLE_USAGE; m_rgColumnTypes = (DBTYPE *)rgtypeCONSTRAINT_TABLE_USAGE; // Set the count of columns and restrictions m_cColumns = cCONSTRAINT_TABLE_USAGE; m_cRestrictions = cCONSTRAINT_TABLE_USAGE_RESTRICTIONS; // Set Table Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszTableRestriction); PRVTRACE(L"GetSchemaInfo::CONSTRAINT_TABLE_USAGE\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowCONSTRAINT_TABLE_USAGE // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_CONSTRAINT_TABLE_USAGE ( DBCOUNTITEM iRow, BYTE * pData ) { ULONG iBind; // Binding Count DATA * pColumn; // Data Structure CCol col; BOOL fResults = TRUE; // Check the count of columns returned if(iRow == 1) COMPARE(cCONSTRAINT_TABLE_USAGE <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"Row[%lu],Col[%s]:CONSTRAINT_TABLE_USAGE:", iRow, m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1:// TABLE_CATALOG if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_CONSTRAINT_TABLE_USAGE:TABLE_CATALOG restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2:// TABLE_SCHEMA if(m_restrict & SECOND) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR2,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes2) { odtLog << L"VerifyRow_CONSTRAINT_TABLE_USAGE:TABLE_SCHEMA restriction failed\n"; m_fRes2=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 3: // TABLE_NAME if(m_restrict & THIRD) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR3,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes3) { odtLog << L"VerifyRow_CONSTRAINT_TABLE_USAGE:TABLE_NAME restriction failed\n"; m_fRes3=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 4: // CONSTRAINT CATALOG case 5: // CONSTRAINT SCHEMA case 6: //CONSTRAINT NAME PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"CONSTRAINT TABLE USAGE: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - CONSTRAINT TABLE USAGE provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } break; } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else { PRVTRACE(L"%s=",m_rgDBCOLUMNINFO[iBind].pwszName); RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // FOREIGN_KEYS // 1. PK_TABLE_CATALOG // 2. PK TABLE SCHEMA // 3. PK TABLE NAME // 4. FK TABLE CATALOG // 5. FK TABLE SCHEMA // 6. FK TABLE ANEM // // Caveat: These restrictions will be tested as part of ad-hoc for the // following reasons, The following code is a place holder in case // the problems listed below are ever fixed: // 1. Can't change private library's create table because not all // drivers will support PK and FK systax, create table would fail // 2. Can't use alter table statement because I can only add column // that allow nulls and pk and fk are not nullable. // //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_FOREIGN_KEYS() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszFOREIGN_KEYS; m_rgColumnTypes = (DBTYPE *)rgtypeFOREIGN_KEYS; // Set the count of columns and restrictions m_cColumns = cFOREIGN_KEYS; m_cRestrictions = cFOREIGN_KEYS_RESTRICTIONS; // Set PK Table Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszPK_TableRestriction); SetRestriction(FOURTH,4, &m_wszR4, m_pwszCatalogRestriction); SetRestriction(FIFTH, 5, &m_wszR5, m_pwszSchemaRestriction); SetRestriction(SIXTH, 6, &m_wszR6, m_pwszFK_TableRestriction); // Set expected row count if (m_fForeignKey) // We created a foreign key, so there must be one row SetRowCount(MIN_REQUIRED, 1); PRVTRACE(L"GetSchemaInfo::FOREIGN_KEYS\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowFOREIGN_KEYS // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_FOREIGN_KEYS ( DBCOUNTITEM iRow, BYTE * pData ) { ULONG iBind; // Binding Count DATA * pColumn; // Data Structure CCol col; BOOL fResults = TRUE; // Check the count of columns returned if(iRow == 1) COMPARE(cFOREIGN_KEYS <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"Row[%lu],Col[%s]:FOREIGN_KEYS:", iRow, m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1:// PK TABLE_CATALOG if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_FOREIGN_KEYS:PK TABLE_CATALOG restriction failed\n"; m_fRes1=FALSE; fResults=FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2:// PK TABLE_SCHEMA if(m_restrict & SECOND) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR2,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes2) { odtLog << L"VerifyRow_FOREIGN_KEYS:PK TABLE_SCHEMA restriction failed\n"; m_fRes2=FALSE; fResults=FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 3: // PK TABLE_NAME if(m_restrict & THIRD) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR3,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes3) { odtLog << L"VerifyRow_FOREIGN_KEYS:PK TABLE_NAME restriction failed\n"; m_fRes3=FALSE; fResults=FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 4: // PK COLUMN NAME case 10:// FK_COLUMN NAME PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 14:// UPDATE RULE case 15:// DELETE RULE if( (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"CASCADE")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"SET NULL")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"SET DEFAULT")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"NO ACTION"))) { odtLog << L"VerifyRow_FOREIGN_KEYS:UPDATE or DELETE RULE expected CASCADE,SET NULL,SET DEFAULT, or NO ACTION but received " << (TYPE_WSTR)pColumn->bValue << ENDL; fResults=FALSE; } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 5: // PK COLUMN GUID case 11:// FK COLUMN GUID case 16:// PK_NAME case 17:// FK_NAME case 18:// DEFERRABILITY PRVTRACE(L"\n"); case 6: // PK COLUMN PROPID case 12:// FK COLUMN PROPID case 13:// ORDINAL PRVTRACE(L"%d\n",*(TYPE_UI4 *)pColumn->bValue); break; case 7:// FK TABLE_CATALOG if(m_restrict & FOURTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR4,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes4) { odtLog << L"VerifyRow_FOREIGN_KEYS:FK TABLE_CATALOG restriction failed\n"; m_fRes4=FALSE; fResults=FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 8:// FK TABLE_SCHEMA if(m_restrict & FIFTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR5,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes5) { odtLog << L"VerifyRow_FOREIGN_KEYS:FK TABLE_SCHEMA restriction failed\n"; m_fRes5=FALSE; fResults=FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 9: // FK TABLE_NAME if(m_restrict & SIXTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR6,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes6) { odtLog << L"VerifyRow_FOREIGN_KEYS:FK TABLE_NAME restriction failed\n"; m_fRes6=FALSE; fResults=FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"FOREIGN KEYS: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - FOREIGN KEYS provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } break; } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults=FALSE; } else { PRVTRACE(L"%s=",m_rgDBCOLUMNINFO[iBind].pwszName); RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // INDEXES // 1. Table Catalog // 2. Table Schema // 3. Index Name // 4. Type // 5. Table Name //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_INDEXES() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszINDEXES; m_rgColumnTypes = (DBTYPE *)rgtypeINDEXES; // Set the count of columns and restrictions m_cColumns = cINDEXES; m_cRestrictions = cINDEXES_RESTRICTIONS; // Set Table Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszIndexRestriction); if((m_currentBitMask & FOURTH) || m_fPassUnsupportedRestrictions) { if((m_restrict & FOURTH)|| (m_restrict & ALLRES)) { m_ulR = DBPROPVAL_IT_BTREE; m_rgvarRestrict[3].vt = VT_UI2; m_rgvarRestrict[3].lVal = DBPROPVAL_IT_BTREE; m_cRestrictionsCurrent ++; SetRestriction(FOURTH); RESTRICTNOTSUPPORTED(FOURTH) } } // TABLE NAME SetRestriction(FIFTH, 5, &m_wszR5, m_pwszTableRestriction); PRVTRACE(L"GetSchemaInfo::INDEXES\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowINDEXES // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_INDEXES ( DBCOUNTITEM iRow, BYTE * pData ) { ULONG iBind; // Binding Count CCol col; BOOL fResults = TRUE; // Check the count of columns returned if(iRow == 1) COMPARE(cINDEXES <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { DBBINDING * pBind = &m_rgDBBINDING[iBind]; DBORDINAL iOrdinal = m_rgDBCOLUMNINFO[iBind].iOrdinal; DBSTATUS ulStatus = STATUS_BINDING(*pBind, pData); DATA * pColumn=(DATA *) (pData + pBind->obStatus); BYTE * pValue = pColumn->bValue; // PRVTRACE(L"INDEXES:Row[%lu],Col[%d,%s]:", // iRow, // m_rgDBCOLUMNINFO[iBind].iOrdinal, // m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1:// TABLE_CATALOG if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_INDEXES:TABLE_CATALOG 1 restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2:// TABLE_SCHEMA if(m_restrict & SECOND) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR2,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes2) { odtLog << L"VerifyRow_INDEXES:TABLE_SCHEMA 2 restriction failed\n"; m_fRes2=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 3: // TABLE_NAME if(m_restrict & FIFTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR5,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes5) { odtLog << L"VerifyRow_INDEXES:TABLE_NAME 5 restriction failed\n"; m_fRes5=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 4:// INDEX_CATALOG case 5: // INDEX_SCHEMA case 18:// COLUMN_NAME case 24:// FILTER_CONDIITON PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 6:// INDEX_NAME if(m_restrict & THIRD) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR3,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes3) { odtLog << L"VerifyRow_INDEXES:INDEX_NAME 3 restriction failed\n"; m_fRes3=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 7: // PRIMARY KEY case 8: // UNIQUE case 9: // CLUSTERED case 14:// SORTBOOKMARKS case 15:// AUTOUPDATE case 25:// INTEGRATED if((*(TYPE_BOOL *)pColumn->bValue)==VARIANT_TRUE) PRVTRACE(L"TRUE\n"); else PRVTRACE(L"FALSE\n"); break; case 10:// TYPE if(m_restrict & FOURTH) { if(m_ulR!=(*(TYPE_UI2*)pColumn->bValue)) { odtLog << L"VerifyRow_INDEXES:INDEX_TYPE 4 restriction failed\n"; m_fRes4=FALSE; fResults = FALSE; } } PRVTRACE(L"%d\n",*(TYPE_UI2 *)pColumn->bValue); break; case 11:// FILLFACTOR // This column cannot be NULL if (COMPARE(ulStatus, DBSTATUS_S_OK)) { ULONG ulFillFactor = *(ULONG *)pValue; // Spec change: Fill factor may be 0 if (!COMPARE(ulFillFactor <= 100, TRUE)) odtLog << L"FillFactor: Invalid value returned.\n"; } break; case 12:// INITIALSIZE case 13:// NULLS case 16:// NULCOLLATION case 22:// CARDINALITY case 23:// PAGES PRVTRACE(L"%d\n",*(TYPE_I4 *)pColumn->bValue); break; case 19: // COLUMN_GUID PRVTRACE(L"\n"); break; case 21:// COLLATION PRVTRACE(L"%d\n",*(TYPE_I2 *)pColumn->bValue); break; case 20:// COLUMN_PROPID case 17:// ORDINAL_POSITION PRVTRACE(L"%d\n",*(TYPE_UI4 *)pColumn->bValue); break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"INDEXES: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - INDEXES provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } break; } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; } else { RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // KEY_COLUMN_USAGE // 1. Constraint Catalog Name // 2. Constraint Schema Name // 3. Constraint Name // 4. Table Catalog // 5. Table Schema // 6. Table Name // 7. Column Name //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_KEY_COLUMN_USAGE() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszKEY_COLUMN_USAGE; m_rgColumnTypes = (DBTYPE *)rgtypeKEY_COLUMN_USAGE; // Set the count of columns and restrictions m_cColumns = cKEY_COLUMN_USAGE; m_cRestrictions = cKEY_COLUMN_USAGE_RESTRICTIONS; // Set Constraint Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND, 2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszKey_Column_Usage_ConstraintRestriction); SetRestriction(FOURTH, 4, &m_wszR4, m_pwszCatalogRestriction); SetRestriction(FIFTH, 5, &m_wszR5, m_pwszSchemaRestriction); SetRestriction(SIXTH, 6, &m_wszR6, m_pwszTableRestriction); SetRestriction(SEVENTH,7, &m_wszR7, m_pwszColumnRestriction); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowKEY_COLUMN_USAGE // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_KEY_COLUMN_USAGE ( DBCOUNTITEM iRow, BYTE * pData ) { ULONG iBind; // Binding Count DATA * pColumn; // Data Structure CCol col; BOOL fResults = TRUE; // don't need to go farther if I have what I'm looking for if(m_fCaptureRestrictions && m_pwszKey_Column_Usage_ConstraintRestriction) return FALSE; // Check the count of columns returned if(iRow == 1) COMPARE(cKEY_COLUMN_USAGE <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // PRVTRACE(L"Row[%lu],Col[%s]:KEY_COLUMN_USAGE:", iRow, m_rgDBCOLUMNINFO[iBind].pwszName); // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1:// CONSTRAINT CATALOG if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_KEY_COLUMN_USAGE:CONSTRAINT CATALOG 1 restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2:// CONSTRAINT SCHEMA if(m_restrict & SECOND) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR2,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes2) { odtLog << L"VerifyRow_KEY_COLUMN_USAGE:CONSTRAINT SCHEMA 2 restriction failed\n"; m_fRes2=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 3: // CONSTRAINT NAME if(m_fCaptureRestrictions) { m_pwszKey_Column_Usage_ConstraintRestriction = (WCHAR *) PROVIDER_ALLOC ((wcslen((WCHAR *) pColumn->bValue)*sizeof(WCHAR)) + sizeof(WCHAR)); if(m_pwszKey_Column_Usage_ConstraintRestriction) wcscpy(m_pwszKey_Column_Usage_ConstraintRestriction,(TYPE_WSTR) pColumn->bValue); } if(m_restrict & THIRD) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR3,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes3) { odtLog << L"VerifyRow_KEY_COLUMN_USAGE:CONSTRAINT NAME 3 restriction failed\n"; m_fRes3=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 4:// TABLE_CATALOG if(m_restrict & FOURTH) { if(!COMPARE(0,_wcsicmp((TYPE_WSTR)m_wszR4,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes4) { odtLog << L"VerifyRow_KEY_COLUMN_USAGE:TABLE_CATALOG 4 restriction failed\n"; m_fRes4=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 5:// TABLE_SCHEMA if(m_restrict & FIFTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR5,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes5) { odtLog << L"VerifyRow_KEY_COLUMN_USAGE:TABLE_SCHEMA 5 restriction failed\n"; m_fRes5=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 6: // TABLE_NAME if(m_restrict & SIXTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR6,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes6) { odtLog << L"VerifyRow_KEY_COLUMN_USAGE:TABLE_NAME 6 restriction failed\n"; m_fRes6=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 7:// COLUMN NAME if(m_restrict & SEVENTH) { if(0,_wcsicmp((TYPE_WSTR)m_wszR7,(TYPE_WSTR)pColumn->bValue)) { if(m_fRes7) { odtLog << L"VerifyRow_KEY_COLUMN_USAGE:COLUMN NAME 7 restriction failed\n"; m_fRes7=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 8: // COLUMN_GUID PRVTRACE(L"\n"); break; case 9: // COLUMN PROPID case 10:// ORDINAL POSITION PRVTRACE(L"%d\n",*(TYPE_UI4 *)pColumn->bValue); break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (!m_rgDBCOLUMNINFO[iBind].iOrdinal) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"KEY COLUMN USAGE: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - KEY COLUMN USAGE provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } break; } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else { PRVTRACE(L"%s=",m_rgDBCOLUMNINFO[iBind].pwszName); RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // PRIMARY_KEYS // 1. Table Catalog // 2. Table Name // 3. Table Schem a // // Caveat: this will be handled in ad-hoc see PrepareParams_Foreign_keys() // for explanation. // //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_PRIMARY_KEYS() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszPRIMARY_KEYS; m_rgColumnTypes = (DBTYPE *)rgtypePRIMARY_KEYS; // Set the count of columns and restrictions m_cColumns = cPRIMARY_KEYS; m_cRestrictions = cPRIMARY_KEYS_RESTRICTIONS; // Set Table Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszPK_TableRestriction); // Set expected count of rows if (m_fPrimaryKey) // We created a primary key, so there must be one row SetRowCount(MIN_REQUIRED, 1); PRVTRACE(L"GetSchemaInfo::PRIMARY_KEYS\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowPRIMARY_KEYS // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_PRIMARY_KEYS ( DBCOUNTITEM iRow, BYTE * pData ) { ULONG iBind; // Binding Count CCol col; BOOL fResults = TRUE; // Check the count of columns returned if(iRow == 1) COMPARE(cPRIMARY_KEYS <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { DBBINDING * pBind = &m_rgDBBINDING[iBind]; DBORDINAL iOrdinal = m_rgDBCOLUMNINFO[iBind].iOrdinal; DBSTATUS ulStatus = STATUS_BINDING(*pBind, pData); DATA * pColumn=(DATA *) (pData + pBind->obStatus); BYTE * pValue = pColumn->bValue; // PRVTRACE(L"Row[%lu],Col[%s]:PRIMARY_KEYS", iRow, m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1:// TABLE CATALOG if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_PRIMARY_KEYS:TABLE CATALOG restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2:// TABLE SCHEMA if(m_restrict & SECOND) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR2,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes2) { odtLog << L"VerifyRow_PRIMARY_KEYS:TABLE SCHEMA restriction failed\n"; m_fRes2=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 3: // TABLE NAME if(m_restrict & THIRD) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR3,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes3) { odtLog << L"VerifyRow_PRIMARY_KEYS:TABLE NAME restriction failed\n"; m_fRes3=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 4:// COLUMN NAME case 8:// PK_NAME if (ulStatus == DBSTATUS_S_OK) { // For now, just make sure the length is right so we read the default value if (!COMPARE(wcslen((WCHAR *)pValue)*sizeof(WCHAR), LENGTH_BINDING(m_rgDBBINDING[iBind], pData))) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Default value has the wrong length.\n"; // TODO: If the current table is the primary table for this test make sure it matches expected. } else if (!COMPARE(ulStatus, DBSTATUS_S_ISNULL)) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Invalid status returned.\n"; break; case 5: // COLUMN_GUID case 6: // COLUMN PROPID case 7: // ORDINAL POSITION if (ulStatus != DBSTATUS_S_OK && !COMPARE(ulStatus, DBSTATUS_S_ISNULL)) odtLog << m_pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Invalid status returned.\n"; PRVTRACE(L"%d\n",*(TYPE_UI4 *)pColumn->bValue); break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"PRIMARY KEYS: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - PRIMARY KEYS provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } break; } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else { PRVTRACE(L"%s=",m_rgDBCOLUMNINFO[iBind].pwszName); RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // PROCEDURE_COLUMNS // 1. Procedure Catalog // 2. Procedure Schema // 3. Procedure Name // 4. Column Name // //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_PROCEDURE_COLUMNS() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszPROCEDURE_COLUMNS; m_rgColumnTypes = (DBTYPE *)rgtypePROCEDURE_COLUMNS; // Set the count of columns and restrictions m_cColumns = cPROCEDURE_COLUMNS; m_cRestrictions = cPROCEDURE_COLUMNS_RESTRICTIONS; // Set Procedure Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszProcedureRestriction); SetRestriction(FOURTH,4, &m_wszR4, m_pwszProcedureColumnsRestriction); PRVTRACE(L"GetSchemaInfo::PROCEDURE_COLUMNS\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowPROCEDURE_COLUMNS // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_PROCEDURE_COLUMNS ( DBCOUNTITEM iRow, BYTE * pData ) { ULONG iBind; // Binding Count DATA * pColumn; // Data Structure CCol col; BOOL fResults = TRUE; // Check the count of columns returned if(iRow == 1) COMPARE(cPROCEDURE_COLUMNS <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"Row[%lu],Col[%s]:PROCEDURE_COLUMNS", iRow, m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1:// PROCEDURE CATALOG if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_PROCEDURE_COLUMNS:PROCEDURE CATALOG 1 restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2:// PROCEDURE SCHEMA if(m_restrict & SECOND) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR2,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes2) { odtLog << L"VerifyRow_PROCEDURE_COLUMNS:PROCEDURE SCHEMA 2 restriction failed\n"; m_fRes2=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 3: // PROCEDURE NAME if(m_restrict & THIRD) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR3,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes3) { odtLog << L"VerifyRow_PROCEDURE_COLUMNS:PROCEDURE NAME 3 restriction failed\n"; m_fRes3=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 4:// COLUMN NAME if(m_fCaptureRestrictions) { m_pwszProcedureColumnsRestriction = (WCHAR *) PROVIDER_ALLOC ((wcslen((WCHAR *) pColumn->bValue)*sizeof(WCHAR)) + sizeof(WCHAR)); if(m_pwszProcedureColumnsRestriction) wcscpy(m_pwszProcedureColumnsRestriction,(TYPE_WSTR) pColumn->bValue); } if(m_restrict & FOURTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR4,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes4) { odtLog << L"VerifyRow_PROCEDURE_COLUMNS:COLUMN NAME 4 restriction failed\n"; m_fRes4=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 5: // COLUMN_GUID case 11:// TYPE_GUID PRVTRACE(L"\n"); break; case 6: // COLUMN PROPID case 7: // ROWSET NUMBER case 8: // ORDINAL POSITION case 12:// CHARACTER_MAXIMUM_LENGTH case 13:// CHARACTER_OCTET_LENGTH PRVTRACE(L"%d\n",*(TYPE_UI4 *)pColumn->bValue); break; case 9:// IS_NULLABLE PRVTRACE(L"%d\n",*(TYPE_BOOL *)pColumn->bValue); break; case 10:// DATA_TYPE case 14:// NUMERIC_PRECISION PRVTRACE(L"%d\n",*(TYPE_UI2 *)pColumn->bValue); break; case 15:// NUMERIC_SCALE PRVTRACE(L"%d\n",*(TYPE_I2 *)pColumn->bValue); break; case 16:// DESCRIPTION PRVTRACE(L"%d\n",(TYPE_WSTR)pColumn->bValue); break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"PROCEDURE COLUMNS: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - PROCEDURE COLUMNS provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } break; } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else { PRVTRACE(L"%s=",m_rgDBCOLUMNINFO[iBind].pwszName); RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // PROCEDURE_PARAMETERS // 1. Procedure Catalog // 2. Procedure Schema // 3. Procedure Name // 4. Parameter Name //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_PROCEDURE_PARAMETERS() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszPROCEDURE_PARAMETERS; m_rgColumnTypes = (DBTYPE *)rgtypePROCEDURE_PARAMETERS; // Set the count of columns and restrictions m_cColumns = cPROCEDURE_PARAMETERS; m_cRestrictions = cPROCEDURE_PARAMETERS_RESTRICTIONS; // Set Procedure Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszProcedureRestriction); SetRestriction(FOURTH,4, &m_wszR4, m_pwszParameterRestriction); PRVTRACE(L"GetSchemaInfo::PROCEDURES\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowPROCEDURE_PARAMETERS // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_PROCEDURE_PARAMETERS(DBCOUNTITEM iRow, BYTE * pData) { ULONG iBind; // Binding Count DATA * pColumn; // Data Structure CCol col; BOOL fResults = TRUE; // don't need to go farther if I have what I'm looking for if(m_fCaptureRestrictions && m_pwszParameterRestriction) return FALSE; // Check the count of columns returned if(iRow == 1) COMPARE(cPROCEDURE_PARAMETERS <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"Row[%lu],Col[%s]:PROCEDURE_PARAMETERS", iRow, m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1:// PROCEDURE CATALOG if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_PROCEDURE_PARAMETERS:PROCEDURE CATALOG restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2:// PROCEDURE SCHEMA if(m_restrict & SECOND) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR2,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes2) { odtLog << L"VerifyRow_PROCEDURE_PARAMETERS:PROCEDURE SCHEMA restriction failed\n"; m_fRes2=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 3: // PROCEDURE_NAME if(m_restrict & THIRD) { if(!COMPARE(0, _wcsnicmp((TYPE_WSTR)m_wszR3,(TYPE_WSTR)pColumn->bValue,wcslen(m_wszR3)))) { if(m_fRes3) { odtLog << L"VerifyRow_PROCEDURE_PARAMETERS:PROCEDURE_NAME restriction failed\n"; m_fRes3=FALSE; fResults = FALSE; } } else { // Check the length of the proc name if( (wcslen(m_wszR3) != wcslen((TYPE_WSTR)pColumn->bValue)) && (!COMPARE(_wcsicmp((TYPE_WSTR)&pColumn->bValue[wcslen(m_wszR3)*sizeof(WCHAR)], L";1")==0,TRUE)) ) { odtLog << L"VerifyRow_PROCEDURE_PARAMETERS:PROCEDURE_NAME length did not match\n"; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 4:// PARAMETER NAME if(m_fCaptureRestrictions) { m_pwszParameterRestriction = (WCHAR *) PROVIDER_ALLOC ((wcslen((WCHAR *) pColumn->bValue)*sizeof(WCHAR)) + sizeof(WCHAR)); if(m_pwszParameterRestriction) wcscpy(m_pwszParameterRestriction,(TYPE_WSTR) pColumn->bValue); } if(m_restrict & FOURTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR4,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes4) { odtLog << L"VerifyRow_PROCEDURE_PARAMETERS:PROCEDURE NAME restriction failed\n"; m_fRes4=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 5: // ORDINAL POSITION case 6: // PARAMETER TYPE case 10:// DATA TYPE PRVTRACE(L"%d\n",*(TYPE_UI2 *)pColumn->bValue); break; case 7: // PARAMETER_HASDEFAULT case 9: // IS NULLABLE if((*(TYPE_BOOL *)pColumn->bValue)==VARIANT_TRUE) PRVTRACE(L"TRUE\n"); else PRVTRACE(L"FALSE\n"); break; case 11:// CHARACTER_MAXIMUM_LENGTH case 12:// CHARACTER_OCTECT_LENGTH PRVTRACE(L"%d\n",*(TYPE_UI4 *)pColumn->bValue); break; case 13:// NUMERIC_PRECISION PRVTRACE(L"%d\n",*(TYPE_UI2 *)pColumn->bValue); break; case 14:// NUMERIC_SCALE PRVTRACE(L"%d\n",*(TYPE_I2 *)pColumn->bValue); break; case 8: // PARAMETER DEFAULT case 15:// DESCRIPTION case 16:// TYPE_NAME case 17:// LOCAL_TYPE_NAME PRVTRACE(L"'%s'\n",(TYPE_WSTR *)pColumn->bValue); break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"PROCEDURE PARAMETERS: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - PROCEDURE PARAMETERS provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } break; } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else { PRVTRACE(L"%s=",m_rgDBCOLUMNINFO[iBind].pwszName); RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // PROCEDURES // 1. Catalog Name // 2. Schema Name // 3. Procedure Name // 4. Procedure Type //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_PROCEDURES() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszPROCEDURES; m_rgColumnTypes = (DBTYPE *)rgtypePROCEDURES; // Set the count of columns and restrictions m_cColumns = cPROCEDURES; m_cRestrictions = cPROCEDURES_RESTRICTIONS; // Set Procedure Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszProcedureRestriction); if((m_currentBitMask & FOURTH) || m_fPassUnsupportedRestrictions) { if((m_restrict & FOURTH)|| (m_restrict & ALLRES)) { if(m_ProcedureTypeRestriction || m_fPassUnsupportedRestrictions) { m_ulR = (m_fPassUnsupportedRestrictions) ? DB_PT_PROCEDURE : m_ProcedureTypeRestriction; m_rgvarRestrict[3].vt = VT_I2; V_I2(&m_rgvarRestrict[3]) = (SHORT)m_ulR; m_cRestrictionsCurrent ++; SetRestriction(FOURTH); RESTRICTNOTSUPPORTED(FOURTH) } } } PRVTRACE(L"GetSchemaInfo::PROCEDURES\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowPROCEDURES // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_PROCEDURES ( DBCOUNTITEM iRow, BYTE * pData ) { ULONG iBind; // Binding Count DATA * pColumn; // Data Structure CCol col; BOOL fResults = TRUE; // don't need to go farther if I have what I'm looking for if(m_fCaptureRestrictions && m_pwszProcedureRestriction && m_ProcedureTypeRestriction) return FALSE; // Check the count of columns returned if(iRow == 1) COMPARE(cPROCEDURES <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"PROCEDURES:Row[%lu],Col[%d.%s]:", // iRow, // m_rgDBCOLUMNINFO[iBind].iOrdinal, // m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1:// PROCEDURE_CATALOG if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_PROCEDURES:PROCEDURE_CATALOG 1 restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2:// PROCEDURE_SCHEMA if(m_restrict & SECOND) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR2,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes2) { odtLog << L"VerifyRow_PROCEDURES:PROCEDURE_SCHEMA 2 restriction failed\n"; m_fRes2=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 3: // PROCEDURE_NAME if(m_fCaptureRestrictions) { m_pwszProcedureRestriction = (WCHAR *) PROVIDER_ALLOC ((wcslen((WCHAR *) pColumn->bValue)*sizeof(WCHAR)) + sizeof(WCHAR)); if(m_pwszProcedureRestriction) wcscpy(m_pwszProcedureRestriction,(TYPE_WSTR) pColumn->bValue); } if(m_restrict & THIRD) { if(!COMPARE(0, _wcsnicmp((TYPE_WSTR)m_wszR3,(TYPE_WSTR)pColumn->bValue,wcslen(m_wszR3)))) { if(m_fRes3) { odtLog << L"VerifyRow_PROCEDURES:PROCEDURE_NAME restriction failed\n"; m_fRes3=FALSE; fResults = FALSE; } } else { // Check the length of the proc name if( (wcslen(m_wszR3) != wcslen((TYPE_WSTR)pColumn->bValue)) && (!COMPARE(_wcsicmp((TYPE_WSTR)&pColumn->bValue[wcslen(m_wszR3)*sizeof(WCHAR)], L";1")==0,TRUE)) ) { odtLog << L"VerifyRow_PROCEDURE_PARAMETERS:PROCEDURE_NAME length did not match\n"; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 4: // PROCEDURE_TYPE if(m_fCaptureRestrictions) m_ProcedureTypeRestriction = *(TYPE_I2 *) pColumn->bValue; if(m_restrict & FOURTH) { if((TYPE_I2) m_ulR != (*(TYPE_I2 *)pColumn->bValue)) { if(m_fRes4) { odtLog << L"VerifyRow_PROCEDURES:DATA_TYPE restriction failed\n"; m_fRes4=FALSE; fResults = FALSE; } } } PRVTRACE(L"%d\n",*(TYPE_I2 *)pColumn->bValue); break; case 5:// PROCEDURE DEFINITION case 6:// DESCRIPTION PRVTRACE(L"%d\n",(TYPE_WSTR)pColumn->bValue); break; // DATE_CREATED // DATE_MODIFIED case 7: case 8: break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"PROCEDURES: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - PROCEDURES provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } break; } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else { RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // PROVIDER_TYPES // 1. Data Type //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_PROVIDER_TYPES() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszPROVIDER_TYPES; m_rgColumnTypes = (DBTYPE *)rgtypePROVIDER_TYPES; // Set the count of columns and restrictions m_cColumns = cPROVIDER_TYPES; m_cRestrictions = cPROVIDER_TYPES_RESTRICTIONS; if((m_currentBitMask & FIRST) || m_fPassUnsupportedRestrictions) { if((m_restrict & FIRST) || (m_restrict & ALLRES)) { if(m_DataTypeRestriction) { m_ulR = m_DataTypeRestriction; m_rgvarRestrict[0].vt = VT_UI2; m_rgvarRestrict[0].iVal = m_DataTypeRestriction; m_cRestrictionsCurrent ++; SetRestriction(FIRST); RESTRICTNOTSUPPORTED(FIRST) } } } if((m_currentBitMask & SECOND) || m_fPassUnsupportedRestrictions) { if((m_restrict & SECOND) || (m_restrict & ALLRES)) { m_fR = (m_BestMatchRestriction==VARIANT_TRUE) ? VARIANT_TRUE : VARIANT_FALSE; m_rgvarRestrict[1].vt = VT_BOOL; m_rgvarRestrict[1].boolVal = (m_BestMatchRestriction==VARIANT_TRUE) ? VARIANT_TRUE : VARIANT_FALSE; m_cRestrictionsCurrent ++; SetRestriction(SECOND); RESTRICTNOTSUPPORTED(SECOND) } } PRVTRACE(L"GetSchemaInfo::PROVIDER_TYPES\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRow_PROVIDER_TYPES // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_PROVIDER_TYPES ( DBCOUNTITEM iRow, BYTE * pData ) { ULONG iBind; // Binding Count DATA * pColumn; // Data Structure CCol col; BOOL fResults = TRUE; // Check the count of columns returned if(iRow == 1) COMPARE(cPROVIDER_TYPES <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"PROVIDER_TYPES:Row[%lu],Col[%d,%s]:", // iRow, // m_rgDBCOLUMNINFO[iBind].iOrdinal, // m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1: // TYPE_NAME case 4: // LITERAL_PREFIX case 5: // LITERAL_SUFFIX case 6: // CREATE PARAMS case 13:// LOCAL_TYPE_NAME case 17:// TYPELIB case 18:// VERSION PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2:// DATA TYPE if(m_restrict & FIRST) { if(m_ulR!= (*(TYPE_UI2 *)pColumn->bValue)) { if(m_fRes1) { odtLog << L"VerifyRow_PROVIDER_TYPES:TYPE NAME restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } PRVTRACE(L"%d\n",*(TYPE_UI2 *)pColumn->bValue); break; case 3: // COLUMN SIZE case 9: // SEARCHABLE PRVTRACE(L"%d\n",*(TYPE_UI4 *)pColumn->bValue); break; case 7: // IS_NULLABLE case 8: // CASE_SENSITIVE case 10:// UNSIGNED_ATTRIBUTE case 11:// FIXED PREC SCALE case 12:// AUTO_UNIQUE_VALUE case 19:// IS_LONG case 21:// IS_FIXEDLENGTH if((*(TYPE_BOOL *)pColumn->bValue)==VARIANT_TRUE) PRVTRACE(L"TRUE\n"); else PRVTRACE(L"FALSE\n"); break; case 14:// MINIMUM_SCALE case 15: // MAXIMUM_SCALE PRVTRACE(L"%d\n",*(TYPE_I2 *)pColumn->bValue); break; case 20: // BEST_MATCH if(m_fCaptureRestrictions) m_BestMatchRestriction = *(TYPE_BOOL *) pColumn->bValue; if(m_restrict & SECOND) { if(m_fR != (*(TYPE_BOOL *)pColumn->bValue)) { odtLog << L"VerifyRow_PROVIDER_TYPES:BEST_MATCH restriction failed\n"; fResults = FALSE; } } if((*(TYPE_BOOL *)pColumn->bValue)==VARIANT_TRUE) PRVTRACE(L"TRUE\n"); else PRVTRACE(L"FALSE\n"); break; case 16:// GUID PRVTRACE(L"\n"); break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"PROVIDER TYPES: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - PROVIDER TYPES provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } break; } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else { RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // REFERENTIAL_CONSTRAINTS // 1. Constraint Catalog // 2. Constraint Schema // 3. Constraint Name //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_REFERENTIAL_CONSTRAINTS() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszREFERENTIAL_CONSTRAINTS; m_rgColumnTypes = (DBTYPE *)rgtypeREFERENTIAL_CONSTRAINTS; // Set the count of columns and restrictions m_cColumns = cREFERENTIAL_CONSTRAINTS; m_cRestrictions = cREFERENTIAL_CONSTRAINTS_RESTRICTIONS; // Set Constraint Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszReferential_ConstraintRestriction); PRVTRACE(L"GetSchemaInfo::REFERENTIAL_CONSTRAINTS\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowREFERENTIAL_CONSTRAINTS // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_REFERENTIAL_CONSTRAINTS ( DBCOUNTITEM iRow, BYTE * pData ) { ULONG iBind; // Binding Count DATA * pColumn; // Data Structure CCol col; BOOL fResults = TRUE; // don't need to go farther if I have what I'm looking for if(m_fCaptureRestrictions && m_pwszReferential_ConstraintRestriction) return FALSE; // Check the count of columns returned if(iRow == 1) COMPARE(cREFERENTIAL_CONSTRAINTS <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"REFERENTIAL_CONSTRAINTS:Row[%lu],Col[%d,%s]:", // iRow, // m_rgDBCOLUMNINFO[iBind].iOrdinal, // m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { // TODO: not currently supported switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1: // CONSTRAINT_CATALOG if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_REFERENTIAL_CONSTRAINTS:CONSTRAINT_CATALOG restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2: // CONSTRAINT_SCHEMA if(m_restrict & SECOND) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR2,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes2) { odtLog << L"VerifyRow_REFERENTIAL_CONSTRAINTS:CONSTRAINT_SCHEMA restriction failed\n"; m_fRes2=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 3: // CONSTRAINT_NAME if(m_fCaptureRestrictions) { m_pwszReferential_ConstraintRestriction = (WCHAR *) PROVIDER_ALLOC ((wcslen((WCHAR *) pColumn->bValue)*sizeof(WCHAR *)) + sizeof(WCHAR)); if(m_pwszReferential_ConstraintRestriction) wcscpy(m_pwszReferential_ConstraintRestriction,(TYPE_WSTR) pColumn->bValue); } if(m_restrict & THIRD) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR3,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes3) { odtLog << L"VerifyRow_REFERENTIAL_CONSTRAINTS:CONSTRAINT_NAME restriction failed\n"; m_fRes3=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 4: // UNIQUE_CONSTRAINT_CATALOG case 5: // UNIQUE_CONSTRAINT_SCHEMA case 6: // UNIQUE_CONSTRAINT_NAME case 10: // DESCRIPTION PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 7: // MATCH_OPTION if( (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"NONE")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"PARTIAL"))&& (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"FULL"))) { odtLog << L"VerifyRow_REFERENTIAL_CONSTRAINTS:MATCH OPTION expected NONE/PARTIAL/FULL but recieved " << (TYPE_WSTR)pColumn->bValue << ENDL; fResults = FALSE; } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 8: // UPDATE_RULE case 9: // DELETE_RULL if( (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"CASCASE")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"SET NULL")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"SET DEFAULT"))&& (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"NO ACTION"))) { odtLog << L"VerifyRow_REFERENTIAL_CONSTRAINTS:UPDATE/DELETE RULE expected SELECT,DELETE,INSERT,UPDATE, or REFERENCES but recieved " << (TYPE_WSTR)pColumn->bValue << ENDL; fResults = FALSE; } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"REFERENTIAL CONSTRAINTS: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - REFERENTIAL CONSTRAINTS provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } break; } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else { RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // SCHEMATA // 1. Catalog Name // 2. Schema Name // 3. Schema Owner //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_SCHEMATA() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszSCHEMATA; m_rgColumnTypes = (DBTYPE *)rgtypeSCHEMATA; // Set the count of columns and restrictions m_cColumns = cSCHEMATA; m_cRestrictions = cSCHEMATA_RESTRICTIONS; // Set Schema Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszSchemaRestriction); PRVTRACE(L"GetSchemaInfo::SCHEMATA\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowSCHEMATA // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_SCHEMATA ( DBCOUNTITEM iRow, BYTE * pData ) { ULONG iBind; // Binding Count DATA * pColumn; // Data Structure CCol col; BOOL fResults = TRUE; // Check the count of columns returned if(iRow == 1) COMPARE(cSCHEMATA <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn=(DATA *)(pData + m_rgDBBINDING[iBind].obStatus); if(pColumn->sStatus == DBSTATUS_S_OK) { switch(m_rgDBBINDING[iBind].iOrdinal) { case 1:// CATALOG_NAME if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_SCHEMATA:CATALOG_NAME restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2:// SCHEMA_NAME if(m_restrict & SECOND) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR2,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes2) { odtLog << L"VerifyRow_SCHEMATA:SCHEMA_NAME restriction failed\n"; m_fRes2=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 3: // SCHEMA_OWNER if(m_restrict & THIRD) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR3,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes3) { odtLog << L"VerifyRow_SCHEMATA:SCHEMA_OWNER restriction failed\n"; m_fRes3=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 4: // DEFAULT_CHARACTER_SET_CATALOG case 5: // DEFAULT_CHARACTER_SET_SCHEMA case 6: // DEFAULT_CHARACTER_SET_NAME break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"SCHEMATA: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - SCHEMATA provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } break; } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else { PRVTRACE(L"%s=",m_rgDBCOLUMNINFO[iBind].pwszName); RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // SQL_LANGUAGES // No Constraints //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_SQL_LANGUAGES() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszSQL_LANGUAGES; m_rgColumnTypes = (DBTYPE *)rgtypeSQL_LANGUAGES; // Set the count of columns and restrictions m_cColumns = cSQL_LANGUAGES; m_cRestrictions = cSQL_LANGUAGES_RESTRICTIONS; m_cRestrictionsCurrent = 0; PRVTRACE(L"GetSchemaInfo::SQL_LANGUAGES\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowSQL_LANGUAGES // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_SQL_LANGUAGES ( DBCOUNTITEM iRow, BYTE * pData ) { ULONG iBind; // Binding Count DATA * pColumn; // Data Structure CCol col; BOOL fResults = TRUE; // Check the count of columns returned if(iRow == 1) COMPARE(cSQL_LANGUAGES <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"Row[%lu],Col[%s]:VerifyRow_SQL_LANGUAGES:", iRow,m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(iBind) { case 1: // SQL LANGUAGE SOURCE if(0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"ISO 9075")) { odtLog << L"VerifyRow_SQL_LANGUAGES:SQL_LANGUAGE_SOURCE expected ISO 9075 but recieved " << (TYPE_WSTR)pColumn->bValue << ENDL; fResults = FALSE; } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2: // SQL LANGUAGE YEAR if(0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"ISO 9075")) { odtLog << L"VerifyRow_SQL_LANGUAGES:SQL_LANGUAGE_YEAR expected 1992 but recieved " << (TYPE_WSTR)pColumn->bValue << ENDL; fResults = FALSE; } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 3: // SQL LANGUAGE CONFORMANCE if( (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"ENTRY")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"INTERMEDIATE")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"FULL"))) { odtLog << L"VerifyRow_REFERENTIAL_CONSTRAINTS:SQL_LANGUAGE_CONFORMANCE expected ENTRY/INTERMEDIATE/FULL but recieved " << (TYPE_WSTR)pColumn->bValue << ENDL; fResults = FALSE; } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 4: // SQL LANGUAGE INTEGRITY if( (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"YES")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"NO"))) { odtLog << L"VerifyRow_REFERENTIAL_CONSTRAINTS:SQL_LANGUAGE_INTEGRITY expected YES/NO but recieved " << (TYPE_WSTR)pColumn->bValue << ENDL; fResults = FALSE; } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 5: // SQL LANGUAGE IMPLEMENTATION, should be null if SQL_LANGUAGE_SOURCE is 'ISO_9075' case 6: // SQL LANGUAGE BINDING SYTLE case 7: // SQL LANGUAGE PROGRAMMING LANGUAGE PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; default: PRVTRACE(L"%s not expected\n",m_rgDBCOLUMNINFO[iBind].pwszName); break; } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else { PRVTRACE(L"%s=",m_rgDBCOLUMNINFO[iBind].pwszName); RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // STATISTICS // 1. Catalog Name // 2. Schema Name // 3. Table Name //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_STATISTICS() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszSTATISTICS; m_rgColumnTypes = (DBTYPE *)rgtypeSTATISTICS; // Set the count of columns and restrictions m_cColumns = cSTATISTICS; m_cRestrictions = cSTATISTICS_RESTRICTIONS; // Set Table Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszTableRestriction); PRVTRACE(L"GetSchemaInfo::STATISTICS\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowSTATISTICS // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_STATISTICS ( DBCOUNTITEM iRow, BYTE * pData ) { ULONG iBind; // Binding Count DATA * pColumn; // Data Structure CCol col; BOOL fResults = TRUE; // Check the count of columns returned if(iRow == 1) COMPARE(cSTATISTICS <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"Row[%lu],Col[%s]:STATISTICS:", iRow, m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1:// TABLE CATALOG if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_STATISTICS:TABLE_CATALOG restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2:// TABLE SCHEMA if(m_restrict & SECOND) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR2,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes2) { odtLog << L"VerifyRow_STATISTICS:TABLE_SCHEMA restriction failed\n"; m_fRes2=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 3: //TABLE NAME if(m_restrict & THIRD) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR3,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes3) { odtLog << L"VerifyRow_STATISTICS:TABLE_NAME restriction failed\n"; m_fRes3=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 4: // CARDINALITY PRVTRACE(L"%d\n",*(TYPE_I4 *)pColumn->bValue); break; default: PRVTRACE(L"%s not expected\n",m_rgDBCOLUMNINFO[iBind].pwszName); break; } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else { PRVTRACE(L"%s=",m_rgDBCOLUMNINFO[iBind].pwszName); RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // TABLE_CONSTRAINTS // 1. Constraint Catalog // 2. Constraint Schema // 3. Constraint Name // 4. Table Catalog // 5. Table Schema // 6. Table Name // 7. Constraint Type //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_TABLE_CONSTRAINTS() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszTABLE_CONSTRAINTS; m_rgColumnTypes = (DBTYPE *)rgtypeTABLE_CONSTRAINTS; // Set the count of columns and restrictions m_cColumns = cTABLE_CONSTRAINTS; m_cRestrictions = cTABLE_CONSTRAINTS_RESTRICTIONS; // Set Constraint Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszTable_ConstraintRestriction); SetRestriction(FOURTH,4, &m_wszR4, m_pwszCatalogRestriction); SetRestriction(FIFTH, 5, &m_wszR5, m_pwszSchemaRestriction); SetRestriction(SIXTH, 6, &m_wszR6, m_pwszTableRestriction); SetRestriction(THIRD, 7, &m_wszR7, m_pwszConstraint_TypeRestriction); PRVTRACE(L"GetSchemaInfo::TABLE_CONSTRAINTS\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowTABLE_CONSTRAINTS // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_TABLE_CONSTRAINTS ( DBCOUNTITEM iRow, BYTE * pData ) { ULONG iBind; // Binding Count DATA * pColumn; // Data Structure CCol col; BOOL fResults = TRUE; // don't need to go farther if I have what I'm looking for if(m_fCaptureRestrictions && m_pwszTable_ConstraintRestriction && m_pwszConstraint_TypeRestriction) return FALSE; // Check the count of columns returned if(iRow == 1) COMPARE(cTABLE_CONSTRAINTS <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"Row[%lu],Col[%s]:TABLE_CONSTRAINTS:", iRow, m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1://CONSTRAINT CATALOG if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_TABLE_CONSTRAINTS:CONSTRAINT CATALOG restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2:// CONSTRAINT SCHEMA if(m_restrict & SECOND) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR2,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes2) { odtLog << L"VerifyRow_TABLE_CONSTRAINTS:CONSTRAINT SCHEMA restriction failed\n"; m_fRes2=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 3: // CONSTRAINT NAME if(m_fCaptureRestrictions) { m_pwszTable_ConstraintRestriction = (WCHAR *) PROVIDER_ALLOC ((wcslen((WCHAR *) pColumn->bValue)*sizeof(WCHAR)) + sizeof(WCHAR)); if(m_pwszTable_ConstraintRestriction) wcscpy(m_pwszTable_ConstraintRestriction,(TYPE_WSTR) pColumn->bValue); } if(m_restrict & THIRD) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR3,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes3) { odtLog << L"VerifyRow_TABLE_CONSTRAINTS:CONSTRAINT NAME restriction failed\n"; m_fRes3=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 4:// TABLE CATALOG if(m_restrict & FOURTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR4,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes4) { odtLog << L"VerifyRow_TABLE_CONSTRAINTS:TABLE CATALOG restriction failed\n"; m_fRes4=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 5:// TABLE SCHEMA if(m_restrict & FIFTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR5,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes5) { odtLog << L"VerifyRow_TABLE_CONSTRAINTS:TABLE SCHEMA restriction failed\n"; m_fRes5=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 6: // TABLE NAME if(m_restrict & SIXTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR6,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes6) { odtLog << L"VerifyRow_TABLE_CONSTRAINTS:CONSTRAINT NAME restriction failed\n"; m_fRes6=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(WCHAR *)pColumn->bValue); break; case 7: // CONSTRAINT TYPE if(m_fCaptureRestrictions) { m_pwszConstraint_TypeRestriction = (WCHAR *) PROVIDER_ALLOC((wcslen((WCHAR *) pColumn->bValue)*sizeof(WCHAR)) + sizeof(WCHAR)); if(m_pwszConstraint_TypeRestriction) wcscpy(m_pwszConstraint_TypeRestriction,(WCHAR *) pColumn->bValue); } if(m_restrict & SEVENTH) { if(!COMPARE(0, _wcsicmp((WCHAR* )m_wszR7,(const WCHAR *)pColumn->bValue))) { if(m_fRes7) { odtLog << L"VerifyRow_TABLE_CONSTRAINTS:CONSTRAINT NAME restriction failed\n"; m_fRes7=FALSE; fResults = FALSE; } } } if( (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"UNIQUE")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"PRIMARY KEY")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"FOREIGN KEY"))&& (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"CHECK"))) { odtLog << L"VerifyRow_TABLE_CONSTRAINTS:CONSTRAINT TYPE expected UNIQUE/PRIMARYKEY/FOREIGNKEY/CHECK but recieved " << (TYPE_WSTR)pColumn->bValue << ENDL; fResults = FALSE; } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 8: // IS_DEFERRABLE case 9: // INITIALLY_DEFERRED if(*(TYPE_BOOL *)pColumn->bValue==VARIANT_TRUE) PRVTRACE(L"TRUE\n"); else PRVTRACE(L"FALSE\n"); break; case 10: // DESCRIPTION PRVTRACE(L"%d\n",(TYPE_WSTR *)pColumn->bValue); break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"TABLE CONSTRAINTS: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - TABLE CONSTRAINTS provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } break; } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else { PRVTRACE(L"%s=",m_rgDBCOLUMNINFO[iBind].pwszName); RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // TABLE_PRIVILEGES // 1. Catalog Name // 2. Schema Name // 3. Table Name // 4. Grantor // 5. Grantee //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_TABLE_PRIVILEGES() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszTABLE_PRIVILEGES; m_rgColumnTypes = (DBTYPE *)rgtypeTABLE_PRIVILEGES; // Set the count of columns and restrictions m_cColumns = cTABLE_PRIVILEGES; m_cRestrictions = cTABLE_PRIVILEGES_RESTRICTIONS; // Set Table Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszTableRestriction); SetRestriction(FOURTH,4, &m_wszR4, m_pwszGrantorRestriction); SetRestriction(FIFTH, 5, &m_wszR5, m_pwszGranteeRestriction); PRVTRACE(L"GetSchemaInfo::TABLE_PRIVILEGES\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowTABLE_PRIVILEGES // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_TABLE_PRIVILEGES ( DBCOUNTITEM iRow, BYTE * pData ) { ULONG iBind; // Binding Count DATA * pColumn; // Data Structure CCol col; BOOL fResults = TRUE; // Check the count of columns returned if(iRow == 1) COMPARE(cTABLE_PRIVILEGES <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"Row[%lu],Col[%s]:TABLE_PRIVILEGES:", iRow, m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1://GRANTOR if(m_restrict & FOURTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR4,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes4) { odtLog << L"VerifyRow_TABLE_PRIVILEGES:GRANTOR restriction failed\n"; m_fRes4=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(WCHAR *)pColumn->bValue); break; case 2:// GRANTEE if(m_restrict & FIFTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR5,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes5) { odtLog << L"VerifyRow_TABLE_PRIVILEGES:GRANTEE restriction failed\n"; m_fRes5=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 3: // TABLE CATALOG if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_TABLE_PRIVILEGES:TABLE CATALOG restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 4:// TABLE SCHEMA if(m_restrict & SECOND) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR2,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes2) { odtLog << L"VerifyRow_TABLE_PRIVILEGES:TABLE SCHEMA restriction failed\n"; m_fRes2=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 5:// TABLE NAME if(m_restrict & THIRD) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR3,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes3) { odtLog << L"VerifyRow_TABLE_PRIVILEGES:TABLE NAME restriction failed\n"; m_fRes3=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 6: // PRIVILEGE TYPE if( (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"SELECT")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"INSERT")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"DELETE")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"REFERENCES")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"UPDATE"))) { odtLog << L"VerifyRow_TABLE_PRIVILEGES:PRIVILEGE TYPE expected SELECT/INSERT/DELETE/REFERENCES/UPDATE but recieved " << (TYPE_WSTR)pColumn->bValue << ENDL; fResults = FALSE; } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 7: // IS_GRANTABLE if(*(TYPE_BOOL *)pColumn->bValue==VARIANT_TRUE) PRVTRACE(L"TRUE\n"); else PRVTRACE(L"FALSE\n"); break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"TABLE PRIVILEGES: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - TABLE PRIVILEGES provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } break; } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else { PRVTRACE(L"%s=",m_rgDBCOLUMNINFO[iBind].pwszName); RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // TABLE_STATISTICS // 1. Catalog Name // 2. Schema Name // 3. Table Name //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_TABLE_STATISTICS() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszTABLESTATISTICS; m_rgColumnTypes = (DBTYPE *)rgtypeTABLESTATISTICS; // Set the count of columns and restrictions m_cColumns = cTABLE_STATISTICS; m_cRestrictions = cTABLE_STATISTICS_RESTRICTIONS; // Set Table Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszTableRestriction); SetRestriction(FOURTH,4, &m_wszR4, m_pwszStatisticsCatalogRestriction); SetRestriction(FIFTH, 5, &m_wszR5, m_pwszStatisticsSchemaRestriction); SetRestriction(SIXTH, 6, &m_wszR6, m_pwszStatisticsNameRestriction); // Seventh restriction if((m_currentBitMask & SEVENTH) || m_fPassUnsupportedRestrictions) { if((m_restrict & SEVENTH)|| (m_restrict & ALLRES)) { m_ulR = m_uiStatisticsTypeRestriction; V_VT(&m_rgvarRestrict[6]) = VT_UI2; V_UI2(&m_rgvarRestrict[6]) = m_uiStatisticsTypeRestriction; m_cRestrictionsCurrent ++; SetRestriction(SEVENTH); RESTRICTNOTSUPPORTED(SEVENTH) } } PRVTRACE(L"GetSchemaInfo::TABLE_STATISTICS\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowTABLE_STATISTICS // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_TABLE_STATISTICS ( DBCOUNTITEM iRow, BYTE * pData ) { ULONG iBind; // Binding Count DATA * pColumn; // Data Structure CCol col; BOOL fResults = TRUE; HRESULT hrOpenTable = E_FAIL; LPWSTR pwszTableName = (LPWSTR)GetValuePtr(TS_TABLE_NAME, pData); LPWSTR pwszStatName = (LPWSTR)GetValuePtr(TS_STATISTICS_NAME, pData); LPWSTR pwszColumnName = (LPWSTR)GetValuePtr(TS_COLUMN_NAME, pData); ULONG * pulTableCardinality = (ULONG *)GetValuePtr(TS_TABLE_CARDINALITY, pData); ULONG * pulOrdinal = (ULONG *)GetValuePtr(TS_ORDINAL_POSITION, pData); ULONG ulStatType = 0; ULONG ulIndex = 0; DBID dbidTable = DB_NULLID; BOOL fNewTable = (!m_pwszTableName || !pwszTableName || (pwszTableName && RelCompareString(pwszTableName, m_pwszTableName))); BOOL fNewStat = fNewTable | (!m_pwszStatName || !pwszStatName || (pwszStatName && RelCompareString(pwszStatName, m_pwszStatName))); CARDINALITY eCardinality = TUPLE_CARDINALITY; LPWSTR pwszCat = (LPWSTR)GetValuePtr(TS_TABLE_CATALOG, pData); LPWSTR pwszSch = (LPWSTR)GetValuePtr(TS_TABLE_SCHEMA, pData); LPWSTR pwszQualifiedName = NULL; TESTC_(m_pTable->GetQualifiedName(pwszCat, pwszSch, pwszTableName,&pwszQualifiedName, TRUE), S_OK); // ********************************************************************* // For current time, set this on for debugging test code. // ********************************************************************* m_fDetailCheck = TRUE; if (m_fDetailCheck) { ULONG * pulStatType = (ULONG *)GetValuePtr(TS_STATISTICS_TYPE, pData); // Attempt to open table and get columns info if (fNewTable) { hrOpenTable = GetColumnInfo(pData, m_rgDBBINDING); // Should be S_OK, or perhaps DB_E_NOTABLE if (DB_E_NOTABLE != hrOpenTable) CHECK(hrOpenTable, S_OK); else // We warn here because it's possible the table name is // bogus, or just deleted. CHECKW(hrOpenTable, S_OK); } else // If we obtained col info for the table we successfully opened it. hrOpenTable = (m_prgColInfo) ? S_OK : E_FAIL; #ifdef BASE_TABLE_ORDINALS // Set index into columns info given ordinal if (m_prgColInfo && pulOrdinal) ulIndex = *pulOrdinal-1+!m_prgColInfo[0].iOrdinal; #else // Set index into columns info given column name if (m_prgColInfo && pwszColumnName) { for (ulIndex = 0; ulIndex < m_cColInfo; ulIndex++) { if (!wcscmp(m_prgColInfo[ulIndex].pwszName, pwszColumnName)) break; } } #endif // Set up table dbid dbidTable.eKind = DBKIND_NAME; dbidTable.uName.pwszName = pwszTableName; // Get statistic type if (pulStatType) ulStatType = *pulStatType; } // Only capture restrictions once. Note we assume catalog and schema // may not be supported but that statistics name will be if(m_fCaptureRestrictions && m_pwszStatisticsNameRestriction) { m_fCaptureRestrictions = FALSE; return FALSE; } // Check the count of columns returned if(iRow == 1) COMPARE(cTABLE_STATISTICS <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"Row[%lu],Col[%s]:TABLE_STATISTICS:", iRow, m_rgDBCOLUMNINFO[iBind].pwszName); // Set cardinality eCardinality = TUPLE_CARDINALITY; if(pColumn->sStatus==DBSTATUS_S_OK || pColumn->sStatus==DBSTATUS_S_ISNULL) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case TS_TABLE_CATALOG: if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_TABLE_STATISTICS:TABLE_CATALOG restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } // Column must have non-empty string if (pColumn->sStatus == DBSTATUS_S_OK) COMPARE(wcslen((TYPE_WSTR)pColumn->bValue) > 0, TRUE); PRVTRACE(L"'%s'\n",(WCHAR *)pColumn->bValue); break; case TS_TABLE_SCHEMA: if(m_restrict & SECOND) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR2,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes2) { odtLog << L"VerifyRow_TABLE_STATISTICS:TABLE_SCHEMA restriction failed\n"; m_fRes2=FALSE; fResults = FALSE; } } } // Column must have non-empty string if (pColumn->sStatus == DBSTATUS_S_OK) COMPARE(wcslen((TYPE_WSTR)pColumn->bValue) > 0, TRUE); PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case TS_TABLE_NAME: if(m_restrict & THIRD) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR3,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes3) { odtLog << L"VerifyRow_TABLE_STATISTICS:TABLE NAME restriction failed\n"; m_fRes3=FALSE; fResults = FALSE; } } } // Column must have non-empty, non-null string if (COMPARE(pColumn->sStatus, DBSTATUS_S_OK)) COMPARE(wcslen((TYPE_WSTR)pColumn->bValue) > 0, TRUE); PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case TS_STATISTICS_CATALOG: if(m_restrict & FOURTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR4,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes4) { odtLog << L"VerifyRow_TABLE_STATISTICS:STATISTICS_CATALOG restriction failed\n"; m_fRes4=FALSE; fResults = FALSE; } } } if(m_fCaptureRestrictions) { m_pwszStatisticsCatalogRestriction = (WCHAR *) PROVIDER_ALLOC((wcslen((WCHAR *) pColumn->bValue)*sizeof(WCHAR)) + sizeof(WCHAR)); if(m_pwszStatisticsCatalogRestriction) wcscpy(m_pwszStatisticsCatalogRestriction,(TYPE_WSTR) pColumn->bValue); } // Column must have non-empty string if (pColumn->sStatus == DBSTATUS_S_OK) COMPARE(wcslen((TYPE_WSTR)pColumn->bValue) > 0, TRUE); PRVTRACE(L"'%s'\n",(WCHAR *)pColumn->bValue); break; case TS_STATISTICS_SCHEMA: if(m_restrict & FIFTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR5,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes5) { odtLog << L"VerifyRow_TABLE_STATISTICS:STATISTICS_SCHEMA restriction failed\n"; m_fRes5=FALSE; fResults = FALSE; } } } if(m_fCaptureRestrictions) { m_pwszStatisticsSchemaRestriction = (WCHAR *) PROVIDER_ALLOC((wcslen((WCHAR *) pColumn->bValue)*sizeof(WCHAR)) + sizeof(WCHAR)); if(m_pwszStatisticsSchemaRestriction) wcscpy(m_pwszStatisticsSchemaRestriction,(TYPE_WSTR) pColumn->bValue); } // Column must have non-empty string if (pColumn->sStatus == DBSTATUS_S_OK) COMPARE(wcslen((TYPE_WSTR)pColumn->bValue) > 0, TRUE); PRVTRACE(L"'%s'\n",(WCHAR *)pColumn->bValue); break; case TS_STATISTICS_NAME: if(m_restrict & SIXTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR6,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes6) { odtLog << L"VerifyRow_TABLE_STATISTICS:STATISTICS_NAME restriction failed\n"; m_fRes6=FALSE; fResults = FALSE; } } } if(m_fCaptureRestrictions) { m_pwszStatisticsNameRestriction = (WCHAR *) PROVIDER_ALLOC((wcslen((WCHAR *) pColumn->bValue)*sizeof(WCHAR)) + sizeof(WCHAR)); if(m_pwszStatisticsNameRestriction) wcscpy(m_pwszStatisticsNameRestriction,(TYPE_WSTR) pColumn->bValue); } // Column must have non-empty string and cannot be NULL if (COMPARE(pColumn->sStatus, DBSTATUS_S_OK)) COMPARE(wcslen((TYPE_WSTR)pColumn->bValue) > 0, TRUE); PRVTRACE(L"'%s'\n",(WCHAR *)pColumn->bValue); break; case TS_STATISTICS_TYPE: { TYPE_UI2 ulStatType = 0; // Column cannot be NULL if (COMPARE(pColumn->sStatus, DBSTATUS_S_OK)) { ulStatType = *(TYPE_UI2 *)pColumn->bValue; if(m_restrict & SEVENTH) { if(!COMPARE(m_uiStatisticsTypeRestriction, ulStatType)) { if(m_fRes7) { odtLog << L"VerifyRow_TABLE_STATISTICS:STATISTICS_TYPE restriction failed\n"; m_fRes7=FALSE; fResults = FALSE; } } } if(m_fCaptureRestrictions) { m_uiStatisticsTypeRestriction = ulStatType; // Avoid posting failures when just capturing restrictions continue; } // Make sure no other bits are set than those spec'd COMPARE(0, ulStatType & (~(DBSTAT_HISTOGRAM | DBSTAT_COLUMN_CARDINALITY | DBSTAT_TUPLE_CARDINALITY))); // If we claim histogram support then NO_OF_RANGES cannot be null // but may be 0 if the table is empty. if (ulStatType & DBSTAT_HISTOGRAM) COMPARE(GetValuePtr(TS_NO_OF_RANGES, pData) != NULL, TRUE); else { CCOMPARE(m_EC, GetValuePtr(TS_NO_OF_RANGES, pData) == NULL, EC_NULL_RANGE_COUNT, L"DBSTAT_HISTOGRAM not set but NO_OF_RANGES is non-NULL", FALSE); } // If we claim column cardinality support then it must not be null if (ulStatType & DBSTAT_COLUMN_CARDINALITY) { COMPARE(GetValuePtr(TS_COLUMN_CARDINALITY, pData) != NULL, TRUE); } else COMPARE(GetValuePtr(TS_COLUMN_CARDINALITY, pData) == NULL, TRUE); // If we claim tuple cardinality support then not be null if (ulStatType & DBSTAT_TUPLE_CARDINALITY) { COMPARE(GetValuePtr(TS_TUPLE_CARDINALITY, pData) != NULL, TRUE); } else COMPARE(GetValuePtr(TS_TUPLE_CARDINALITY, pData) == NULL, TRUE); // DetailCheckStatType(ulStatType, pData); // Detail check if (m_fDetailCheck) { IRowset * pIRowset = NULL; DBID dbidStat; LPWSTR pwszStatName = (LPWSTR)GetValuePtr(TS_STATISTICS_NAME, pData); HRESULT hrOpenHistogram = E_FAIL; dbidStat.eKind = DBKIND_GUID_NAME; dbidStat.uName.pwszName = pwszStatName; dbidStat.uGuid.guid = g_guidHistogramRowset; // Attempt to open histogram rowset hrOpenHistogram = m_pIOpenRowset->OpenRowset(NULL, &dbidTable, &dbidStat, IID_IRowset, 0, NULL, (IUnknown **)&pIRowset); // If there's a histogram then validate values if (ulStatType & DBSTAT_HISTOGRAM) { // Histograms are only supported on first column // of a multicolumn statistic. if (pulOrdinal && *pulOrdinal == 1) { ULONG * pcRanges = (ULONG *)GetValuePtr(TS_NO_OF_RANGES, pData); // It's possible the table was deleted after we opened // the schema rowset if (S_OK == hrOpenHistogram) { if (CHECK(pIRowset != NULL, TRUE)) { HRESULT hrGetNextRows = S_OK; ULONG cRows = 0; HROW * phRows = NULL; DBCOUNTITEM cRowsObtained = 0; DBORDINAL cBinding = 0; DBLENGTH cbRowSize = 0; DBBINDING * pBinding = NULL; HACCESSOR hAccessor = DB_NULL_HACCESSOR; LPBYTE pDataRows = NULL; // Check histogram rowset columns info if (m_prgColInfo && !COMPARE(CheckHistogramColInfo( pIRowset, m_prgColInfo[ulIndex].wType, &cBinding, &pBinding, &cbRowSize, &hAccessor ), TRUE)) odtLog << L"Histogram colinfo doesn't match.\n"; // Make sure the provider returned valid info if (cBinding > 0 && pBinding && cbRowSize > 0 && hAccessor != DB_NULL_HACCESSOR) { LPBYTE pDataHist = NULL; DBBINDING dbBind; DBCOUNTITEM ulRangeCount = 0; DBCOUNTITEM ulTotal = 0; // We need the table cardinality so if not available // we must compute ourselves if (pulTableCardinality) ulTotal = *pulTableCardinality; else ulTotal = Cardinality(pwszQualifiedName, 0, TABLE_CARDINALITY); // Create a binding structure for the other row // data memcpy(&dbBind, pBinding, sizeof(DBBINDING)); dbBind.obStatus+=cbRowSize; dbBind.obLength+=cbRowSize; dbBind.obValue+=cbRowSize; // Allocate memory for two rows of histogram SAFE_ALLOC(pDataRows, BYTE, cbRowSize*2); pDataHist = pDataRows; while ((hrGetNextRows = pIRowset->GetNextRows( NULL, 0, 1, &cRowsObtained, &phRows)) == S_OK) { cRows++; if (COMPARE(cRowsObtained, 1) && COMPARE(phRows != NULL, TRUE) && CHECK(pIRowset->GetData(phRows[0], hAccessor, pDataHist), S_OK)) { LPBYTE pRANGE_HI_KEY = GetValuePtr(HR_RANGE_HI_KEY, pDataHist, pBinding); TYPE_R8 * pRANGE_ROWS = (TYPE_R8 *)GetValuePtr(HR_RANGE_ROWS, pDataHist, pBinding); TYPE_R8 * pEQ_ROWS = (TYPE_R8 *)GetValuePtr(HR_EQ_ROWS, pDataHist, pBinding); TYPE_I8 * pDISTINCT_RANGE_ROWS = (TYPE_I8 *)GetValuePtr(HR_DISTINCT_RANGE_ROWS, pDataHist, pBinding); DBBINDING * pPrevBind=NULL; DBBINDING * pCurrentBind = pBinding; double fFraction, fPercent; // Set pointers to previous and current bindings for RANGE_HIGH_KEY if (cRows > 1) { if (pDataHist == pDataRows) { pCurrentBind = pBinding; pPrevBind = &dbBind; } else { pCurrentBind = &dbBind; pPrevBind = pBinding; } } // Validate this row // RANGE_HI_KEY is mandatory COMPARE(pRANGE_HI_KEY != NULL, TRUE); // One of RANGE_ROWS or EQ_ROWS is required COMPARE(pRANGE_ROWS != NULL || pEQ_ROWS != NULL, TRUE); // Validate sort is by RANGE_HI_KEY, ascending order // Validate data for each returned column // RANGE_HI_KEY /* Actually, this may not necessarily be a value in the column It may not even be within the range of values in the table, so we really can't test this. // Must be a value in the column if (pRANGE_HI_KEY) { ulRangeCount = Cardinality(pwszQualifiedName, ulIndex, EQ_ROWS_CARDINALITY, NULL, pCurrentBind, pDataRows, cbRowSize*2); // Fail if no value in table == RANGE_HIGH_KEY if (!COMPARE(ulRangeCount > 0, TRUE)) odtLog << pwszTableName << L": RANGE_HI_KEY not in base table.\n"; } */ // RANGE_ROWS // Fraction of number of rows that fall in this histogram // range. Select rows in this range and // divide by table cardinality. if (pRANGE_ROWS) { ulRangeCount = Cardinality(pwszQualifiedName, ulIndex, RANGE_ROWS_CARDINALITY, pPrevBind, pCurrentBind, pDataRows, cbRowSize*2); fFraction = (float)(DB_LORDINAL)ulRangeCount/(float)(DB_LORDINAL)ulTotal; // Compute percentage error in result, avoid division by 0 if (fFraction > 0.0) fPercent = fabs((*(double *)pRANGE_ROWS - fFraction)/fFraction); else fPercent = 0.0; // Fail if off by more than 10% CCOMPARE(m_EC, fPercent < MAX_STATISTIC_ERROR, EC_BAD_RANGE_ROWS, L"RANGE_ROWS not within 10%", FALSE); } // EQ_ROWS // Fraction of rows equal to RANGE_HIGH_KEY. // Select rows equal and divide by table cardinality. if (pEQ_ROWS) { ulRangeCount = Cardinality(pwszQualifiedName, ulIndex, EQ_ROWS_CARDINALITY, NULL, pCurrentBind, pDataRows, cbRowSize*2); fFraction = (float)(DB_LORDINAL)ulRangeCount/(float)(DB_LORDINAL)ulTotal; // Compute percentage error in result, avoid division by 0 if (fFraction > 0.0) fPercent = fabs((*(double *)pEQ_ROWS - fFraction)/fFraction); else fPercent = 0.0; // Fail if off by more than 10% CCOMPARE(m_EC, fPercent < MAX_STATISTIC_ERROR, EC_BAD_EQ_ROWS, L"EQ_ROWS not within 10%", FALSE); } // DISTINCT_RANGE_ROWS // Number of distinct values in this range. // Select distinct rows in this range. if (pDISTINCT_RANGE_ROWS) { ulRangeCount = Cardinality(pwszQualifiedName, ulIndex, DISTINCT_RANGE_ROWS_CARDINALITY, pPrevBind, pCurrentBind, pDataRows, cbRowSize*2); // Compute percentage error in result, avoid division by 0 if (ulRangeCount) fPercent = fabs(float((*(LONGLONG *)pDISTINCT_RANGE_ROWS - (LONGLONG)ulRangeCount))/(float)(DB_LORDINAL)ulRangeCount); else fPercent = 0.0; // Fail if off by more than 10% CCOMPARE(m_EC, fPercent < MAX_STATISTIC_ERROR, EC_BAD_DISTINCT_RANGE_ROWS, L"DISTINCT_RANGE_ROWS not within 10%", FALSE); } } // Release the row CHECK(pIRowset->ReleaseRows(1, phRows, NULL, NULL, NULL), S_OK); // Point the pDataHist buffer to other half of total buffer pDataHist = pDataRows+cbRowSize*(cRows % 2); ReleaseInputBindingsMemory(cBinding, pBinding, pDataHist, FALSE); } // Free the row handles SAFE_FREE(phRows); // Release memory for the previous row we retrieved if (cRows) ReleaseInputBindingsMemory(cBinding, pBinding, pDataRows+cbRowSize*((cRows-1) % 2), FALSE); SAFE_FREE(pDataRows); // Make sure we got DB_S_ENDOFROWSET CHECK(hrGetNextRows, DB_S_ENDOFROWSET); // Make sure row count matches NO_OF_RANGES if (pcRanges) COMPARE(cRows, *pcRanges); } } } else { CHECK(pIRowset == NULL, TRUE); // We allow the histogram failure if the table no longer // exists. if (!CHECK(hrOpenHistogram, DB_E_NOTABLE)) odtLog << L"Histogram rowset not returned.\n"; } } } else { // If the table was deleted the provider may return // DB_E_NOTABLE instead of DB_E_NOSTATISTIC if (hrOpenHistogram != DB_E_NOTABLE) { CCHECK(m_EC, hrOpenHistogram, DB_E_NOSTATISTIC, EC_BAD_HR_OPENHISTOGRAM, L"Unexpected return code from OpenRowset on histogram.", FALSE); } } SAFE_RELEASE(pIRowset); } } PRVTRACE(L"'%d'\n",(WCHAR *)pColumn->bValue); break; } case TS_COLUMN_NAME: // Sanity check // Column must have non-empty string and cannot be NULL if (COMPARE(pColumn->sStatus, DBSTATUS_S_OK)) { COMPARE(wcslen((TYPE_WSTR)pColumn->bValue) > 0, TRUE); // Detail check if (m_fDetailCheck && SUCCEEDED(hrOpenTable)) // Column name must match columns info for this ordinal COMPARE(RelCompareString(m_prgColInfo[ulIndex].pwszName, (TYPE_WSTR)pColumn->bValue), 0); } break; case TS_COLUMN_GUID: // Sanity check: none // Detail check if (m_fDetailCheck && SUCCEEDED(hrOpenTable)) { // Column guid must match columns info if (S_OK == pColumn->sStatus) { COMPARE(m_prgColInfo[ulIndex].columnid.uGuid.guid == *(GUID *)pColumn->bValue, TRUE); } else { // Must be NULL // COMPARE(m_prgColInfo[ulIndex].columnid.uGuid.guid == DB_NULLGUID, TRUE); } } break; case TS_COLUMN_PROPID: // Sanity check: none // Detail check if (m_fDetailCheck && SUCCEEDED(hrOpenTable)) { // Column propid must match columns info if (S_OK == pColumn->sStatus) COMPARE(m_prgColInfo[ulIndex].columnid.uName.ulPropid == *(ULONG *)pColumn->bValue, TRUE); // If status == DBSTATUS_S_ISNULL, then value is undefined and can't be // compared. And it appears ulPropid in columnsinfo is uninitialized. } break; case TS_ORDINAL_POSITION: // The ordinal position must be sequential within the table { // Column cannot be null if (COMPARE(pColumn->sStatus, DBSTATUS_S_OK)) { // If we have a valid column name if (pwszTableName && pwszStatName) { if (fNewStat) { // This is a new statistic, ordinal must be 1 m_iOrdinalExpected = 1; SAFE_FREE(m_pwszTableName); SAFE_FREE(m_pwszStatName); m_pwszTableName = wcsDuplicate(pwszTableName); m_pwszStatName = wcsDuplicate(pwszStatName); } else m_iOrdinalExpected++; // Compare Ordinal returned with expected if (!COMPARE(m_iOrdinalExpected, *(TYPE_UI4 *)pColumn->bValue)) odtLog << pwszTableName << L": Invalid ordinal value returned.\n"; } } break; } case TS_SAMPLE_PCT: case TS_LAST_UPDATE_TIME: case TS_NO_OF_RANGES: // This is tested for accuracy by counting rows in histogram rowset. break; case TS_COLUMN_CARDINALITY: eCardinality = COLUMN_CARDINALITY; // Fall through case TS_TUPLE_CARDINALITY: // This should equal number distinct rows in table for this column if (m_fDetailCheck && SUCCEEDED(hrOpenTable) && pColumn->sStatus == DBSTATUS_S_OK) { DBCOUNTITEM cRows = Cardinality(pwszQualifiedName, ulIndex, eCardinality); // Note test bug here Cardinality() doesn't include NULL rows. CCOMPARE(m_EC, cRows == *(ULONG *)pColumn->bValue, EC_BAD_COL_OR_TUPLE_CARD, L"Column or Tuple cardinality is incorrect", FALSE); } break; case TS_TABLE_CARDINALITY: // Spec doesn't indicate this can be NULL. COMPARE(pColumn->sStatus, DBSTATUS_S_OK); // Detail check // This should equal number of rows in table if (m_fDetailCheck && SUCCEEDED(hrOpenTable) && pColumn->sStatus == DBSTATUS_S_OK) { DBCOUNTITEM cRows = Cardinality(pwszQualifiedName, ulIndex, TABLE_CARDINALITY); CCOMPARE(m_EC, cRows == *(ULONG *)pColumn->bValue, EC_BAD_TABLE_CARDINALITY, L"Table cardinality is incorrect", FALSE); } break; case TS_AVG_COLUMN_LENGTH: break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"TABLE STATISTICS: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - TABLE STATISTICS provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } break; } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; COMPARE(pColumn->sStatus, DBSTATUS_S_OK); } else { PRVTRACE(L"%s=",m_rgDBCOLUMNINFO[iBind].pwszName); RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); COMPARE(pColumn->sStatus, DBSTATUS_S_OK); } } CLEANUP: SAFE_FREE(pwszQualifiedName); return fResults; } //-------------------------------------------------------------------- // TABLES // 1. Catalog Name // 2. Schema Name // 3. Table Name // 4. Table Type //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_TABLES() { // Set the Schema column Count, Names and Types m_cColumns = cTABLES; m_rgColumnNames = (WCHAR **) rgwszTABLES; m_rgColumnTypes = (DBTYPE *) rgtypeTABLES; // Set the count of restrictions m_cRestrictions = cTABLES_RESTRICTIONS; // Set Valid Table Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszTableRestriction); SetRestriction(FOURTH,4, &m_wszR4, m_pwszTable_TypeRestriction); // Set an Invalid Table Restriction if(m_restrict & FIFTH) { SetRestriction(FIFTH,5, &m_wszR5, m_pwszTableRestriction); m_cRestrictions = 5; } // Set expected row count. Since we create a table there must be // at least one. SetRowCount(MIN_REQUIRED, 1); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowTABLES // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_TABLES(DBCOUNTITEM iRow, BYTE * pData) { ULONG iBind; // Binding Count DATA * pColumn; // Data Structure CCol col; BOOL fResults = TRUE; // Try to open a rowset on the table GetColumnInfo(pData, m_rgDBBINDING); // Check the count of columns returned if(iRow == 1) COMPARE(cTABLES <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { // TABLE_CATALOG case 1: fResults &= TestReturnData(iRow,pColumn,FIRST,&m_fRes1,m_wszR1); break; // TABLE_SCHEMA case 2: fResults &= TestReturnData(iRow,pColumn,SECOND,&m_fRes2,m_wszR2); break; // TABLE_NAME case 3: fResults &= TestReturnData(iRow,pColumn,THIRD,&m_fRes3,m_wszR3); break; // TABLE_TYPE case 4: fResults &= TestReturnData(iRow,pColumn,FOURTH,&m_fRes4,m_wszR4,FALSE); // Check the only spec'ed Types if( (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"ALIAS")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"TABLE")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"SYNONYM")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"SYSTEM TABLE")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"GLOBAL TEMPORARY")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"LOCAL TEMPORARY")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"SYSTEM VIEW")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"VIEW"))) { odtLog << L"Provider specific TABLE TYPE was returned by the provider: " << (TYPE_WSTR)pColumn->bValue << ENDL; fResults = FALSE; } break; // TABLE_GUID case 5: if(pColumn->sStatus == DBSTATUS_S_OK) COMPARE(pColumn->ulLength, sizeof(GUID)); else if(pColumn->sStatus == DBSTATUS_S_ISNULL) { // COMPARE(pColumn->ulLength, 0); // Not required per spec. } break; // DESCRIPTION case 6: if(pColumn->sStatus == DBSTATUS_S_ISNULL) { // COMPARE(pColumn->ulLength, 0); // Not required per spec. } break; // TABLE_PROPID case 7: if(pColumn->sStatus == DBSTATUS_S_OK) COMPARE(pColumn->ulLength, sizeof(ULONG)); else if(pColumn->sStatus == DBSTATUS_S_ISNULL) { // COMPARE(pColumn->ulLength, 0); // Not required per spec. } break; // DATE_CREATED // DATE_MODIFIED case 8: case 9: if(pColumn->sStatus == DBSTATUS_S_OK) COMPARE(pColumn->ulLength, sizeof(DATE)); else if(pColumn->sStatus == DBSTATUS_S_ISNULL) { // COMPARE(pColumn->ulLength, 0); // Not required per spec. } break; // PROVIDER SPECIFIC default: if (iRow == 1) { if(!m_rgDBCOLUMNINFO[iBind].iOrdinal) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"TABLES: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - TABLES provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } break; } } return fResults; } //-------------------------------------------------------------------- // TABLES_INFO // 1. Catalog Name // 2. Schema Name // 3. Table Name // 4. Table Type //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_TABLES_INFO() { // Set the Schema column Count, Names and Types m_cColumns = cTABLES_INFO; m_rgColumnNames = (WCHAR **) rgwszTABLES_INFO; m_rgColumnTypes = (DBTYPE *) rgtypeTABLES_INFO; // Set the count of restrictions m_cRestrictions = cTABLES_INFO_RESTRICTIONS; // Set Valid TableInfo Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszTableRestriction); SetRestriction(FOURTH,4, &m_wszR4, m_pwszTable_TypeRestriction); // Set an Invalid TableInfo Restriction if(m_restrict & FIFTH) { SetRestriction(FIFTH,5, &m_wszR5, m_pwszTableRestriction); m_cRestrictions = 5; } // Set expected row count. Since we create a table there must be // at least one. SetRowCount(MIN_REQUIRED, 1); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowTABLES_INFO // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_TABLES_INFO(DBCOUNTITEM iRow, BYTE * pData) { ULONG iBind; // Binding Count DATA * pColumn; // Data Structure CCol col; BOOL fResults = TRUE; // Check the count of columns returned if(iRow == 1) COMPARE(cTABLES_INFO <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { // TABLE_CATALOG case 1: fResults &= TestReturnData(iRow,pColumn,FIRST,&m_fRes1,m_wszR1); break; // TABLE_SCHEMA case 2: fResults &= TestReturnData(iRow,pColumn,SECOND,&m_fRes2,m_wszR2); break; // TABLE_NAME case 3: fResults &= TestReturnData(iRow,pColumn,THIRD,&m_fRes3,m_wszR3); break; // TABLE_TYPE case 4: fResults &= TestReturnData(iRow,pColumn,FOURTH,&m_fRes4,m_wszR4); // Check the only spec'ed Types if( (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"ALIAS")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"TABLE")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"SYNONYM")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"SYSTEM TABLE")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"GLOBAL TEMPORARY")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"SYSTEM TEMPORARY")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"SYSTEM VIEW")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"VIEW"))) { odtLog << L"VerifyRow_TABLES_INFO:TABLE TYPE expected ALIAS/TABLE/SYNONYM/SYSTEM TABLE/GLOBAL/SYSTEM/VIEW but recieved " << (TYPE_WSTR)pColumn->bValue << ENDL; fResults = FALSE; } break; // TABLE_GUID case 5: break; // BOOKMARKS case 6: break; // BOOKMARK_TYPE // BOOKMARK_DATATYPE // BOOKMARK_MAXIMUM // BOOKMARK_INFORMATION case 7: case 8: case 9: case 10: break; // TABLE_VERSION case 11: break; // CARDINALITY case 12: break; // DESCRIPTION case 13: break; // TABLE_PROPID case 14: break; // PROVIDER SPECIFIC default: if (iRow == 1) { if(!m_rgDBCOLUMNINFO[iBind].iOrdinal) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"TABLES_INFO: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - TABLES_INFO provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } break; } } return fResults; } //-------------------------------------------------------------------- // TRANSLATIONS // 1. Catalog Name // 2. Schema Name // 3. Translation Name //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_TRANSLATIONS() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszTRANSLATIONS; m_rgColumnTypes = (DBTYPE *)rgtypeTRANSLATIONS; // Set the count of columns and restrictions m_cColumns = cTRANSLATIONS; m_cRestrictions = cTRANSLATIONS_RESTRICTIONS; // Set Transalation Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszTranslationReplace); PRVTRACE(L"GetSchemaInfo::TRANSLATIONS\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowTRANSLATIONS // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_TRANSLATIONS ( DBCOUNTITEM iRow, BYTE * pData ) { ULONG iBind; // Binding Count DATA * pColumn; // Data Structure CCol col; BOOL fResults = TRUE; // don't need to go farther if I have what I'm looking for if(m_fCaptureRestrictions && m_pwszTranslationReplace) return FALSE; // Check the count of columns returned if(iRow == 1) COMPARE(cTRANSLATIONS <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"Row[%lu],Col[%s]:TRANSLATIONS:", iRow, m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1:// TABLE_CATALOG if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_TRANSLATIONS: TRANSLATION CATALOG restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2:// TABLE_SCHEMA if(m_restrict & SECOND) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR2,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes2) { odtLog << L"VerifyRow_TRANSLATIONS: TRANSLATION SCHEMA restriction failed\n"; m_fRes2=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 3:// Translation Name if(m_fCaptureRestrictions) { m_pwszTranslationReplace = (TYPE_WSTR) PROVIDER_ALLOC ((wcslen((WCHAR *) pColumn->bValue)*sizeof(WCHAR)) + sizeof(WCHAR)); if(m_pwszTranslationReplace) wcscpy(m_pwszTranslationReplace,(TYPE_WSTR) pColumn->bValue); } if(m_restrict & THIRD) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR3,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes3) { odtLog << L"VerifyRow_TRANSLATIONS: TRANSLATION NAME restriction failed\n"; m_fRes3=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(WCHAR *)pColumn->bValue); break; case 4: // SOURCE CHARACTER SET CATALOG case 5: // SOURCE CHARACTER SET SCHEMA case 6: // SOURCE CHARACTER SET NAME case 7: // TARGET CHARACTER SET CATALOG case 8: // TARGET CHARACTER SET SCHEMA case 9: // TARGET CHARACTER SET NAME PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"TRANSLATIONS: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - TRANSLATIONS provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } break; } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else { PRVTRACE(L"%s=",m_rgDBCOLUMNINFO[iBind].pwszName); RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // TRUSTEE // 1. TRUSTEE_NAME // 2. TRUSTEE_GUID // 3. TRUSTEE_TYPE //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_TRUSTEE() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszTRUSTEE; m_rgColumnTypes = (DBTYPE *)rgtypeTRUSTEE; // Set the count of columns and restrictions m_cColumns = cTRUSTEE; m_cRestrictions = cTRUSTEE_RESTRICTIONS; odtLog << L"*** Add restriction values for DBSCHEMA_TRUSTEE.\n"; // Set TRUSTEE Restrictions // SetRestriction(FIRST, 1, &m_wszR1, m_pwszTrusteeName); // SetRestriction(SECOND,2, &m_wszR2, m_pwszTrusteeGUID); // SetRestriction(THIRD, 3, &m_wszR3, m_pwszTrusteePROPID); // SetRestriction(FOURTH,4, &m_wszR4, m_pwszTrusteeType); PRVTRACE(L"GetSchemaInfo::TRUSTEE\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowTRANSLATIONS // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_TRUSTEE ( DBCOUNTITEM iRow, BYTE * pData ) { ULONG iBind; // Binding Count DATA * pColumn; // Data Structure CCol col; BOOL fResults = TRUE; // don't need to go farther if I have what I'm looking for if(m_fCaptureRestrictions && m_pwszTranslationReplace) return FALSE; odtLog << L"*** Currently not testing values returned from DBSCHEMA_TRUSTEE.\n"; // Check the count of columns returned if(iRow == 1) COMPARE(cTRUSTEE <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"Row[%lu],Col[%s]:TRUSTEE:", iRow, m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1:// TRUSTEE_NAME /* if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_TRUSTEE: TRUSTEE_NAME restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } */ PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2:// TRUSTEE_GUID /* if(m_restrict & SECOND) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR2,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes2) { odtLog << L"VerifyRow_TRUSTEE: TRUSTEE_GUID restriction failed\n"; m_fRes2=FALSE; fResults = FALSE; } } } */ PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 3:// TRUSTEE_PROPID /* if(m_fCaptureRestrictions) { m_pwszTranslationReplace = (TYPE_WSTR) PROVIDER_ALLOC ((wcslen((WCHAR *) pColumn->bValue)*sizeof(WCHAR)) + sizeof(WCHAR)); if(m_pwszTranslationReplace) wcscpy(m_pwszTranslationReplace,(TYPE_WSTR) pColumn->bValue); } if(m_restrict & THIRD) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR3,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes3) { odtLog << L"VerifyRow_TRUSTEE: TRUSTEE_PROPID restriction failed\n"; m_fRes3=FALSE; fResults = FALSE; } } } */ PRVTRACE(L"'%s'\n",(WCHAR *)pColumn->bValue); break; case 4: // TRUSTEE_TYPE PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"TRANSLATIONS: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - TRANSLATIONS provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } break; } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else { PRVTRACE(L"%s=",m_rgDBCOLUMNINFO[iBind].pwszName); RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // USAGE_PRIVILGES // 1. Catalog Name // 2. Schema Name // 3. Object Name // 4. Object Type // 5. Grantor // 6. Grantee //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_USAGE_PRIVILEGES() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszUSAGE_PRIVILEGES; m_rgColumnTypes = (DBTYPE *)rgtypeUSAGE_PRIVILEGES; // Set the count of columns and restrictions m_cColumns = cUSAGE_PRIVILEGES; m_cRestrictions = cUSAGE_PRIVILEGES_RESTRICTIONS; // Set Object Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszObjectRestriction); SetRestriction(FOURTH,4, &m_wszR4, m_pwszObject_TypeRestriction); SetRestriction(FIFTH, 5, &m_wszR5, m_pwszGrantorRestriction); SetRestriction(SIXTH, 6, &m_wszR6, m_pwszGranteeRestriction); PRVTRACE(L"GetSchemaInfo::USAGE_PRIVILGES\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowUSAGE_PRIVILEGES // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_USAGE_PRIVILEGES ( DBCOUNTITEM iRow, BYTE * pData ) { ULONG iBind; // Binding Count DATA * pColumn; // Data Structure CCol col; BOOL fResults = TRUE; // don't need to go farther if I have what I'm looking for if(m_fCaptureRestrictions && m_pwszObjectRestriction && m_pwszObject_TypeRestriction) return FALSE; // Check the count of columns returned if(iRow == 1) COMPARE(cUSAGE_PRIVILEGES <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"Row[%lu],Col[%s]:USAGE_PRIVILEGES:", iRow, m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1://GRANTOR if(m_restrict & FIFTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR5,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes5) { odtLog << L"VerifyRow_USAGE_PRIVILEGES:GRANTOR restriction failed\n"; m_fRes5=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2:// GRANTEE if(m_restrict & SIXTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR6,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes6) { odtLog << L"VerifyRow_USAGE_PRIVILEGES:GRANTEE restriction failed\n"; m_fRes6=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 3: // OBJECT CATALOG if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_USAGE_PRIVILEGES:OBJECT CATALOG restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 4:// OBJECT SCHEMA if(m_restrict & SECOND) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR2,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes2) { odtLog << L"VerifyRow_USAGE_PRIVILEGES:OBJECT SCHEMA restriction failed\n"; m_fRes2=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 5:// OBJECT NAME if(m_fCaptureRestrictions) { m_pwszObjectRestriction = (WCHAR *) PROVIDER_ALLOC ((wcslen((WCHAR *) pColumn->bValue)*sizeof(WCHAR)) + sizeof(WCHAR)); if(m_pwszObjectRestriction) wcscpy(m_pwszObjectRestriction,(TYPE_WSTR) pColumn->bValue); } if(m_restrict & THIRD) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR3,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes3) { odtLog << L"VerifyRow_USAGE_PRIVILEGES:OBJECT NAME restriction failed\n"; m_fRes3=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 6: // OBJECT TYPE if(m_restrict & FOURTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR4,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes4) { odtLog << L"VerifyRow_USAGE_PRIVILEGES:OBJECT TYPE restriction failed\n"; m_fRes4=FALSE; fResults = FALSE; } } } if(m_fCaptureRestrictions) { m_pwszObject_TypeRestriction = (WCHAR *) PROVIDER_ALLOC ((wcslen((WCHAR *) pColumn->bValue)*sizeof(WCHAR)) + sizeof(WCHAR)); if(m_pwszObject_TypeRestriction) wcscpy(m_pwszObject_TypeRestriction,(TYPE_WSTR) pColumn->bValue); } if( (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"DOMAIN")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"CHARACTER SET")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"COLLATION")) && (0!=wcscmp((TYPE_WSTR)pColumn->bValue,L"TRANSLATION"))) { odtLog << L"VerifyRow_USAGE_PRIVILEGES:OBJECT TYPE expected DOMAIN/CHARACTERSET/COLLATION/TRANSLATION but recieved " << (TYPE_WSTR)pColumn->bValue << ENDL; fResults = FALSE; } PRVTRACE(L"'%s'\n",(WCHAR *)pColumn->bValue); break; case 7: // PRIVILEGE TYPE PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 8: // IS_GRANTABLE if(*(TYPE_BOOL *)pColumn->bValue==VARIANT_TRUE) PRVTRACE(L"TRUE\n"); else PRVTRACE(L"FALSE\n"); break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"USAGE PRIVILEGES: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - USAGE PRIVILEGES provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } break; } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else { PRVTRACE(L"%s=",m_rgDBCOLUMNINFO[iBind].pwszName); RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // VIEW_COLUMN_USAGE // 1. Catalog Name // 2. Schema Name // 3. View Name //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_VIEW_COLUMN_USAGE() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszVIEW_COLUMN_USAGE; m_rgColumnTypes = (DBTYPE *)rgtypeVIEW_COLUMN_USAGE; // Set the count of columns and restrictions m_cColumns = cVIEW_COLUMN_USAGE; m_cRestrictions = cVIEW_COLUMN_USAGE_RESTRICTIONS; // Set View Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszViewRestriction); PRVTRACE(L"GetSchemaInfo::VIEW_COLUMN_USAGE\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowVIEW_COLUMN_USAGE // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_VIEW_COLUMN_USAGE ( DBCOUNTITEM iRow, BYTE * pData ) { ULONG iBind; // Binding Count DATA * pColumn; // Data Structure CCol col; BOOL fResults = TRUE; // Check the count of columns returned if(iRow == 1) COMPARE(cVIEW_COLUMN_USAGE <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"Row[%lu],Col[%s]:VIEW_COLUMN_USAGE:", iRow, m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1://VIEW CATALOG if(m_restrict & FIFTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR5,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes5) { odtLog << L"VerifyRow_VIEW_COLUMN_USAGE: VIEW CATALOG restriction failed\n"; m_fRes5=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2:// VIEW SCHEMA if(m_restrict & SIXTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR6,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes6) { odtLog << L"VerifyRow_VIEW_COLUMN_USAGE:VIEW SCHEMA restriction failed\n"; m_fRes6=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 3: // VIEW NAME if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_VIEW_COLUMN_USAGE:VIEW NAME restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 4:// TABLE CATALOG case 5:// TABLE SCHEMA case 6:// TABLE NAME case 7:// COLUMN NAME PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 8: // COLUMN GUID PRVTRACE(L"\n"); break; case 9: // COLUMN PROPID PRVTRACE(L"%d\n",*(TYPE_UI4 *)pColumn->bValue); break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"VIEW COLUMN USAGE: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - VIEW COLUMN USAGE provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } break; } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else { PRVTRACE(L"%s=",m_rgDBCOLUMNINFO[iBind].pwszName); RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // VIEW_TABLE_USAGE // 1. Catalog Name // 2. Schema Name // 3. View Name //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_VIEW_TABLE_USAGE() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszVIEW_TABLE_USAGE; m_rgColumnTypes = (DBTYPE *)rgtypeVIEW_TABLE_USAGE; // Set the count of columns and restrictions m_cColumns = cVIEW_TABLE_USAGE; m_cRestrictions = cVIEW_TABLE_USAGE_RESTRICTIONS; // Set View Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszViewRestriction); PRVTRACE(L"GetSchemaInfo::VIEW_TABLE_USAGE\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowVIEW_TABLE_USAGE // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_VIEW_TABLE_USAGE ( DBCOUNTITEM iRow, BYTE * pData ) { ULONG iBind; // Binding Count DATA * pColumn; // Data Structure CCol col; BOOL fResults = TRUE; // don't need to go farther if I have what I'm looking for if(m_fCaptureRestrictions && m_pwszViewRestriction) return FALSE; // Check the count of columns returned if(iRow == 1) COMPARE(cVIEW_TABLE_USAGE <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"Row[%lu],Col[%s]:VIEW_TABLE_USAGE:", iRow, m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1://VIEW CATALOG if(m_restrict & FIFTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR5,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes5) { odtLog << L"VerifyRow_VIEW_TABLE_USAGE: VIEW CATALOG restriction failed\n"; m_fRes5=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2:// VIEW SCHEMA if(m_restrict & SIXTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR6,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes6) { odtLog << L"VerifyRow_VIEW_TABLE_USAGE:VIEW SCHEMA restriction failed\n"; m_fRes6=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 3: // VIEW NAME if(m_fCaptureRestrictions) { m_pwszViewRestriction = (WCHAR *) PROVIDER_ALLOC ((wcslen((WCHAR *) pColumn->bValue)*sizeof(WCHAR*)) + sizeof(WCHAR)); if(m_pwszViewRestriction) wcscpy(m_pwszViewRestriction,(TYPE_WSTR) pColumn->bValue); } if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_VIEW_TABLE_USAGE:VIEW NAME restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 4:// TABLE CATALOG case 5:// TABLE SCHEMA case 6:// TABLE NAME PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"VIEW TABLE USAGE: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - VIEW TABLE USAGE provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } break; } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; fResults = FALSE; } else { PRVTRACE(L"%s=",m_rgDBCOLUMNINFO[iBind].pwszName); RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } //-------------------------------------------------------------------- // VIEWS // 1. Table Catalog // 2. Table Schema // 3. Table View //-------------------------------------------------------------------- BOOL CSchemaTest::PrepareParams_VIEWS() { // Set the Schema column Names and Types m_rgColumnNames = (WCHAR **)rgwszVIEWS; m_rgColumnTypes = (DBTYPE *)rgtypeVIEWS; // Set the count of columns and restrictions m_cColumns = cVIEWS; m_cRestrictions = cVIEWS_RESTRICTIONS; // Set View Restrictions SetRestriction(FIRST, 1, &m_wszR1, m_pwszCatalogRestriction); SetRestriction(SECOND,2, &m_wszR2, m_pwszSchemaRestriction); SetRestriction(THIRD, 3, &m_wszR3, m_pwszTableRestriction); PRVTRACE(L"GetSchemaInfo::VIEWS\n"); return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowVIEWS // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRow_VIEWS ( DBCOUNTITEM iRow, BYTE * pData ) { ULONG iBind; // Binding Count DATA * pColumn; // Data Structure CCol col; BOOL fResults = TRUE; // Check the count of columns returned if(iRow == 1) COMPARE(cVIEWS <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); // PRVTRACE(L"Row[%lu],Col[%s]:VIEWS:", iRow, m_rgDBCOLUMNINFO[iBind].pwszName); if(pColumn->sStatus==DBSTATUS_S_OK) { switch(m_rgDBCOLUMNINFO[iBind].iOrdinal) { case 1://TABLE CATALOG if(m_restrict & FIFTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR5,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes5) { odtLog << L"VerifyRow_VIEWS: TABLE CATALOG restriction failed\n"; m_fRes5=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 2:// TABLE SCHEMA if(m_restrict & SIXTH) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR6,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes6) { odtLog << L"VerifyRow_VIEWS:TABLE SCHEMA restriction failed\n"; m_fRes6=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 3: // TABLE NAME if(m_restrict & FIRST) { if(!COMPARE(0, _wcsicmp((TYPE_WSTR)m_wszR1,(TYPE_WSTR)pColumn->bValue))) { if(m_fRes1) { odtLog << L"VerifyRow_VIEWS:TABLE NAME restriction failed\n"; m_fRes1=FALSE; fResults = FALSE; } } } PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 4:// VIEW_DEFINITION case 7:// DESCRIPTION PRVTRACE(L"'%s'\n",(TYPE_WSTR)pColumn->bValue); break; case 5:// CHECK_OPTION case 6:// IS_UPDATEABLE if(*(TYPE_BOOL *)pColumn->bValue==VARIANT_TRUE) PRVTRACE(L"TRUE\n"); else PRVTRACE(L"FALSE\n"); break; // DATE_CREATED // DATE_MODIFIED case 8: case 9: break; default: // We found a column not spec'd for this schema rowset, print a warning. if (iRow == 1) { if (m_rgDBCOLUMNINFO[iBind].iOrdinal == 0) { if(!GetProperty(DBPROP_BOOKMARKS,DBPROPSET_ROWSET,m_pIRowset)) odtLog << L"VIEWS: Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } else odtLog << L"Warning - VIEWS provider specific column name: " << m_rgDBCOLUMNINFO[iBind].pwszName << "\n"; } break; } } else if (pColumn->sStatus==DBSTATUS_S_TRUNCATED) { // Have to flag error. odtLog << L"DBSTATUS_S_TRUNCATED: " << (TYPE_WSTR)pColumn->bValue << L"\n"; // We shouldn't be flagging an error for LONG columns, we expect truncation. if (!(m_rgDBCOLUMNINFO[iBind].dwFlags & DBCOLUMNFLAGS_ISLONG)) fResults = FALSE; } else { PRVTRACE(L"%s=",m_rgDBCOLUMNINFO[iBind].pwszName); RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus); } } return fResults; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::CheckResults(IUnknown * pIRowset, IID iid) { BOOL fResult = TRUE; // if I didn't get rowset back when I expected FIRST, return error if(SUCCEEDED(m_HR)) { if( ((m_iid==IID_IRowset) && (!m_pIRowset)) || ((m_iid==IID_IAccessor) && (!m_pIAccessor)) || ((m_iid==IID_IRowsetInfo) && (!m_pIRowsetInfo)) || ((m_iid==IID_IColumnsInfo) && (!m_pIColumnsInfo))|| ((m_iid==IID_IRowsetChange) && (!m_pIRowsetChange)) ) { odtLog << L"CheckResults:expected rowset but didn't get FIRST\n"; return FALSE; } // check that the riid pointer can be used, // regardless of which riid it is fResult &= CheckRIID(pIRowset, iid); fResult &= VerifyRowset(pIRowset); } else // make sure rowset if empty { if( ((m_iid==IID_IRowset) && (m_pIRowset)) || ((m_iid==IID_IAccessor) && (m_pIAccessor)) || ((m_iid==IID_IRowsetInfo) && (m_pIRowsetInfo))|| ((m_iid==IID_IColumnsInfo) && (m_pIColumnsInfo))|| ((m_iid==IID_IRowsetChange) && (m_pIRowsetChange))) { odtLog << L"CheckResults: method returned error and valid rowset pointer!\n"; return FALSE; } } return fResult; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // CheckAgainstIColumnsInfo // // Checks the DBCOLUMNINFO array returned by IColumnsInfo::GetColumnsInfo against // the what the spec says the column name, type and order should be // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::CheckAgainstIColumnsInfo() { BOOL fResult = TRUE; BOOL fCountNotChecked= FALSE; ULONG ulIndex = 0; COMPARE(m_cColumns <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // Make sure the rowset is not null if((!m_pIRowset) || (!m_cDBCOLUMNINFO) || (!m_rgDBCOLUMNINFO) || (!m_pStringsBuffer)) { odtLog << L"CheckAgainstIColumnsInfo:Either rowset or DBCOLUMNINFO variables are null."<CountColumnsOnTable(); iCol++) { // Get the information about the column if (!CHECK(m_pTable->GetColInfo(iCol, TempCol), S_OK)) { fResult = FALSE; goto CLEANUP; } // If this is DBTYPE_DBTIMESTAMP it may be the right one if (m_rgDBCOLUMNINFO[ulIndex].wType == TempCol.GetProviderType()) { bPrecision = TempCol.GetPrecision(); bScale = TempCol.GetScale(); if (bPrecision == m_rgDBCOLUMNINFO[ulIndex].bPrecision && bScale == m_rgDBCOLUMNINFO[ulIndex].bScale) { // We found a matching value for precision and scale break; } } } // Precision is defined as length of string representation assuming max // allowed precision of fractional seconds component. // TODO: Compare against CCol. if (m_rgDBCOLUMNINFO[ulIndex].bPrecision != bPrecision) { odtLog <QueryInterface(IID_IRowset,(void **) &pInterface))) cErrors++; SAFE_RELEASE(pInterface); // QI for IID_IAccessor if(FAILED(hr=pColRowset->QueryInterface(IID_IAccessor,(void **) &pInterface))) cErrors++; SAFE_RELEASE(pInterface); // QI for IID_IColumnsInfo if(FAILED(hr=pColRowset->QueryInterface(IID_IColumnsInfo,(void **) &pInterface))) cErrors++; SAFE_RELEASE(pInterface); // QI for IID_IRowsetInfo if(FAILED(hr=pColRowset->QueryInterface(IID_IRowsetInfo,(void **) &pInterface))) cErrors++; SAFE_RELEASE(pInterface); // QI for IID_IConvertType if(FAILED(hr=pColRowset->QueryInterface(IID_IConvertType,(void **) &pInterface))) cErrors++; SAFE_RELEASE(pInterface); if(!cErrors) return TRUE; else return FALSE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // VerifyRowset, verify rowset and row order // // 1) Verify Maxlength, Precision, and Scale for non-applicable datatypes // 2) Check ComputeMode // 3) Order of rows is order of columns in query // // ---------------------------------------------- // 1. IColumnsInfo::GetColumnInfo, build binding (from GetAccessorAndBindings) // 2. IAccessor::CreateAccessor (from GetAccessorAndBindings) // Loop // 3. IRowset::GetNextRows // 4. IRowset::GetData // 5. IRowset::ReleaseRows // End Loop // // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CSchemaTest::VerifyRowset(IUnknown * pIUnknown) { BOOL fVerifyRow = TRUE; BOOL fFirstTimeThruLoop = TRUE; HRESULT hr = E_FAIL; BOOL fReleaseRowset = FALSE; // whether I should release pIRowset; HACCESSOR hAccessor=DB_NULL_HACCESSOR; // handle to accessor ULONG iBind = 0; // current binding ULONG iRow = 0; // current row DBLENGTH cbRowSize = 0; // size of row DBCOUNTITEM cRowsObtained = 0; // total rows obtained from getnextrows DBCOUNTITEM cTotalRows = 0; // total row count BYTE * pRow = NULL; // row of Data HROW * prghRows = NULL; // array of hrows IAccessor * pIAccessor = NULL; ULONG ulRowsToVerify; BOOL fCapturingRestrictions = m_fCaptureRestrictions; BOOL fContinue = TRUE; m_fResult = FALSE; m_fRes1=m_fRes2=m_fRes3=m_fRes4=m_fRes5=m_fRes6=m_fRes7=TRUE; // if I don't have the rowset pointer, I need to go get FIRST if (!pIUnknown) { if(m_iid == IID_IColumnsInfo) pIUnknown = m_pIColumnsInfo; else if(m_iid == IID_IAccessor) pIUnknown = m_pIAccessor; else if(m_iid == IID_IRowsetChange) pIUnknown = m_pIRowsetChange; else if(m_iid == IID_IRowsetInfo) pIUnknown = m_pIRowsetInfo; else if((m_iid == IID_IRowset) && (!m_pIRowset)) return FALSE; } if(pIUnknown && !m_pIRowset && FAILED(hr=pIUnknown->QueryInterface(IID_IRowset,(void **)&m_pIRowset)) ) return FALSE; if (!VerifyInterface(m_pIRowset, IID_IAccessor, ROWSET_INTERFACE, (IUnknown**)&pIAccessor)) goto CLEANUP; fReleaseRowset = TRUE; // get bindings and column info if(!CHECK(hr=GetAccessorAndBindings( m_pIRowset, // @parmopt [IN] Rowset to create Accessor for DBACCESSOR_ROWDATA, // @parmopt [IN] Properties of the Accessor &hAccessor, // @parmopt [OUT] Accessor created &m_rgDBBINDING, // @parmopt [OUT] Array of DBBINDINGS &m_cDBBINDING, // @parmopt [OUT] Count of bindings &cbRowSize, // @parmopt [OUT] Length of a row, DATA DBPART_VALUE|DBPART_STATUS |DBPART_LENGTH, ALL_COLS_BOUND, // @parmopt [IN] Which columns will be used in the bindings FORWARD, // @parmopt [IN] Order to bind columns in accessor NO_COLS_BY_REF, // @parmopt [IN] Which column types to bind by reference &m_rgDBCOLUMNINFO, // @parmopt [OUT] Array of DBCOLUMNINFO &m_cDBCOLUMNINFO, // @parmopt [OUT] Count of Columns, also count of ColInfo elements &m_pStringsBuffer, DBTYPE_EMPTY, // @parmopt [IN] Modifier to be OR'd with each binding type. 0, // @parmopt [IN] Used only if eColsToBind = USE_COLS_TO_BIND_ARRAY NULL, // @parmopt [IN] Used only if eColsToBind = USE_COLS_TO_BIND_ARRAY NULL, // @parmopt [IN] Corresponds to what ordinals are specified for each binding, if NO_COLS_OWNED_BY_PROV, // @parmopt [IN] Which columns' memory is to be owned by the provider DBPARAMIO_NOTPARAM, // @parmopt [IN] Parameter kind specified for all bindings BLOB_LONG, // @parmopt [IN] how to bind BLOB Columns NULL),S_OK)) // @parmopt [OUT] returned status array from CreateAccessor goto CLEANUP; // Don't need to check if only capturing restrictions if(!m_fCaptureRestrictions) fVerifyRow &= CheckAgainstIColumnsInfo(); // check if we need to go on if((!m_cDBBINDING) || (!m_cDBCOLUMNINFO) || (!m_rgDBBINDING) || (!m_rgDBCOLUMNINFO)) goto CLEANUP; if(m_fPassUnsupportedRestrictions) { m_fResult = TRUE; goto CLEANUP; } // create space for row of data pRow = (BYTE *) PROVIDER_ALLOC(cbRowSize); if(!pRow) goto CLEANUP; if(GetModInfo()->GetDebugMode() & DEBUGMODE_FULL ) ulRowsToVerify = 90000; else // This should be larger than NUMROWS_CHUNK to force at least one additional // GetNextRows call below. ulRowsToVerify = 100; // Process all the rows, NUMROWS_CHUNK rows at a time while(fContinue) { // get rows to process hr=GetNextRows(0,30,&cRowsObtained,&prghRows); TEST4C_(hr, S_OK, DB_S_ENDOFROWSET, DB_S_STOPLIMITREACHED, DB_S_ROWLIMITEXCEEDED); // verify that we have rows to process if(cRowsObtained==0) { if (CHECK(hr, DB_S_ENDOFROWSET)) break; else goto CLEANUP; } // Only verify required number of rows if (cTotalRows < ulRowsToVerify) { // Make sure we don't call verify with no valid restrictions. ASSERT((m_restrict != ALLRES) || (m_currentBitMask == 0)); // Loop over rows obtained, getting data for each for(iRow=0;iRowGetData(prghRows[iRow],hAccessor,pRow))) goto CLEANUP; // make sure we got the row if(pRow==NULL) goto CLEANUP; // do something with row fVerifyRow &= VerifyRow(m_guid,cTotalRows,pRow); // If we know we've filled the restriction then break out of loop // Otherwise we continue for all rows if (fCapturingRestrictions && !m_fCaptureRestrictions) { m_fCaptureRestrictions = fCapturingRestrictions; fContinue = FALSE; break; } } } else cTotalRows += cRowsObtained; if (!CHECK(hr=m_pIRowset->ReleaseRows(cRowsObtained,prghRows,NULL,NULL,NULL),S_OK)) goto CLEANUP; fFirstTimeThruLoop = FALSE; } switch (m_eRowCount) { case MIN_VALUE: // Warn if we didn't get any rows but expected some if (m_ulRowCount && !cTotalRows) odtLog << L"Warning - this rowset didn't return any rows so no values were checked.\n"; // Fail if we got some rows but less than minimum expected if (cTotalRows) TESTC(cTotalRows >= m_ulRowCount); break; case MIN_REQUIRED: // Fail if we got less than minimum expected TESTC(cTotalRows >= m_ulRowCount); break; case EXACT_VALUE: // ASSERT(cTotalRows == m_ulRowCount); TESTC(cTotalRows == m_ulRowCount); break; default: ASSERT(!L"Unexpected row count value for schema rowset."); } // If we made it to here and verified each row then set success if (fVerifyRow) m_fResult = TRUE; CLEANUP: // Clear any table name information that might be left over SAFE_FREE(m_pwszTableName); if (pIAccessor && hAccessor != DB_NULL_HACCESSOR) CHECK(pIAccessor->ReleaseAccessor(hAccessor, NULL), S_OK); SAFE_RELEASE(pIAccessor); SAFE_RELEASE(m_pIRowset); m_cDBCOLUMNINFO = 0; m_cDBBINDING = 0; // Free the memory PROVIDER_FREE(m_rgDBCOLUMNINFO); PROVIDER_FREE(m_pStringsBuffer); PROVIDER_FREE(m_rgDBBINDING); PROVIDER_FREE(pRow); PROVIDER_FREE(prghRows); return m_fResult; } ULONG CSchemaTest::SchemaCatalogRestriction(ULONG ulIndex) { GUID guidSchema = m_rgSchemas[ulIndex]; return SchemaCatalogRestriction(guidSchema); } ULONG CSchemaTest::SchemaCatalogRestriction(GUID guidSchema) { // If the GUID is one for which we know a catalog restriction exists then return FIRST. // Catalog restriction is always the first one. // This is most of them but we can't use negative logic 'cause we might get a guid we // don't recognize. if (guidSchema == DBSCHEMA_ASSERTIONS || guidSchema == DBSCHEMA_CATALOGS || guidSchema == DBSCHEMA_CHARACTER_SETS || guidSchema == DBSCHEMA_CHECK_CONSTRAINTS || guidSchema == DBSCHEMA_COLLATIONS || guidSchema == DBSCHEMA_COLUMN_DOMAIN_USAGE || guidSchema == DBSCHEMA_COLUMN_PRIVILEGES || guidSchema == DBSCHEMA_COLUMNS || guidSchema == DBSCHEMA_CONSTRAINT_COLUMN_USAGE || guidSchema == DBSCHEMA_CONSTRAINT_TABLE_USAGE || guidSchema == DBSCHEMA_FOREIGN_KEYS || guidSchema == DBSCHEMA_INDEXES || guidSchema == DBSCHEMA_KEY_COLUMN_USAGE || guidSchema == DBSCHEMA_PRIMARY_KEYS || guidSchema == DBSCHEMA_PROCEDURE_COLUMNS || guidSchema == DBSCHEMA_PROCEDURE_PARAMETERS || guidSchema == DBSCHEMA_PROCEDURES || guidSchema == DBSCHEMA_REFERENTIAL_CONSTRAINTS || guidSchema == DBSCHEMA_SCHEMATA || guidSchema == DBSCHEMA_STATISTICS || guidSchema == DBSCHEMA_TABLE_CONSTRAINTS || guidSchema == DBSCHEMA_TABLE_PRIVILEGES || guidSchema == DBSCHEMA_TABLE_STATISTICS || guidSchema == DBSCHEMA_TABLES || guidSchema == DBSCHEMA_TABLES_INFO || guidSchema == DBSCHEMA_TRANSLATIONS || guidSchema == DBSCHEMA_USAGE_PRIVILEGES || guidSchema == DBSCHEMA_VIEW_COLUMN_USAGE || guidSchema == DBSCHEMA_VIEW_TABLE_USAGE || guidSchema == DBSCHEMA_VIEWS) return FIRST; // else return ZERO restrictions return ZERO; } ULONG CSchemaTest::SchemaSchemaRestriction(ULONG ulIndex) { GUID guidSchema = m_rgSchemas[ulIndex]; return SchemaSchemaRestriction(guidSchema); } ULONG CSchemaTest::SchemaSchemaRestriction(GUID guidSchema) { // If the GUID is one for which we know a catalog restriction exists then return FIRST. // Catalog restriction is always the first one. // This is most of them but we can't use negative logic 'cause we might get a guid we // don't recognize. if (guidSchema == DBSCHEMA_ASSERTIONS || guidSchema == DBSCHEMA_CHARACTER_SETS || guidSchema == DBSCHEMA_CHECK_CONSTRAINTS || guidSchema == DBSCHEMA_COLLATIONS || guidSchema == DBSCHEMA_COLUMN_DOMAIN_USAGE || guidSchema == DBSCHEMA_COLUMN_PRIVILEGES || guidSchema == DBSCHEMA_COLUMNS || guidSchema == DBSCHEMA_CONSTRAINT_COLUMN_USAGE || guidSchema == DBSCHEMA_CONSTRAINT_TABLE_USAGE || guidSchema == DBSCHEMA_FOREIGN_KEYS || guidSchema == DBSCHEMA_INDEXES || guidSchema == DBSCHEMA_KEY_COLUMN_USAGE || guidSchema == DBSCHEMA_PRIMARY_KEYS || guidSchema == DBSCHEMA_PROCEDURE_COLUMNS || guidSchema == DBSCHEMA_PROCEDURE_PARAMETERS || guidSchema == DBSCHEMA_PROCEDURES || guidSchema == DBSCHEMA_REFERENTIAL_CONSTRAINTS || guidSchema == DBSCHEMA_SCHEMATA || guidSchema == DBSCHEMA_STATISTICS || guidSchema == DBSCHEMA_TABLE_CONSTRAINTS || guidSchema == DBSCHEMA_TABLE_PRIVILEGES || guidSchema == DBSCHEMA_TABLE_STATISTICS || guidSchema == DBSCHEMA_TABLES || guidSchema == DBSCHEMA_TABLES_INFO || guidSchema == DBSCHEMA_TRANSLATIONS || guidSchema == DBSCHEMA_USAGE_PRIVILEGES || guidSchema == DBSCHEMA_VIEW_COLUMN_USAGE || guidSchema == DBSCHEMA_VIEW_TABLE_USAGE || guidSchema == DBSCHEMA_VIEWS) return SECOND; // else return ZERO restrictions return ZERO; } ULONG CSchemaTest::SchemaTableRestriction(ULONG ulIndex) { GUID guidSchema = m_rgSchemas[ulIndex]; return SchemaTableRestriction(guidSchema); } ULONG CSchemaTest::SchemaTableRestriction(GUID guidSchema) { // This is most of them but we can't use negative logic 'cause we might get a guid we // don't recognize. if (guidSchema == DBSCHEMA_COLUMN_PRIVILEGES || guidSchema == DBSCHEMA_COLUMNS || guidSchema == DBSCHEMA_CHECK_CONSTRAINTS_BY_TABLE || guidSchema == DBSCHEMA_CONSTRAINT_COLUMN_USAGE || guidSchema == DBSCHEMA_CONSTRAINT_TABLE_USAGE || guidSchema == DBSCHEMA_FOREIGN_KEYS || // This is really PK_TABLE_NAME, but it will suffice guidSchema == DBSCHEMA_INDEXES || // This is really INDEX_NAME, but we always use table name guidSchema == DBSCHEMA_PRIMARY_KEYS || guidSchema == DBSCHEMA_STATISTICS || guidSchema == DBSCHEMA_TABLE_PRIVILEGES || guidSchema == DBSCHEMA_TABLE_STATISTICS || guidSchema == DBSCHEMA_TABLES || guidSchema == DBSCHEMA_TABLES_INFO || guidSchema == DBSCHEMA_VIEWS) return THIRD; else if (guidSchema == DBSCHEMA_KEY_COLUMN_USAGE || guidSchema == DBSCHEMA_TABLE_CONSTRAINTS) return SIXTH; // else return ZERO restrictions return ZERO; } void CSchemaTest::LimitRestrictions(ULONG ulIndex) { // Don't pass restrictions for most schemas, but for those that have a catalog, schema, // or table name limit to current catalog, schema, table. This is done to keep the test // run time shorter. It took several hours on some providers without these restrictions. // Without a catalog restriction ALL catalogs (databases) should be returned. SetRestriction(SchemaCatalogRestriction(ulIndex)); SetRestriction(SchemaSchemaRestriction(ulIndex)); SetRestriction(SchemaTableRestriction(ulIndex)); } // GetValuePtr // Assumptions: All columns are bound LPBYTE CSchemaTest::GetValuePtr(DBORDINAL iOrdinal, LPBYTE pData, DBBINDING * pBinding) { LPBYTE pValue = NULL; DBORDINAL iBind = 0; // If no binding structure passed in assume user wants m_rgDBBINDING if (!pBinding) pBinding = m_rgDBBINDING; if (pBinding) { iBind = iOrdinal - !pBinding[0].iOrdinal - 1; if (STATUS_BINDING(pBinding[iBind], pData) == DBSTATUS_S_OK) { pValue = (LPBYTE)&VALUE_BINDING(pBinding[iBind], pData); } } return pValue; } // Compare histogram rowset columns info BOOL CSchemaTest::CheckHistogramColInfo(IRowset * pIHistogramRowset, DBTYPE wRangeColType, DBORDINAL * pcBinding, DBBINDING ** ppBinding, DBLENGTH * pcbRowSize, HACCESSOR * phAccessor) { HACCESSOR hAccessor = DB_NULL_HACCESSOR; DBLENGTH cbRowSize = 0; BOOL fColInfo = FALSE; DBORDINAL cActualCols = 0; // Count of columns returned in histogram rowset // Save off member vars so we can call CheckAgainstIColumnsInfo() DBBINDING * pBinding = m_rgDBBINDING; DBCOUNTITEM cBinding = m_cDBBINDING; DBCOLUMNINFO * pColInfo = m_rgDBCOLUMNINFO; DBORDINAL cColInfo = m_cDBCOLUMNINFO; LPWSTR pStringsBuf = m_pStringsBuffer; LPWSTR * ppColNames = m_rgColumnNames; DBTYPE * pColTypes = m_rgColumnTypes; ULONG cCols = m_cColumns; m_cDBCOLUMNINFO = 0; m_rgDBCOLUMNINFO = NULL; m_pStringsBuffer = NULL; // Set up pointers to column name and type information m_rgColumnNames = (WCHAR **)rgwszHistogramCols; m_rgColumnTypes = (DBTYPE *)rgtypeHistogramCols; // Set the count of columns and restrictions m_cColumns = cHistogramCols; // Update expected type for RANGE_HI_KEY m_rgColumnTypes[0] = wRangeColType; // get bindings and column info if(!CHECK(GetAccessorAndBindings( pIHistogramRowset, // @parmopt [IN] Rowset to create Accessor for DBACCESSOR_ROWDATA, // @parmopt [IN] Properties of the Accessor &hAccessor, // @parmopt [OUT] Accessor created &m_rgDBBINDING, // @parmopt [OUT] Array of DBBINDINGS &m_cDBBINDING, // @parmopt [OUT] Count of bindings &cbRowSize, // @parmopt [OUT] Length of a row, DATA DBPART_VALUE|DBPART_STATUS |DBPART_LENGTH, ALL_COLS_BOUND, // @parmopt [IN] Which columns will be used in the bindings FORWARD, // @parmopt [IN] Order to bind columns in accessor NO_COLS_BY_REF, // @parmopt [IN] Which column types to bind by reference &m_rgDBCOLUMNINFO, // @parmopt [OUT] Array of DBCOLUMNINFO &m_cDBCOLUMNINFO, // @parmopt [OUT] Count of Columns, also count of ColInfo elements &m_pStringsBuffer, DBTYPE_EMPTY, // @parmopt [IN] Modifier to be OR'd with each binding type. 0, // @parmopt [IN] Used only if eColsToBind = USE_COLS_TO_BIND_ARRAY NULL, // @parmopt [IN] Used only if eColsToBind = USE_COLS_TO_BIND_ARRAY NULL, // @parmopt [IN] Corresponds to what ordinals are specified for each binding, if NO_COLS_OWNED_BY_PROV, // @parmopt [IN] Which columns' memory is to be owned by the provider DBPARAMIO_NOTPARAM, // @parmopt [IN] Parameter kind specified for all bindings BLOB_LONG, // @parmopt [IN] how to bind BLOB Columns NULL),S_OK)) // @parmopt [OUT] returned status array from CreateAccessor goto CLEANUP; fColInfo = CheckAgainstIColumnsInfo(); // CheckAgainstIColumnsInfo doesn't test for any extra columns, so warn here // if there are extras cActualCols = m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal; // Check for extra columns in histogram rowset. This is only a warning // since it's allowed to return extra columns. Cache the warning so we don't // get it for every histogram over and over. CCOMPARE(m_EC, cHistogramCols == cActualCols, EC_EXTRA_COLUMN, L"Extra column in Histogram rowset.", TRUE); CLEANUP: // Populate output params if (pcBinding) *pcBinding = m_cDBCOLUMNINFO; if (ppBinding) *ppBinding = m_rgDBBINDING; else SAFE_FREE(m_rgDBBINDING); if (pcbRowSize) *pcbRowSize = cbRowSize; if (phAccessor) *phAccessor = hAccessor; SAFE_FREE(m_rgDBCOLUMNINFO); SAFE_FREE(m_pStringsBuffer); // Restore member vars to avoid side effects m_rgDBBINDING = pBinding; m_cDBBINDING = cBinding; m_rgDBCOLUMNINFO= pColInfo; m_cDBCOLUMNINFO = cColInfo; m_pStringsBuffer= pStringsBuf; m_rgColumnNames = ppColNames; m_rgColumnTypes = pColTypes; m_cColumns = cCols; return fColInfo; } DBCOUNTITEM CSchemaTest::Cardinality(LPWSTR pwszTableName, ULONG ulColIndex, CARDINALITY eCardinality, DBBINDING * pStartBind, DBBINDING * pEndBind, LPBYTE pDataRows, DBLENGTH cbRowSize) { HRESULT hr = S_OK; ULONG ulIndexFirst = 0; size_t cChars = 0; LPWSTR pwszColList = NULL; LPWSTR pwszSelectFmt = (LPWSTR)wszSELECT_DISTINCTCOLLIST; LPWSTR pwszSelect = NULL; LPWSTR pwszGreaterFmt = L"%s > ?"; LPWSTR pwszLessThanEqFmt = L"%s <= ?"; LPWSTR pwszEqFmt = L"%s = ?"; LPWSTR pwszRange = NULL; DBCOUNTITEM ulCardinality = 0; IRowset * pIRowset = NULL; IAccessor * pIAccessor = NULL; ICommand * pICommand = NULL; IAccessor * pICmdAccessor = NULL; DBBINDING dbCountBind; DBBINDING dbParamBind[2]; // Only two params required for all cases ULONG cParams = 0; HACCESSOR hAcc = DB_NULL_HACCESSOR; HACCESSOR hParamAcc = DB_NULL_HACCESSOR; HROW * phRows = NULL; ULONG * pulCardinality = NULL; DBORDINAL iCol; DBCOUNTITEM cRowsObtained; DBPARAMS dbParams; DBBINDSTATUS rgStatus[2]; // Previously used the count aggregate function, but that was bad because: // 1) Doesn't include NULL rows // 2) Fails against GUID column on some providers. // select count(*) from (select distinct col1,col2 from where col1 > ? and // col1 <= ?) t1 // Now we use just the select distinct, but this still will fail for BLOB columns, // so we have to avoid calling this function for BLOBS. // TODO: If this function is made more sophisticated we can actually call for BLOBS. // Possible improvements 1) Use conversion function, 2) actually retrieve data // ourselves and count distinct values. // select distinct col1,col2 from
where col1 > ? and col1 <= ? // Initialize binding structures memset(&dbCountBind, 0, sizeof(DBBINDING)); memset(&dbParamBind, 0, sizeof(DBBINDING)*2); // Initialize dbParams memset(&dbParams, 0, sizeof(DBPARAMS)); // Note we use params for this to avoid having to convert range limits to strings and // obtain the appropriate literal prefix and suffix. I am assuming that any provider // that has gone to the trouble to provide extensive support for query processors has // also supported parameters. switch (eCardinality) { // Both range rows and eq rows are non-distinct, and all the cardinalities // for histogram are for only one column. But they all need a 'where' clause case EQ_ROWS_CARDINALITY: // We don't have a range for this cardinality, we're only looking for // values equal to RANGE_HIGH_KEY ASSERT(!pStartBind); // Fall through case RANGE_ROWS_CARDINALITY: // Both of these counts are non-distinct, so change our select // clause to not return distinct counts. pwszSelectFmt = (LPWSTR)wszSELECT_COLLISTFROMTBL; // Fall through case DISTINCT_RANGE_ROWS_CARDINALITY: { size_t cchWhere = wcslen(wszWHERE); // Length of " where " size_t cchColName = wcslen(m_prgColInfo[ulColIndex].pwszName); LPWSTR pwszFmt = pwszLessThanEqFmt; if (eCardinality == EQ_ROWS_CARDINALITY) pwszFmt = pwszEqFmt; // Fill out param info if (pStartBind) { cchWhere += wcslen(pwszGreaterFmt) -2 + cchColName + wcslen(wszAND); // Set parameter binding info memcpy(&dbParamBind[cParams], pStartBind, sizeof(DBBINDING)); dbParamBind[cParams].eParamIO = DBPARAMIO_INPUT; dbParamBind[cParams].iOrdinal = cParams+1; cParams++; } if (pEndBind) { cchWhere += wcslen(pwszFmt) -2 + cchColName; // Set parameter binding info memcpy(&dbParamBind[cParams], pEndBind, sizeof(DBBINDING)); dbParamBind[cParams].eParamIO = DBPARAMIO_INPUT; dbParamBind[cParams].iOrdinal = cParams+1; cParams++; } // Now we know all the pieces for the range clause, allocate memory and create SAFE_ALLOC(pwszRange, WCHAR, cchWhere+1); wcscpy(pwszRange, wszWHERE); // Put in the starting range clause if (pStartBind) { swprintf(pwszRange+wcslen(pwszRange), pwszGreaterFmt, m_prgColInfo[ulColIndex].pwszName); wcscat(pwszRange, wszAND); } // Put in ending range clause (always needed) swprintf(pwszRange+wcslen(pwszRange), pwszFmt, m_prgColInfo[ulColIndex].pwszName); } // Fall through case COLUMN_CARDINALITY: ulIndexFirst = ulColIndex; // Fall through case TUPLE_CARDINALITY: // Compute memory for column list (column name plus comma) for (iCol = 0; iCol < ulColIndex-ulIndexFirst+1; iCol++) cChars+=wcslen(m_prgColInfo[iCol+ulIndexFirst].pwszName)+1; // Allocate memory for col list SAFE_ALLOC(pwszColList, WCHAR, cChars+1); // Fill col list // Note we leave out BLOB cols because providers can't do a // select distinct on a BLOB, which may have some impact on // the cardinality results. pwszColList[0] = L'\0'; for (iCol = 0; iCol < ulColIndex-ulIndexFirst+1; iCol++) { if (m_prgColInfo[iCol+ulIndexFirst].dwFlags & DBCOLUMNFLAGS_ISLONG) continue; // Put in comma separator if needed if (pwszColList[0]) wcscat(pwszColList, L","); wcscat(pwszColList, m_prgColInfo[iCol+ulIndexFirst].pwszName); } // Compute memory required for select distinct statement // Length of select, 2 parenthesis, table name, table alias name cChars+=wcslen(pwszSelectFmt)+wcslen(pwszTableName); // Add space for 'where' clause if needed if (pwszRange) cChars+=wcslen(pwszRange); // Allocate mem for select SAFE_ALLOC(pwszSelect, WCHAR, cChars+1); // select distinct col1,col2 from
swprintf(pwszSelect, pwszSelectFmt, pwszColList, pwszTableName); // Tack on where clause if needed if (pwszRange) wcscat(pwszSelect, pwszRange); // Free the range clause SAFE_FREE(pwszRange); break; case TABLE_CARDINALITY: pwszSelectFmt = (LPWSTR)wszSELECT_ALLFROMTBL; cChars+=wcslen(pwszSelectFmt)+wcslen(pwszTableName); // Allocate mem for select SAFE_ALLOC(pwszSelect, WCHAR, cChars+1); // Create select stmt swprintf(pwszSelect, pwszSelectFmt, pwszTableName); break; } // Execute the command if (cParams) { // Get the command object for the table object pICommand = m_pTable->get_ICommandPTR(); // Addref the command object so we can release later. pICommand->AddRef(); // Get accessor interface TESTC(VerifyInterface(pICommand, IID_IAccessor, COMMAND_INTERFACE, (IUnknown **)&pICmdAccessor)); // Create the parameter accessor TESTC_(pICmdAccessor->CreateAccessor(DBACCESSOR_PARAMETERDATA, cParams, dbParamBind, cbRowSize, &hParamAcc, rgStatus), S_OK); // Fill DBPARAMS info dbParams.pData = pDataRows; dbParams.cParamSets = 1; dbParams.hAccessor = hParamAcc; } if (!CHECK(m_pTable->BuildCommand(pwszSelect, IID_IRowset, EXECUTE_IFNOERROR, 0, NULL, &dbParams, NULL, (IUnknown **)&pIRowset, &pICommand), S_OK)) goto CLEANUP; // Get accessor and bindings dbCountBind.obStatus = offsetof(DATA, sStatus); dbCountBind.obLength = offsetof(DATA, ulLength); dbCountBind.obValue = offsetof(DATA, bValue); dbCountBind.wType = DBTYPE_UI4; dbCountBind.iOrdinal = 1; dbCountBind.dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS; TESTC(VerifyInterface(pIRowset, IID_IAccessor, ROWSET_INTERFACE, (IUnknown **)&pIAccessor)); TESTC_(pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 1, &dbCountBind, 0, &hAcc, NULL), S_OK); // Count the rows while(hr != DB_S_ENDOFROWSET) { TEST2C_(hr = pIRowset->GetNextRows(NULL, 0, 10000, &cRowsObtained, &phRows), S_OK, DB_S_ENDOFROWSET); if (hr == S_OK) { TESTC(cRowsObtained); } ulCardinality+=cRowsObtained; if (cRowsObtained) { CHECK(pIRowset->ReleaseRows(cRowsObtained, phRows, NULL, NULL, NULL), S_OK); *phRows = DB_NULL_HROW; } } CLEANUP: // Release rows if (pIRowset && phRows && *phRows != DB_NULL_HROW) CHECK(pIRowset->ReleaseRows(cRowsObtained, phRows, NULL, NULL, NULL), S_OK); // Release parameter accessor if (pICmdAccessor && hParamAcc != DB_NULL_HACCESSOR) CHECK(pICmdAccessor->ReleaseAccessor(hParamAcc, NULL), S_OK); SAFE_FREE(phRows); SAFE_FREE(pwszColList); SAFE_FREE(pwszSelect); SAFE_RELEASE(pICommand); SAFE_RELEASE(pIRowset); SAFE_RELEASE(pIAccessor); SAFE_RELEASE(pICmdAccessor); return ulCardinality; } void CSchemaTest::SetRowCount(ROW_COUNT eRowCount, DBORDINAL ulRowCount) { m_eRowCount = eRowCount; m_ulRowCount = ulRowCount; } HRESULT CSchemaTest::GetNextRows(DBROWOFFSET lOffset, DBROWCOUNT cRows, DBCOUNTITEM* pcRowsObtained, HROW** prghRows) { ASSERT(prghRows); TBEGIN DBCOUNTITEM cRowsObtained = 0; DBCOUNTITEM i=0; //Record if we passed in consumer allocated array... HROW* rghRowsInput = *prghRows; //GetNextRows HRESULT hr = m_pIRowset->GetNextRows(NULL, lOffset, cRows, &cRowsObtained, prghRows); //Verify Correct values returned if(SUCCEEDED(hr)) { if(hr == S_OK) { TESTC(cRowsObtained==(DBCOUNTITEM)ABS(cRows)); } else { TESTC(cRowsObtained < (DBCOUNTITEM)ABS(cRows)); } //Verify row array for(i=0; i 0, TRUE); } } // HACK FOR ORACLE if (pwszSch && wcslen(pwszSch) == 0) pwszSch = NULL; // Now we have either NULL or valid pointers to catalog, schema, table names TESTC_(m_pTable->GetQualifiedName(pwszCat, pwszSch, pwszTable,&pwszQualifiedName, TRUE), S_OK); // If we already have information for this table then just don't bother if (m_pwszTableName && !wcscmp(pwszQualifiedName, m_pwszTableName)) { m_ulTableOrdinal++; // If we couldn't actually retrieve the colinfo for this table then // return S_FALSE if (!m_prgColInfo) return S_FALSE; // Otherwise return success else return S_OK; } // Copy the table name into member var SAFE_FREE(m_pwszTableName); m_pwszTableName = pwszQualifiedName; // Initialize out params m_ulTableOrdinal = 1; // Note that schema rowset never reports bookmarks SAFE_FREE(m_prgColInfo); SAFE_FREE(m_pwszStringsBuffer); // Get IOpenRowset interface TESTC(VerifyInterface(m_pThisTestModule->m_pIUnknown2, IID_IOpenRowset, SESSION_INTERFACE, (IUnknown**)&pIOpenRowset)); // Create DBID from table name dbid.eKind = DBKIND_NAME; dbid.uName.pwszName = m_pwszTableName; // Call OpenRowset hr = pIOpenRowset->OpenRowset(NULL, &dbid, NULL, IID_IColumnsInfo, 0, NULL, (IUnknown **)&pIColumnsInfo); if (FAILED(hr)) odtLog << m_pwszTableName << L": Unable to open table.\n"; // It's possible the table was deleted between the time we called GetRowset and attempting // to open the table, so we have to allow DB_E_NOTABLE, but post a warning. switch(hr) { case DB_E_NOTABLE: case DB_SEC_E_PERMISSIONDENIED: TESTW_(hr, S_OK); goto CLEANUP; default: TESTC_(hr, S_OK); } // Make sure we've got a valid interface ptr TESTC(pIColumnsInfo != NULL); // Now call GetColumnInfo. We already know cColumns so no need to return in member // var. TESTC_(hr = pIColumnsInfo->GetColumnInfo(&m_cColInfo, &m_prgColInfo, &m_pwszStringsBuffer), S_OK); CLEANUP: SAFE_RELEASE(pIOpenRowset); SAFE_RELEASE(pIColumnsInfo); return hr; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Module Values // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // {{ TCW_MODULE_GLOBALS DECLARE_MODULE_CLSID = { 0x4ace5741, 0x13bb, 0x11cf, { 0x89, 0x0f, 0x00, 0xaa, 0x00, 0xb5, 0xa9, 0x1b }}; DECLARE_MODULE_NAME("IDBSchemaRowset"); DECLARE_MODULE_OWNER("Microsoft"); DECLARE_MODULE_DESCRIP("test module for IDBSchemaRowset"); DECLARE_MODULE_VERSION(795921705); // TCW_WizardVersion(2) // TCW_Automation(True) // }} TCW_MODULE_GLOBALS_END //-------------------------------------------------------------------- // @func Initialises up indexes, Primary and Foreign keys on the primary table. // Should call TerminateKeysOnTable() upon failure of InitKeysOnTable or completion of test. // // Global values set. g_fPrimaryKey (TRUE if Primary key is available on the table). // g_fForeignKey (TRUE if Foreign key is available on the table). // g_fIndexes (TRUE if indexes are available on the table.) // g_pExtraTable Creates it. // BOOL CSchemaTest::InitKeysOnTable() { CCol TempCol1, TempCol2; LONG lrand1 =0; LONG lrand2 =0; LONG lrand3 =0; ULONG i; BOOL fSuccess = FALSE; ICommand * pICmd = NULL; IDBCreateCommand * pIDBCrtCmd = (IDBCreateCommand *)m_pThisTestModule->m_pIUnknown2; // Create the second table. g_pKeyTable1 = new CTable(pIDBCrtCmd, (LPWSTR)gwszModuleName, NONULLS); if (!g_pKeyTable1) { odtLog << wszMemoryAllocationError; return FALSE; } g_pKeyTable2 = new CTable(pIDBCrtCmd, (LPWSTR)gwszModuleName, NONULLS); if (!g_pKeyTable2) { odtLog << wszMemoryAllocationError; // g_pKeyTable1 will be cleaned up in TerminateKeysOnTable(); return FALSE; } if (FAILED(g_pKeyTable2->CreateTable(0))) goto CLEANUP; if (FAILED(g_pKeyTable1->CreateTable(0))) goto CLEANUP; // Now alter the tables to create Primary keys and foreign keys. for (i = 1; i <= g_pKeyTable1->CountColumnsOnTable(); i++) { if (FAILED(g_pKeyTable1->GetColInfo(i, TempCol1))) goto CLEANUP; // if it is not a long column and is fixed length We found our candidate for Primary and Foreign Key. if (!TempCol1.GetIsLong() && !TempCol1.GetNullable()) // Primary keys typically can't be nullable columns { fSuccess = TRUE; break; } } if (! fSuccess ) goto CLEANUP; fSuccess = FALSE; for (i = 1; i <= g_pKeyTable2->CountColumnsOnTable(); i++) { if (FAILED(g_pKeyTable2->GetColInfo(i, TempCol2))) goto CLEANUP; // if it is not a long column and is fixed length We found our candidate for Primary and Foreign Key. if (// (TempCol2.GetProviderType() == DBTYPE_STR) && !(TempCol2.GetIsLong()) && !TempCol2.GetNullable()) // Primary keys typically can't be nullable columns { fSuccess = TRUE; break; } } if (! fSuccess ) goto CLEANUP; // Now alloc space for the strings. g_pwszAddPrimaryKeyOnTable1 = (WCHAR *)PROVIDER_ALLOC( (wcslen(g_wszAddPrimaryKey)*sizeof (WCHAR)) + sizeof (WCHAR) + (wcslen(g_pKeyTable1->GetTableName())*sizeof (WCHAR)) + 2 * (wcslen(TempCol1.GetColName())*sizeof (WCHAR)) + 20 // Extra space for the KeyNumber (Random number). ); if (!g_pwszAddPrimaryKeyOnTable1) { odtLog << wszMemoryAllocationError; goto CLEANUP; } g_pwszAddPrimaryKeyOnTable2 = (WCHAR *)PROVIDER_ALLOC( (wcslen(g_wszAddPrimaryKey)*sizeof (WCHAR)) + sizeof (WCHAR) + (wcslen(g_pKeyTable2->GetTableName())*sizeof (WCHAR)) + 2 * (wcslen(TempCol2.GetColName())*sizeof (WCHAR)) + 20 // Extra space for the KeyNumber (Random number). ); if (!g_pwszAddPrimaryKeyOnTable2) { odtLog << wszMemoryAllocationError; goto CLEANUP; } g_pwszAddForeignKeyOnTable1 = (WCHAR *)PROVIDER_ALLOC( (wcslen(g_wszAddForeignKey)*sizeof (WCHAR)) + sizeof (WCHAR) + (wcslen(g_pKeyTable1->GetTableName())*sizeof (WCHAR)) + 2 * (wcslen(TempCol1.GetColName())*sizeof (WCHAR)) + (wcslen(g_pKeyTable1->GetTableName())*sizeof (WCHAR)) + (wcslen(TempCol1.GetColName())*sizeof (WCHAR)) + 20 // Extra space for the KeyNumber (Random number). ); if (!g_pwszAddForeignKeyOnTable1) { odtLog << wszMemoryAllocationError; goto CLEANUP; } g_pwszDropPrimaryKeyConstraint1 = (WCHAR *)PROVIDER_ALLOC( (wcslen(g_wszDropPrimaryKeyConstraint)*sizeof (WCHAR)) + sizeof (WCHAR) + (wcslen(g_pKeyTable1->GetTableName())*sizeof (WCHAR)) + (wcslen(TempCol1.GetColName())*sizeof (WCHAR)) + 20 // Extra space for the KeyNumber (Random number). ); if (!g_pwszDropPrimaryKeyConstraint1) { odtLog << wszMemoryAllocationError; goto CLEANUP; } g_pwszDropPrimaryKeyConstraint2 = (WCHAR *)PROVIDER_ALLOC( (wcslen(g_wszDropPrimaryKeyConstraint)*sizeof (WCHAR)) + sizeof (WCHAR) + (wcslen(g_pKeyTable2->GetTableName())*sizeof (WCHAR)) + (wcslen(TempCol2.GetColName())*sizeof (WCHAR)) + 20 // Extra space for the KeyNumber (Random number). ); if (!g_pwszDropPrimaryKeyConstraint2) { odtLog << wszMemoryAllocationError; goto CLEANUP; } g_pwszDropForeignKeyConstraint1 = (WCHAR *)PROVIDER_ALLOC( (wcslen(g_wszDropForeignKeyConstraint)*sizeof (WCHAR)) + sizeof (WCHAR) + (wcslen(g_pKeyTable1->GetTableName())*sizeof (WCHAR)) + (wcslen(TempCol1.GetColName())*sizeof (WCHAR)) + 20 // Extra space for the KeyNumber (Random number). ); if (!g_pwszDropForeignKeyConstraint1) { odtLog << wszMemoryAllocationError; goto CLEANUP; } // Add primary key on Table 1. swprintf(g_pwszAddPrimaryKeyOnTable1, g_wszAddPrimaryKey, g_pKeyTable1->GetTableName(), (lrand1 = GetLongRandomNumber()), TempCol1.GetColName(), TempCol1.GetColName()); // Add primary key on table 2. swprintf(g_pwszAddPrimaryKeyOnTable2, g_wszAddPrimaryKey, g_pKeyTable2->GetTableName(), (lrand2 = GetLongRandomNumber()), TempCol2.GetColName(), TempCol2.GetColName()); // Add foriegn key on table 1. (from table 2). swprintf(g_pwszAddForeignKeyOnTable1, g_wszAddForeignKey, g_pKeyTable1->GetTableName(), (lrand3 = GetLongRandomNumber()), TempCol1.GetColName(), TempCol1.GetColName(), g_pKeyTable2->GetTableName(), TempCol2.GetColName() ); // Drop primary key on table 1. swprintf(g_pwszDropPrimaryKeyConstraint1, g_wszDropPrimaryKeyConstraint, g_pKeyTable1->GetTableName(), lrand1, TempCol1.GetColName()); // Drop primary key on table 2. swprintf(g_pwszDropPrimaryKeyConstraint2, g_wszDropPrimaryKeyConstraint, g_pKeyTable2->GetTableName(), lrand2, TempCol2.GetColName()); // Drop the foreign key on table 1. swprintf(g_pwszDropForeignKeyConstraint1, g_wszDropForeignKeyConstraint, g_pKeyTable1->GetTableName(), lrand3, TempCol1.GetColName()); pICmd = g_pKeyTable1->get_ICommandPTR(); // If we don't already have a primary key on the table if (!g_pKeyTable1->GetPrimaryKeyColumn()) { if( !CHECK(g_pKeyTable1->BuildCommand(g_pwszAddPrimaryKeyOnTable1, // SQL STMT IID_NULL, EXECUTE_ALWAYS, NULL, NULL, NULL, NULL, NULL, &pICmd), S_OK) ) goto CLEANUP; // Set m_fKeyOnTable to Success so that we can drop them.(even if One constraint goes through). g_fKeysOnTable = TRUE; } else m_fPrimaryKey = TRUE; // There should be a minimum of one row in PRIMARY_KEYS rowset pICmd = g_pKeyTable2->get_ICommandPTR(); // If we don't already have a primary key on the table if (!g_pKeyTable2->GetPrimaryKeyColumn()) { TESTC_(g_pKeyTable2->BuildCommand(g_pwszAddPrimaryKeyOnTable2, // SQL STMT IID_NULL, EXECUTE_ALWAYS, NULL, NULL, NULL, NULL, NULL, &pICmd), S_OK); } m_fPrimaryKey = TRUE; // There should be a minimum of one row in PRIMARY_KEYS rowset pICmd = g_pKeyTable2->get_ICommandPTR(); TESTC_(g_pKeyTable1->BuildCommand(g_pwszAddForeignKeyOnTable1, // SQL STMT IID_NULL, EXECUTE_ALWAYS, NULL, NULL, NULL, NULL, NULL, &pICmd), S_OK); m_fForeignKey = TRUE; // There should be a minimum of one row in FOREIGN_KEYS rowset // Now we add rows. // First add rows in 2nd Table and then on 1st table. // Start with a table with 1 rows if (FAILED(g_pKeyTable2->Insert(1))) goto CLEANUP; if (FAILED(g_pKeyTable1->Insert(1))) goto CLEANUP; fSuccess = TRUE; CLEANUP: if (!fSuccess) { // CLEANUP memory incase of failure. PROVIDER_FREE(g_pwszAddPrimaryKeyOnTable1); PROVIDER_FREE(g_pwszAddPrimaryKeyOnTable2); PROVIDER_FREE(g_pwszAddForeignKeyOnTable1); PROVIDER_FREE(g_pwszDropPrimaryKeyConstraint1); PROVIDER_FREE(g_pwszDropPrimaryKeyConstraint2); PROVIDER_FREE(g_pwszDropForeignKeyConstraint1); } return fSuccess; } //-------------------------------------------------------------------- // @func Drops Key constraintes, indexes etc, created in InitKeysOnTable() // Drops the extra table after dropping the constraints. BOOL CSchemaTest::TerminateKeysOnTable() { // Drop the constraints. ICommand * pICmd = NULL; if (g_fKeysOnTable) { // We still need to flag an error if the Drop constraint fails. pICmd = g_pKeyTable1->get_ICommandPTR(); CHECK(g_pKeyTable1->BuildCommand(g_pwszDropPrimaryKeyConstraint1, // SQL STMT IID_NULL, EXECUTE_ALWAYS, NULL, NULL, NULL, NULL, NULL, &pICmd), S_OK); CHECK(g_pKeyTable1->BuildCommand(g_pwszDropForeignKeyConstraint1, // SQL STMT IID_NULL, EXECUTE_ALWAYS, NULL, NULL, NULL, NULL, NULL, &pICmd), S_OK); CHECK(g_pKeyTable2->BuildCommand(g_pwszDropPrimaryKeyConstraint2, // SQL STMT IID_NULL, EXECUTE_ALWAYS, NULL, NULL, NULL, NULL, NULL, &pICmd), S_OK); } if (g_pKeyTable1) { // remove table from database (g_pKeyTable1)->DropTable(); // delete CTable object delete g_pKeyTable1; g_pKeyTable1 = NULL; } if (g_pKeyTable2) { // remove table from database (g_pKeyTable2)->DropTable(); // delete CTable object delete g_pKeyTable2; g_pKeyTable2 = NULL; } // CLEANUP memory incase of failure. PROVIDER_FREE(g_pwszAddPrimaryKeyOnTable1); PROVIDER_FREE(g_pwszAddPrimaryKeyOnTable2); PROVIDER_FREE(g_pwszAddForeignKeyOnTable1); PROVIDER_FREE(g_pwszDropPrimaryKeyConstraint1); PROVIDER_FREE(g_pwszDropPrimaryKeyConstraint2); PROVIDER_FREE(g_pwszDropForeignKeyConstraint1); return TRUE; } //-------------------------------------------------------------------- // @func Module level initialization routine // // @rdesc Success or Failure // @flag TRUE | Successful initialization // @flag FALSE | Initialization problems // BOOL ModuleInit(CThisTestModule * pThisTestModule) { HRESULT hr; // Need to initialize these in ModuleInit to make sure they get reset if test is // run against two providers. g_fKeysOnTable=FALSE; g_pIDBSchemaRowset=NULL; g_fKagera = FALSE; g_fSQLServer = FALSE; cSchemas=0; rgSchemas=NULL; rgRestrictions=NULL; // Get connection and session objects if (ModuleCreateDBSession(pThisTestModule)) { LPWSTR pwszName=NULL; g_fKagera = IsMSDASQL(); // Needed for ExtraLib g_pIDBInitialize = (IDBInitialize *)pThisTestModule->m_pIUnknown; // Fail gracefully and quit module if we don't support IDBSchemaRowset if (FAILED(hr = pThisTestModule->m_pIUnknown2->QueryInterface( IID_IDBSchemaRowset,(void **)&g_pIDBSchemaRowset))) { // Make sure we returned E_NOINTERFACE if we've failed if (pThisTestModule->m_pError->Validate(hr, LONGSTRING(__FILE__), __LINE__, E_NOINTERFACE)) odtLog << L"IDBSchemaRowset is not supported.\n"; return TEST_SKIPPED; } // Get the name of the backend GetProperty(DBPROP_DBMSNAME, DBPROPSET_DATASOURCEINFO, pThisTestModule->m_pIUnknown, &pwszName); if (pwszName) { if (!wcscmp(pwszName, L"Microsoft SQL Server")) g_fSQLServer = TRUE; } SAFE_FREE(pwszName); // Just Print out What is Supported if (FAILED(g_pIDBSchemaRowset->GetSchemas(&cSchemas, &rgSchemas, &rgRestrictions))) { SAFE_RELEASE(g_pIDBSchemaRowset); return FALSE; } for(ULONG index=0; indexm_pVoid = new CTable( (IUnknown *)pThisTestModule->m_pIUnknown2,(LPWSTR)gwszModuleName); if (!pThisTestModule->m_pVoid) { odtLog << wszMemoryAllocationError; return FALSE; } // Start with a table with 30 rows if (!CHECK(((CTable *)pThisTestModule->m_pVoid)->CreateTable(30), S_OK)) return FALSE; return TRUE; } return FALSE; } //-------------------------------------------------------------------- // @func Module level termination routine // // @rdesc Success or Failure // @flag TRUE | Successful initialization // @flag FALSE | Initialization problems // BOOL ModuleTerminate(CThisTestModule * pThisTestModule) { // We still own the table since all of our testcases // have only used it and not deleted it. if (pThisTestModule->m_pVoid) { // Remove table from database ((CTable *)pThisTestModule->m_pVoid)->DropTable(); // Delete CTable object delete (CTable*)pThisTestModule->m_pVoid; pThisTestModule->m_pVoid = NULL; } SAFE_RELEASE(g_pIDBSchemaRowset); SAFE_FREE(rgSchemas); SAFE_FREE(rgRestrictions); return ModuleReleaseDBSession(pThisTestModule); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Helper classes // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class CHelper { protected: CTable * m_pTable; GUID m_guidSchema; SchemaList * m_pSchemaInfo; CSchemaTest * m_pCSchemaTest; BOOL m_fPassUnsupportedRestrictions; BOOL m_fUseCommonArgumentDefaults; BOOL m_fSupported; // Is this schema supported? ULONG m_ulRestrictionSupport; DBORDINAL m_ulRowCount; ROW_COUNT m_eRowCount; LPWSTR m_pwszCatalogRestriction; LPWSTR m_pwszSchemaName; ULONG_PTR m_ulNullCollation; DBCOUNTITEM m_cTotalRows; // @cmember Count of columns in rowset DBORDINAL m_cDBCOLUMNINFO; // @cmember Array of column information in rowset DBCOLUMNINFO * m_rgDBCOLUMNINFO; // @cmember String buffer for column info LPWSTR m_pStringsBuffer; // @cmember Array of column information in rowset DBCOLUMNINFO * m_rgDBCOLUMNINFO_Prev; // @cmember String buffer for column info LPWSTR m_pStringsBuffer_Prev; // @cmember Count of columns in rowset DBCOUNTITEM m_cDBCOLUMNINFO_Prev; // @cmember Count of Bindings DBCOUNTITEM m_cDBBINDING; // @cmember Array of Bindings DBBINDING * m_rgDBBINDING; // Bitmask of which restrictions are requested RESTRICTIONS m_restrict; // @cmember Count of restrictions ULONG m_cRestrict; // All cached restrictions VARIANT m_rgRestrict[MAXRESTRICTION]; // Valid restrictions for this schema VARIANT m_rgRestrictValid[MAXRESTRICTION]; // Restrictions for this schema VARIANT m_rgRestrictUsed[MAXRESTRICTION]; // Track actual restriction array used VARIANT * m_prgRestrictUsed; ULONG m_cRestrictionsUsed; // @cmember Rowset pointer IRowset * m_pIRowset; // Do I want to capture restrictions only BOOL m_fCaptureRestrictions; BOOL m_fCaptured; // Pointer to current row of schema LPBYTE m_pRow; // Pointer to previous row of schema used to verify sorting/ordinals LPBYTE m_pRowPrev; // IDBSchemaRowset interface pointer to use IDBSchemaRowset * m_pIDBSchemaRowset; // Row to use for restrictions DBCOUNTITEM m_ulRestrictRow; // Column ordinal to use for restriction ULONG m_iRestrict; enum RESTRICT_ARRAY m_eRestrictArray; LPWSTR m_pwszTableName; ULONG m_ulTableOrdinal; DBCOLUMNINFO * m_prgColInfo; LPWSTR m_pwszStringsBuffer; DBORDINAL m_cColInfo; CErrorCache m_ECHelper; // Error cache ULONG m_ulSchemaVersion; ULONG m_ulOLEDBVer; // Helper functions HRESULT GetColumnInfo(LPBYTE pData, DBBINDING * pBinding); BOOL FillRestrictions(DBCOUNTITEM iRow, LPBYTE pData); LPWSTR GetRestrictionName(ULONG iRestrict); RESTRICT_CAT GetRestrictCat(ULONG iRestrict); ULONG GetLiteralMaxSize(DBLITERAL eLiteral); // Function to create at least two rows in schema, so sorting test will actually test something. // It's possible this function may just return TRUE if we know the schema already has many rows. virtual BOOL InsertRows(void) {return TRUE;} // Function to pick a row from the schema and use values from that row for restrictions BOOL GetRestrictions(ULONG iRestrict); BOOL IsRestricted(ULONG iRestrict); // Row verification functions BOOL CheckAgainstIColumnsInfo(SchemaList * pSchemaInfo); BOOL VerifyRowset(IRowset * pIRowset); LPBYTE GetValuePtr(DBORDINAL iOrdinal, LPBYTE pData, DBBINDING * pBinding = NULL); void GetVersionInfo(IDBInitialize * pIDBInit); BOOL VerifyRowCommon(DBCOUNTITEM iRow, BYTE * pData); BOOL VerifySort(DBCOUNTITEM iRow, BYTE * pData); BOOL VerifyValidTable(DBCOUNTITEM iRow, LPBYTE pData); BOOL VerifyColumnCommon(DBORDINAL iOrdinal, DATA * pColumn); virtual BOOL VerifyRestriction(DBORDINAL iOrdinal, DATA * pColumn); BOOL VerifyLength(DBORDINAL iOrdinal, DATA * pColumn); BOOL VerifyTypeSpecific(DBORDINAL iOrdinal, DATA * pColumn); virtual BOOL VerifyValue(DBORDINAL iOrdinal, DATA * pColumn); BOOL VerifyNull(DBORDINAL iOrdinal, DATA * pColumn); BOOL VerifyNonEmptyString(DATA * pColumn, LPWSTR pwszTable, LPWSTR pwszColumn); BOOL VerifyColumnMatch(DBORDINAL iOrdinal1, DBORDINAL iOrdinal2); // Schema-specific validation virtual BOOL VerifyColumn(DBORDINAL iOrdinal, DATA * pColumn) {return TRUE;} virtual BOOL CompareNull(DBORDINAL iOrdinal) { if (!COMPARE(m_pSchemaInfo->pColList[iOrdinal-1].fAllowNull, TRUE)) { odtLog << L"Column " << m_pSchemaInfo->pColList[iOrdinal-1].pwszName << L" was NULL.\n"; return FALSE; } return TRUE; } public: CHelper(void); virtual ~CHelper(void); virtual BOOL Init(CSchemaTest * pThis); virtual BOOL CreateCheckConstraints(void); virtual BOOL CreateStoredProcs(void); virtual LPWSTR CreateObject(UINT idsObject, LPWSTR pwszObjectName = NULL); virtual BOOL VerifyObject(UINT idsObject); virtual BOOL VerifyObjectValue(UINT idsObject, ULONG iOrdinal); BOOL CheckResults(HRESULT hr, REFIID iid, IUnknown * pIUnknown); HRESULT GetNextRows(DBROWOFFSET lOffset, DBROWCOUNT cRows, DBCOUNTITEM* pcRowsObtained, HROW** prghRows); BOOL IsSupported(void); void UseArgumentDefaults(BOOL fUseDefaults) {m_fUseCommonArgumentDefaults = fUseDefaults;} GUID GetSchema(void) {return m_guidSchema;} LPWSTR GetCatalogName(); HRESULT GetRowsetHelper ( IUnknown * pIUnknown = NULL, ULONG cRestrictions = RV_ALL, VARIANT * prgRestrictions = NULL, REFIID riid = IID_IRowset, ULONG cPropertySets = 0, DBPROPSET rgPropertySets[] = NULL, IUnknown ** ppRowset = NULL, GUID guidSchema = GUID_NULL, BOOL fFreeRowset = TRUE ); BOOL HasUnsupportedRestriction(void); BOOL IsSupportedRestriction(ULONG iRestrict); void ClearRestrictions(VARIANT * prgVariant = NULL); BOOL GetValidColumnValues(DBORDINAL iOrdinal, ULONG * pcValidValues, LPVOID * ppValidValues); BOOL SetValidColumnValues(DBORDINAL iOrdinal, ULONG cValidValues, LPVOID pValidValues); void SetValidRestriction(ULONG iRestrict); void SetEmptyRestrict(ULONG iRestrict); void SetRestriction(ULONG iRestrict); BOOL SetRestriction(ULONG iRestrict, LPVOID pValue); BOOL SetRestriction(ULONG iRestrict, LPVOID pValue, DBTYPE wType); BOOL SetRestriction(ULONG iRestrict, VARIANT * pVariant); BOOL SetInvalidRestriction(ULONG iRestrict, LPVOID pValue, DBTYPE wType); void SetRestrictionType(ULONG iRestrict, DBTYPE wType); ULONG RestrictionCount(void) {return m_pSchemaInfo->cRestrictions;} void SetRestrictionArray(enum RESTRICT_ARRAY eRestrictArray) {m_eRestrictArray = eRestrictArray;} VARIANT * GetRestrictPtr(ULONG iRestrict); ULONG GetRestrictionMaxLength(ULONG iRestrict); void SetRowCount(ROW_COUNT eRowCount, DBORDINAL ulRowCount); int TestRestriction(ULONG iRestrict); // Obsolete functions void SetRestrictions(ULONG ulRestrict) {m_restrict = ulRestrict;} }; CHelper::CHelper(void) { m_pTable = NULL; m_guidSchema = GUID_NULL; m_pSchemaInfo = NULL; m_fPassUnsupportedRestrictions = FALSE; m_fUseCommonArgumentDefaults = TRUE; m_fSupported = FALSE; m_ulRestrictionSupport = 0; m_ulRowCount = 1; // By default we will require at least one row back from schema m_pwszCatalogRestriction = NULL; m_pwszSchemaName = NULL; m_ulNullCollation = DBPROPVAL_NC_HIGH; m_cTotalRows = 0; m_eRowCount = MIN_REQUIRED; m_cDBBINDING = 0; m_cDBCOLUMNINFO = 0; m_cRestrict = 0; m_fCaptureRestrictions = FALSE; m_iRestrict = 0; m_pIDBSchemaRowset = NULL; m_ulRestrictRow = 2; m_prgRestrictUsed = NULL; m_cRestrictionsUsed = 0; m_pRow = NULL; m_pRowPrev = NULL; m_pIRowset = NULL; m_rgDBBINDING = NULL; m_rgDBCOLUMNINFO = NULL; m_pStringsBuffer = NULL; m_eRestrictArray = RT_SUPPORTED; m_rgDBCOLUMNINFO_Prev = NULL; m_pStringsBuffer_Prev = NULL; m_cDBCOLUMNINFO_Prev = 0; // Information specific to a given table in a schema m_pwszTableName = NULL; m_ulTableOrdinal = 0; m_prgColInfo = NULL; m_pwszStringsBuffer = NULL; m_cColInfo = 0; // Init all restrictions variants for (ULONG iRestrict = 0; iRestrict < MAXRESTRICTION; iRestrict++) { VariantInit(&m_rgRestrict[iRestrict]); VariantInit(&m_rgRestrictValid[iRestrict]); VariantInit(&m_rgRestrictUsed[iRestrict]); } } CHelper::~CHelper(void) { ClearRestrictions(m_rgRestrict); ClearRestrictions(m_rgRestrictValid); ClearRestrictions(m_rgRestrictUsed); SAFE_FREE(m_rgDBBINDING); SAFE_FREE(m_rgDBCOLUMNINFO); SAFE_FREE(m_pStringsBuffer); SAFE_RELEASE(m_pIDBSchemaRowset); SAFE_RELEASE(m_pIRowset); SAFE_FREE(m_pwszTableName); SAFE_FREE(m_prgColInfo); SAFE_FREE(m_pwszStringsBuffer); SAFE_FREE(m_rgDBCOLUMNINFO_Prev); SAFE_FREE(m_pStringsBuffer_Prev); SAFE_FREE(m_pwszCatalogRestriction); SAFE_FREE(m_pwszSchemaName); } BOOL CHelper::Init(CSchemaTest * pThis) { ULONG cSchemas = 0; WCHAR * pwszOLEDBVER = NULL; GUID * rgSchemas = NULL; ULONG * rgRestrictionSupport = NULL; BOOL fFoundSchema = FALSE; ULONG iSchema; BOOL fResult = FALSE; IDBInitialize * pIDBInit = NULL; TESTC(pThis != NULL) pIDBInit = pThis->m_pIDBInitialize; m_ECHelper.Init(GetModInfo()->GetDebugMode()); // CHelper is a virtual (not pure) base class and m_guidSchema is populated // in the derived class with the proper schema, so don't allow users to // Init without a valid schema. TESTC(m_guidSchema != GUID_NULL) m_pCSchemaTest = pThis; m_pTable = pThis->m_pTable; m_pIDBSchemaRowset = pThis->m_pIDBSchemaRowset; m_pIDBSchemaRowset->AddRef(); // Locate this schema in the global schema information array for (iSchema = 0; iSchema < NUMELEM(AllSchemas); iSchema++) { if (*AllSchemas[iSchema].pguid == m_guidSchema) { m_pSchemaInfo = &AllSchemas[iSchema]; break; } } TESTC(m_pSchemaInfo != NULL) // Get Restriction support for this schema m_fSupported = FALSE; TESTC_(m_pIDBSchemaRowset->GetSchemas(&cSchemas, &rgSchemas, &rgRestrictionSupport), S_OK) for(iSchema=0; iSchemapulColCount) { m_pSchemaInfo->cColumns = m_pSchemaInfo->pulColCount[0]; } fResult = TRUE; CLEANUP: SAFE_FREE(rgSchemas); SAFE_FREE(rgRestrictionSupport); return fResult; } // Default implementation does nothing LPWSTR CHelper::CreateObject(UINT idsObject, LPWSTR pwszObjectName) {return NULL;} BOOL CHelper::VerifyObject(UINT idsObject) {return TRUE;} BOOL CHelper::VerifyObjectValue(UINT idsObject, ULONG iOrdinal) {return TRUE;} // Determine the schema version and OLEDB version void CHelper::GetVersionInfo(IDBInitialize * pIDBInit) { LPWSTR pwszOLEDBVER = NULL; // Get DBPROP_PROVIDEROLEDBVER for use in setting correct column count for each schema if (GetProperty(DBPROP_PROVIDEROLEDBVER, DBPROPSET_DATASOURCEINFO, pIDBInit, &pwszOLEDBVER)) { if (!wcscmp(pwszOLEDBVER, L"02.00")) { m_ulSchemaVersion = VER_20; m_ulOLEDBVer = VER_20; } else if (!wcscmp(pwszOLEDBVER, L"02.10")) { m_ulSchemaVersion = VER_21; m_ulOLEDBVer = VER_21; } else if (!wcscmp(pwszOLEDBVER, L"02.50")) { m_ulSchemaVersion = VER_25; m_ulOLEDBVer = VER_25; } else if (!wcscmp(pwszOLEDBVER, L"02.60")) { m_ulSchemaVersion = VER_26; m_ulOLEDBVer = VER_26; } else if (!wcscmp(pwszOLEDBVER, L"02.70")) { m_ulSchemaVersion = VER_27; m_ulOLEDBVer = VER_27; } else { odtLog << L"Unexpected provider OLEDB version.\n"; COMPARE(0,1); } SAFE_FREE(pwszOLEDBVER); } } BOOL CHelper::CreateCheckConstraints(void) { // Create at least two check constraints that will not impact other test variations // using the test's default table. // alter table slh add constraint slhconstraint check (col1 >= 'bbb' or col1 < 'bbb') // %1 tablename, %2 constraintname, %3 columnname, %4 constraintvalue BOOL fRet = FALSE; CCol TempCol; size_t ccStmt = 0; DBORDINAL iCol; LPWSTR pwszStmtFormat = L"alter table %s add constraint %s check (%s >= '%s' or %s < '%s')"; LPWSTR pwszConstraintName = NULL; LPWSTR pwszColumnName = NULL; LPWSTR pwszTableName = NULL; LPWSTR pwszConstraintValue = L"a"; // We use any bogus value because the constriant is not constrained LPWSTR pwszStmt = NULL; // This function uses SQL Server syntax. For other DBMS's we assume the check constraints // already exist and so just return TRUE; if (!g_fSQLServer) return TRUE; // Populate the table name pwszTableName = m_pTable->GetTableName(); for (iCol = 1; iCol <= m_pTable->CountColumnsOnTable(); iCol++) { // Get the information about the column if (!CHECK(m_pTable->GetColInfo(iCol, TempCol), S_OK)) { fRet = FALSE; goto CLEANUP; } // Get a char column name if ((TempCol.GetProviderType() != DBTYPE_STR && TempCol.GetProviderType() != DBTYPE_WSTR) || TempCol.GetIsLong()) continue; // Create a unique constraint name pwszConstraintName = MakeObjectName(L"Cnst", 30); CHECK_MEMORY(pwszConstraintName); pwszColumnName = TempCol.GetColName(); ccStmt = wcslen(pwszStmtFormat) + wcslen(pwszTableName) + wcslen(pwszConstraintName) + wcslen(pwszColumnName) + wcslen(pwszConstraintValue) + 1; SAFE_ALLOC(pwszStmt, WCHAR, ccStmt); swprintf(pwszStmt, pwszStmtFormat, pwszTableName, pwszConstraintName, pwszColumnName, pwszConstraintValue, pwszColumnName, pwszConstraintValue); // Execute the command expecting S_OK TESTC_(m_pTable->BuildCommand(pwszStmt, IID_IRowset, EXECUTE_IFNOERROR, 0, NULL, NULL, NULL, NULL), S_OK); SAFE_FREE(pwszConstraintName); SAFE_FREE(pwszStmt); fRet = TRUE; } CLEANUP: SAFE_FREE(pwszConstraintName); SAFE_FREE(pwszStmt); return fRet; } BOOL CHelper::CreateStoredProcs(void) { // Create at least two stored procs using the test's default table. // create proc slhproc(@p1 char(30), @p2 char(30)) as begin select * from where charcol > 'aaa' or charcol < 'zzz'; end BOOL fRet = FALSE; CCol TempCol; size_t ccStmt = 0; DBORDINAL iCol; LPWSTR pwszStmtFormat = L"create procedure %s(@p1 char(30), @p2 char(30)) as begin select * from %s where %s > 'a' or %s < 'z'; end"; LPWSTR pwszColumnName = NULL; LPWSTR pwszSprocName = NULL; LPWSTR pwszTableName = NULL; LPWSTR pwszStmt = NULL; // This function uses SQL Server syntax. For other DBMS's we assume the procs // already exist and so just return TRUE; if (!g_fSQLServer) return TRUE; // Populate the table name pwszTableName = m_pTable->GetTableName(); for (iCol = 1; iCol <= m_pTable->CountColumnsOnTable(); iCol++) { // Get the information about the column if (!CHECK(m_pTable->GetColInfo(iCol, TempCol), S_OK)) { fRet = FALSE; goto CLEANUP; } // Get a char column name if ((TempCol.GetProviderType() != DBTYPE_STR && TempCol.GetProviderType() != DBTYPE_WSTR) || TempCol.GetIsLong()) continue; // Create a unique sproc name pwszSprocName = MakeObjectName(L"IDBSproc", 30); CHECK_MEMORY(pwszSprocName); pwszColumnName = TempCol.GetColName(); ccStmt = wcslen(pwszStmtFormat) + wcslen(pwszTableName) + wcslen(pwszSprocName) + wcslen(pwszColumnName) + wcslen(pwszColumnName) + 1; SAFE_ALLOC(pwszStmt, WCHAR, ccStmt); swprintf(pwszStmt, pwszStmtFormat, pwszSprocName, pwszTableName, pwszColumnName, pwszColumnName); // Execute the command expecting S_OK TESTC_(m_pTable->BuildCommand(pwszStmt, IID_IRowset, EXECUTE_IFNOERROR, 0, NULL, NULL, NULL, NULL), S_OK); odtLog << L"Created stored proc " << pwszSprocName << L"\n"; SAFE_FREE(pwszSprocName); SAFE_FREE(pwszStmt); fRet = TRUE; } CLEANUP: SAFE_FREE(pwszSprocName); SAFE_FREE(pwszStmt); return fRet; } BOOL CHelper::IsSupported(void) { return m_fSupported; } void CHelper::ClearRestrictions(VARIANT * prgVariant) { // By default clear the restrictions actually used if (!prgVariant) prgVariant = m_rgRestrictUsed; for (ULONG iRestrict = 0; iRestrict < MAXRESTRICTION; iRestrict++) VariantClear(&prgVariant[iRestrict]); } ULONG CHelper::GetLiteralMaxSize(DBLITERAL eLiteral) { DBLITERALINFO* pLiteralInfo = NULL; pLiteralInfo = m_pTable->GetLiteralInfo(eLiteral); TESTC(pLiteralInfo != NULL); return pLiteralInfo->cchMaxLen; CLEANUP: return CCHMAXLENGTH_UNKNOWN; } ULONG CHelper::GetRestrictionMaxLength(ULONG iRestrict) { ULONG ulRestrictBit = 1 << (iRestrict-1); RESTRICT_CAT eRestrictType = GetRestrictCat(iRestrict); // Restrictions are 1 based _ASSERTE(iRestrict > 0); // We don't care about undefined restrictions if (eRestrictType == RC_UND) return CCHMAXLENGTH_UNKNOWN; switch (eRestrictType) { case RC_CATALOG: // Use max catalog name size return GetLiteralMaxSize(DBLITERAL_CATALOG_NAME); case RC_SCHEMA: // Use max schema name size return GetLiteralMaxSize(DBLITERAL_SCHEMA_NAME); case RC_TABLE: // Use max table name size return GetLiteralMaxSize(DBLITERAL_TABLE_NAME); case RC_CONSTRAINT: // return GetLiteralMaxSize(DBLITERAL_CONSTRAINT_NAME); odtLog << L"Missing DBLITERAL_CONSTRAINT_NAME in OLEDB.H, using DBLITERAL_TABLE_NAME\n"; return GetLiteralMaxSize(DBLITERAL_TABLE_NAME); case RC_COLUMN: return GetLiteralMaxSize(DBLITERAL_COLUMN_NAME); case RC_USER: return GetLiteralMaxSize(DBLITERAL_USER_NAME); case RC_INDEX: return GetLiteralMaxSize(DBLITERAL_INDEX_NAME); case RC_PROCEDURE: return GetLiteralMaxSize(DBLITERAL_PROCEDURE_NAME); case RC_PARAMETER: // No literal value for COLUMN NAME, use COLUMN_NAME return GetLiteralMaxSize(DBLITERAL_COLUMN_NAME); case RC_CONSTRAINT_TYPE: return (ULONG)wcslen(L"PRIMARY KEY"); case RC_STATISTICS: // No literal value for STATISTICS NAME, use COLUMN_NAME return (ULONG)GetLiteralMaxSize(DBLITERAL_COLUMN_NAME); case RC_TABLE_TYPE: return (ULONG)wcslen(L"GLOBAL TEMPORARY"); // Unknown length values case RC_SERVER: case RC_UND: odtLog << L"Unknown restriction length, using DBLITERAL_COLUMN_NAME values.\n"; return GetLiteralMaxSize(DBLITERAL_COLUMN_NAME); default: odtLog << L"Unknown restriction length, restriction not tested.\n"; COMPARE(0, 1); return CCHMAXLENGTH_UNKNOWN; } } LPWSTR CHelper::GetRestrictionName(ULONG iRestrict) { // A valid restriction must be within range if (COMPARE(iRestrict > 0 && iRestrict <= m_pSchemaInfo->cRestrictions, TRUE)) { DBORDINAL iOrdinal = m_pSchemaInfo->pulRestrictions[iRestrict-1]; return m_pSchemaInfo->pColList[iOrdinal-1].pwszName; } return NULL; } LPWSTR CHelper::GetCatalogName() { return m_pwszCatalogRestriction; }; RESTRICT_CAT CHelper::GetRestrictCat(ULONG iRestrict) { // A valid restriction must be within range if (COMPARE(iRestrict > 0 && iRestrict <= m_pSchemaInfo->cRestrictions, TRUE)) return m_pSchemaInfo->peRestrictCat[iRestrict-1]; return RC_UND; } int CHelper::TestRestriction(ULONG iRestrict) { HRESULT hrExpected = S_OK; HRESULT hr = E_FAIL; BOOL fResult = FALSE; BOOL fIsOutsideRange = FALSE; VARIANT * pVariantFirst = GetRestrictPtr(RV_ONE); if (!IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } // If this restriction is > number of spec'd restrictions -> E_INVALIDARG if (iRestrict > m_pSchemaInfo->cRestrictions) { odtLog << L"Restriction " << iRestrict << L" is NOT supported.\n"; fIsOutsideRange = TRUE; hrExpected = E_INVALIDARG; } else if (IsSupportedRestriction(iRestrict)) odtLog << L"Restriction on " << GetRestrictionName(iRestrict) << L" is supported.\n"; else { odtLog << L"Restriction on " << GetRestrictionName(iRestrict) << L" is NOT supported.\n"; hrExpected = DB_E_NOTSUPPORTED; } SetRestrictionArray(RT_CUSTOM); // If this restrictions is outside the range of valid restrictions // just set to the same as the first restriction, since there is // no value cached and we don't know which column to cache from anyway // or the restriction type if (fIsOutsideRange) SetRestriction(iRestrict, pVariantFirst); else SetRestriction(iRestrict); hr = GetRowsetHelper(NULL, iRestrict); // Provider is allowed to return E_INVALIDARG if restriction is not supported. if (hrExpected == DB_E_NOTSUPPORTED && hr == E_INVALIDARG) hrExpected = hr; TESTC_(hr, hrExpected); fResult = TRUE; CLEANUP: ClearRestrictions(); SetRestrictionArray(RT_SUPPORTED); return fResult; } BOOL CHelper::IsRestricted(ULONG iRestrict) { // A valid restriction must be within range if (COMPARE(iRestrict > 0 && iRestrict <= m_pSchemaInfo->cRestrictions, TRUE)) { return (!m_rgRestrictUsed || m_rgRestrictUsed[iRestrict-1].vt != VT_EMPTY); } return FALSE; } void CHelper::SetRestriction(ULONG iRestrict) { // A valid restriction must be within range if (COMPARE(iRestrict > 0 && iRestrict <= m_pSchemaInfo->cRestrictions, TRUE)) { VariantClear(&m_rgRestrictUsed[iRestrict-1]); CHECK(VariantCopy(&m_rgRestrictUsed[iRestrict-1], &m_rgRestrict[iRestrict-1]), S_OK); } } // Set a list of allowed values for this columm BOOL CHelper::GetValidColumnValues(DBORDINAL iOrdinal, ULONG * pcValidValues, LPVOID * ppValidValues) { // Make sure ordinal is valid if (!iOrdinal || iOrdinal > m_pSchemaInfo->cColumns) return FALSE; // Make sure out params were passed if (!pcValidValues || !ppValidValues) return FALSE; *pcValidValues = m_pSchemaInfo->pColList[iOrdinal-1].cValidVals; *ppValidValues = m_pSchemaInfo->pColList[iOrdinal-1].pValidVals; return TRUE; } // Set a list of allowed values for this columm BOOL CHelper::SetValidColumnValues(DBORDINAL iOrdinal, ULONG cValidValues, LPVOID pValidValues) { // Make sure ordinal is valid if (!iOrdinal || iOrdinal > m_pSchemaInfo->cColumns) return FALSE; m_pSchemaInfo->pColList[iOrdinal-1].cValidVals = cValidValues; m_pSchemaInfo->pColList[iOrdinal-1].pValidVals = pValidValues; return TRUE; } void CHelper::SetValidRestriction(ULONG iRestrict) { // A valid restriction must be within range if (COMPARE(iRestrict > 0 && iRestrict <= m_pSchemaInfo->cRestrictions, TRUE)) { VariantClear(&m_rgRestrictUsed[iRestrict-1]); CHECK(VariantCopy(&m_rgRestrictUsed[iRestrict-1], &m_rgRestrictValid[iRestrict-1]), S_OK); } } void CHelper::SetEmptyRestrict(ULONG iRestrict) { // A valid restriction must be within range if (COMPARE(iRestrict > 0 && iRestrict <= m_pSchemaInfo->cRestrictions, TRUE)) { VariantClear(&m_rgRestrictUsed[iRestrict-1]); V_VT(&m_rgRestrictUsed[iRestrict-1]) = VT_EMPTY; } } BOOL CHelper::SetRestriction(ULONG iRestrict, VARIANT * pVariant) { BOOL fResult = FALSE; TESTC(pVariant != NULL); VariantClear(&m_rgRestrictUsed[iRestrict-1]); TESTC_(VariantCopy(&m_rgRestrictUsed[iRestrict-1], pVariant), S_OK); fResult = TRUE; CLEANUP: return fResult; } BOOL CHelper::SetRestriction(ULONG iRestrict, LPVOID pValue) { VARIANT * pVariant = NULL; DBTYPE wType; DBORDINAL iOrdinal; BOOL fResult = FALSE; // Must be within range if (COMPARE(iRestrict > 0 && iRestrict <= m_pSchemaInfo->cRestrictions, TRUE)) { iOrdinal = m_pSchemaInfo->pulRestrictions[iRestrict-1]; wType = m_pSchemaInfo->pColList[iOrdinal-1].wType; VariantClear(&m_rgRestrictUsed[iRestrict-1]); pVariant = DBTYPE2VARIANT(pValue, wType); TESTC(pVariant != NULL); TESTC_(VariantCopy(&m_rgRestrictUsed[iRestrict-1], pVariant), S_OK); fResult = TRUE; } CLEANUP: if (pVariant) VariantClear(pVariant); SAFE_FREE(pVariant); return fResult; } BOOL CHelper::SetRestriction(ULONG iRestrict, LPVOID pValue, DBTYPE wType) { VARIANT * pVariant = NULL; BOOL fResult = FALSE; // Must be within range if (COMPARE(iRestrict > 0 && iRestrict <= MAXRESTRICTION, TRUE)) { VariantClear(&m_rgRestrictUsed[iRestrict-1]); pVariant = DBTYPE2VARIANT(pValue, wType); TESTC(pVariant != NULL); TESTC_(VariantCopy(&m_rgRestrictUsed[iRestrict-1], pVariant), S_OK); fResult = TRUE; } CLEANUP: if (pVariant) VariantClear(pVariant); SAFE_FREE(pVariant); return fResult; } BOOL CHelper::SetInvalidRestriction(ULONG iRestrict, LPVOID pValue, DBTYPE wType) { BOOL fResult = FALSE; // Must be within range if (COMPARE(iRestrict > 0 && iRestrict <= MAXRESTRICTION, TRUE)) { VariantClear(&m_rgRestrictUsed[iRestrict-1]); V_VT(&m_rgRestrictUsed[iRestrict-1]) = wType; m_rgRestrictUsed[iRestrict-1].punkVal = (struct IUnknown *)pValue; fResult = TRUE; } return fResult; } void CHelper::SetRestrictionType(ULONG iRestrict, DBTYPE wType) { if (COMPARE(iRestrict > 0 && iRestrict <= MAXRESTRICTION, TRUE)) V_VT(&m_rgRestrictUsed[iRestrict-1]) = wType; } VARIANT * CHelper::GetRestrictPtr(ULONG iRestrict) { VARIANT * prgRestrictions = NULL; if (COMPARE(iRestrict > 0 && iRestrict <= MAXRESTRICTION, TRUE)) { switch(m_eRestrictArray) { case RT_CACHED: prgRestrictions = m_rgRestrict; break; case RT_SUPPORTED: prgRestrictions = m_rgRestrictValid; break; case RT_CUSTOM: prgRestrictions = m_rgRestrictUsed; break; } _ASSERTE(prgRestrictions); return &prgRestrictions[iRestrict-1]; } return NULL; } BOOL CHelper::FillRestrictions(DBCOUNTITEM iRow, LPBYTE pData) { // Fill restrictions with values from this row DBTYPE wType; ULONG iRestrict = 0; ULONG iEnd = m_pSchemaInfo->cRestrictions; VARIANT * pVariant = NULL; LPBYTE pValue = NULL; BOOL fResult = FALSE; // If we're not on the right row, then bail if (iRow != m_ulRestrictRow) return TRUE; // This is the right row, fill the restriction column(s) desired if (m_iRestrict) { // Only want to restrict this restriction, convert to 0-based iRestrict = m_iRestrict-1; TESTC(iRestrict < iEnd); // Make sure a bad restriction wasn't passed iEnd = m_iRestrict; } for (; iRestrict < iEnd; iRestrict++) { DBORDINAL iOrdinal = m_pSchemaInfo->pulRestrictions[iRestrict]; wType = m_pSchemaInfo->pColList[iOrdinal-1].wType; pValue = GetValuePtr(iOrdinal, pData, m_rgDBBINDING); // If there is no value, then restriction must be VT_NULL; if (!pValue) { V_VT(&m_rgRestrict[iRestrict]) = VT_NULL; continue; } // GUID restrictions are mapped to BSTR if (wType == DBTYPE_GUID) { wType = DBTYPE_BSTR; // We don't support this yet, need conversionn from GUID->BSTR TESTC(FALSE); } pVariant = DBTYPE2VARIANT(pValue, wType); TESTC(pVariant != NULL); TESTC_(VariantCopy(&m_rgRestrict[iRestrict], pVariant), S_OK) VariantClear(pVariant); SAFE_FREE(pVariant); } fResult = TRUE; CLEANUP: if (pVariant) VariantClear(pVariant); SAFE_FREE(pVariant); m_fCaptured = TRUE; // Otherwise we'll loop forever looking for restriction return fResult; } BOOL CHelper::GetRestrictions(ULONG iRestrict) { IRowset * pIRowset = NULL; BOOL fResult = FALSE; // Pick a row and use this row's value for restriction iRestrict (1-based) // If iRestrict is 0, then all restrictions are filled from this row. // At some later time we will add code to select an interesting restriction such // as a NULL value. // For now the row is hard-coded, but later we will use some heuristic to determine m_ulRestrictRow = 2; m_iRestrict = iRestrict; m_fCaptureRestrictions = TRUE; m_fCaptured = FALSE; // Clear all cached restrictions ClearRestrictions(m_rgRestrict); // Call the GetRowsetHelper to actually do the work of filling the restrictions // if the schema is supported, otherwise just leave VT_EMPTY if (m_fSupported) { TESTC_(GetRowsetHelper(NULL, RV_NULL), S_OK); // Now m_rgRestrict is filled with valid known values for each possible restriction, // but not all of them may be supported restrictions. Copy supported restrictions to // m_rgRestrictValid. for (iRestrict = 1; iRestrict <= m_pSchemaInfo->cRestrictions; iRestrict++) { if (IsSupportedRestriction(iRestrict)) { VariantClear(&m_rgRestrictValid[iRestrict-1]); TESTC_(VariantCopy(&m_rgRestrictValid[iRestrict-1], &m_rgRestrict[iRestrict-1]), S_OK) } } } fResult = TRUE; CLEANUP: return fResult; } BOOL CHelper::IsSupportedRestriction(ULONG iRestrict) { if (COMPARE(iRestrict > 0, TRUE)) return m_ulRestrictionSupport & (1<<(iRestrict-1)); else return FALSE; } BOOL CHelper::HasUnsupportedRestriction(void) { for(ULONG iRestrict = 1; iRestrict <= m_pSchemaInfo->cRestrictions; iRestrict++) { if (!IsSupportedRestriction(iRestrict)) return TRUE; } return FALSE; } void CHelper::SetRowCount(ROW_COUNT eRowCount, DBORDINAL ulRowCount) { m_eRowCount = eRowCount; m_ulRowCount = ulRowCount; } BOOL CHelper::CheckAgainstIColumnsInfo(SchemaList * pSchemaInfo) { BOOL fResult = TRUE; BOOL fCountNotChecked= FALSE; BOOL fBookmark = FALSE; ULONG ulIndex = 0; ColList * pColList = pSchemaInfo->pColList; ULONG cCols = pSchemaInfo->cColumns; ULONG iOrdinalExpected = 0; ULONG iSchemaInfo = 0; // Make sure the right number of columns were returned for this schema COMPARE(cCols <= (m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal), TRUE); // Make sure the rowset is not null if((!m_pIRowset) || (!m_cDBCOLUMNINFO) || (!m_rgDBCOLUMNINFO) || (!m_pStringsBuffer)) { odtLog << L"CheckAgainstIColumnsInfo:Either rowset or DBCOLUMNINFO variables are null."<pwszName << L": Bookmark column was found but the DBPROP_BOOKMARKS was not set.\n"; } // Check column ordering, column name and data type, skip bookmark column for(ulIndex = (0 + fBookmark); ulIndex < m_cDBCOLUMNINFO; ulIndex ++) { iOrdinalExpected = ulIndex-fBookmark+1; iSchemaInfo = ulIndex-fBookmark; // only check spec'd columns, not any provider-specific columns if(iSchemaInfo < cCols) { // Check column ordinal if(!COMPARE(m_rgDBCOLUMNINFO[ulIndex].iOrdinal, iOrdinalExpected)) { odtLog << L"ORDINAL [" << m_rgDBCOLUMNINFO[ulIndex].pwszName << L"," << ulIndex << L"]: Expected "<< iOrdinalExpected << L", Received " << m_rgDBCOLUMNINFO[ulIndex].iOrdinal << ENDL; fResult = FALSE; } // If there is a name in this column, check to make sure it is correct if( (m_rgDBCOLUMNINFO[ulIndex].pwszName) && (!COMPARE(0, _wcsicmp(m_rgDBCOLUMNINFO[ulIndex].pwszName,pColList[iSchemaInfo].pwszName)))) { odtLog << L"NAME [" << m_rgDBCOLUMNINFO[ulIndex].pwszName << L"," << ulIndex << L"]: Expected " << pColList[iSchemaInfo].pwszName << L", Received " << m_rgDBCOLUMNINFO[ulIndex].pwszName << ENDL; fResult = FALSE; } // Check column type if(!COMPARE(m_rgDBCOLUMNINFO[ulIndex].wType, pColList[iSchemaInfo].wType)) { odtLog << L"TYPE [" << m_rgDBCOLUMNINFO[ulIndex].pwszName << L"," << ulIndex << L"]: Expected " << pColList[iSchemaInfo].wType << L", Received " << m_rgDBCOLUMNINFO[ulIndex].wType << ENDL; fResult = FALSE; } // Check column size if((!IsFixedLength(m_rgDBCOLUMNINFO[ulIndex].wType)) && (!m_rgDBCOLUMNINFO[ulIndex].ulColumnSize)) { odtLog << L"COLUMNSIZE [" << m_rgDBCOLUMNINFO[ulIndex].pwszName << L"," << ulIndex << L"]: " << L"Column Size for variable length Column is ZERO, expected non-zero." << ENDL; fResult = FALSE; } else if((IsFixedLength(m_rgDBCOLUMNINFO[ulIndex].wType)) && (!COMPARE((ULONG)GetDBTypeSize(m_rgDBCOLUMNINFO[ulIndex].wType), m_rgDBCOLUMNINFO[ulIndex].ulColumnSize))) { odtLog << L"COLUMNSIZE [" << m_rgDBCOLUMNINFO[ulIndex].pwszName << L"," << ulIndex << L"]: Expected " << L"Column Size for the Column is incorrect. " << ENDL; fResult = FALSE; } // Check column precision and scale // Note some provider return an alternate precision/scale for // DBTYPE_CY if(IsNumericType(m_rgDBCOLUMNINFO[ulIndex].wType) && m_rgDBCOLUMNINFO[ulIndex].wType != DBTYPE_CY) { ULONG MaxPrecision = 0; // Switch on the Type switch(m_rgDBCOLUMNINFO[ulIndex].wType) { case DBTYPE_I1: case DBTYPE_UI1: MaxPrecision = 3; break; case DBTYPE_I2: case DBTYPE_UI2: MaxPrecision = 5; break; case DBTYPE_R4: MaxPrecision = 7; break; case DBTYPE_I4: case DBTYPE_UI4: MaxPrecision = 10; break; case DBTYPE_R8: MaxPrecision = 15; break; case DBTYPE_CY: case DBTYPE_I8: MaxPrecision = 19; break; case DBTYPE_UI8: MaxPrecision = 20; break; } // Precision is valid if (((m_rgDBCOLUMNINFO[ulIndex].wType != DBTYPE_DECIMAL) && (m_rgDBCOLUMNINFO[ulIndex].wType != DBTYPE_NUMERIC) && (m_rgDBCOLUMNINFO[ulIndex].wType != DBTYPE_VARNUMERIC)) && (MaxPrecision != m_rgDBCOLUMNINFO[ulIndex].bPrecision) ) { odtLog << L"PRECISION [" << m_rgDBCOLUMNINFO[ulIndex].pwszName << L"," << ulIndex << L"]: Expected " << MaxPrecision << L", Received " << m_rgDBCOLUMNINFO[ulIndex].bPrecision << ENDL; fResult = FALSE; } // Scale is ~0 if (((m_rgDBCOLUMNINFO[ulIndex].wType != DBTYPE_DECIMAL) && (m_rgDBCOLUMNINFO[ulIndex].wType != DBTYPE_NUMERIC) && (m_rgDBCOLUMNINFO[ulIndex].wType != DBTYPE_VARNUMERIC)) && (!COMPARE((BYTE)(~0), m_rgDBCOLUMNINFO[ulIndex].bScale))) { odtLog << L"SCALE [" << m_rgDBCOLUMNINFO[ulIndex].pwszName << L"," << ulIndex << L"]: Expected the Scale to be ~0" << L", Received " << m_rgDBCOLUMNINFO[ulIndex].bScale << ENDL; fResult = FALSE; } } else if (m_rgDBCOLUMNINFO[ulIndex].wType == DBTYPE_DBTIMESTAMP || m_rgDBCOLUMNINFO[ulIndex].wType == DBTYPE_CY) { CCol TempCol; BYTE bPrecision = 0; BYTE bScale = 0; // Get bPrecision and bScale for DBTYPE_DBTIMESTAMP or // DBTYPE_CY from CCol object for (DBORDINAL iCol = 1; iCol <= m_pTable->CountColumnsOnTable(); iCol++) { // Get the information about the column if (!CHECK(m_pTable->GetColInfo(iCol, TempCol), S_OK)) { fResult = FALSE; goto CLEANUP; } // If this is DBTYPE_DBTIMESTAMP it may be the right one if (m_rgDBCOLUMNINFO[ulIndex].wType == TempCol.GetProviderType()) { bPrecision = TempCol.GetPrecision(); bScale = TempCol.GetScale(); if (bPrecision == m_rgDBCOLUMNINFO[ulIndex].bPrecision && bScale == m_rgDBCOLUMNINFO[ulIndex].bScale) { // We found a matching value for precision and scale break; } } } // Precision is defined as length of string representation assuming max // allowed precision of fractional seconds component. // TODO: Compare against CCol. if (!COMPARE(m_rgDBCOLUMNINFO[ulIndex].bPrecision, bPrecision)) { odtLog <"; odtLog << L"Warning - " << m_pSchemaInfo->pwszName << L" provider specific column name: " << pwszName << "\n"; } // If we can tell the names match, don't print the warning else if (wcscmp(pwszName, pwszPrevName)) odtLog << L"Warning - " << m_pSchemaInfo->pwszName << L" provider specific column name: " << pwszName << "\n"; } } CLEANUP: return fResult; } HRESULT CHelper::GetNextRows(DBROWOFFSET lOffset, DBROWCOUNT cRows, DBCOUNTITEM* pcRowsObtained, HROW** prghRows) { ASSERT(prghRows); TBEGIN DBCOUNTITEM cRowsObtained = 0; DBCOUNTITEM i=0; //Record if we passed in consumer allocated array... HROW* rghRowsInput = *prghRows; //GetNextRows HRESULT hr = m_pIRowset->GetNextRows(NULL, lOffset, cRows, &cRowsObtained, prghRows); //Verify Correct values returned if(SUCCEEDED(hr)) { if(hr == S_OK) { TESTC(cRowsObtained==(DBCOUNTITEM)ABS(cRows)); } else { TESTC(cRowsObtained < (DBCOUNTITEM)ABS(cRows)); } //Verify row array for(i=0; ipguid; // Reset row count from this schema m_cTotalRows = 0; // get bindings and column info if(!CHECK(hr=GetAccessorAndBindings( pIRowset, // @parmopt [IN] Rowset to create Accessor for DBACCESSOR_ROWDATA, // @parmopt [IN] Properties of the Accessor &hAccessor, // @parmopt [OUT] Accessor created &m_rgDBBINDING, // @parmopt [OUT] Array of DBBINDINGS &m_cDBBINDING, // @parmopt [OUT] Count of bindings &cbRowSize, // @parmopt [OUT] Length of a row, DATA DBPART_VALUE|DBPART_STATUS |DBPART_LENGTH, ALL_COLS_BOUND, // @parmopt [IN] Which columns will be used in the bindings FORWARD, // @parmopt [IN] Order to bind columns in accessor NO_COLS_BY_REF, // @parmopt [IN] Which column types to bind by reference &m_rgDBCOLUMNINFO, // @parmopt [OUT] Array of DBCOLUMNINFO &m_cDBCOLUMNINFO, // @parmopt [OUT] Count of Columns, also count of ColInfo elements &m_pStringsBuffer, DBTYPE_EMPTY, // @parmopt [IN] Modifier to be OR'd with each binding type. 0, // @parmopt [IN] Used only if eColsToBind = USE_COLS_TO_BIND_ARRAY NULL, // @parmopt [IN] Used only if eColsToBind = USE_COLS_TO_BIND_ARRAY NULL, // @parmopt [IN] Corresponds to what ordinals are specified for each binding, if NO_COLS_OWNED_BY_PROV, // @parmopt [IN] Which columns' memory is to be owned by the provider DBPARAMIO_NOTPARAM, // @parmopt [IN] Parameter kind specified for all bindings BLOB_LONG, // @parmopt [IN] how to bind BLOB Columns NULL),S_OK)) // @parmopt [OUT] returned status array from CreateAccessor goto CLEANUP; // Don't need to check if only capturing restrictions if(!m_fCaptureRestrictions) { fVerifyRow &= CheckAgainstIColumnsInfo(m_pSchemaInfo); // Free any previous columninfo SAFE_FREE(m_rgDBCOLUMNINFO_Prev); SAFE_FREE(m_pStringsBuffer_Prev); // Save the pointer to the previous columninfo m_cDBCOLUMNINFO_Prev = m_cDBCOLUMNINFO; m_rgDBCOLUMNINFO_Prev = m_rgDBCOLUMNINFO; m_pStringsBuffer_Prev = m_pStringsBuffer; } // check if we need to go on TESTC(m_cDBBINDING && m_cDBCOLUMNINFO && m_rgDBBINDING && m_rgDBCOLUMNINFO) if(m_fPassUnsupportedRestrictions) { fVerifyRow = TRUE; goto CLEANUP; } // create space for two rows of data SAFE_ALLOC(pRowBuff, BYTE, cbRowSize*2); m_pRow = pRowBuff; // Start by writing into beginning of buffer if(GetModInfo()->GetDebugMode() & DEBUGMODE_FULL ) ulRowsToVerify = 90000; else // This should be larger than NUMROWS_CHUNK to force at least one additional // GetNextRows call below. ulRowsToVerify = 100; _ASSERTE(m_pRowPrev == NULL); // Process all the rows, NUMROWS_CHUNK rows at a time while(fContinue) { // get rows to process hr=GetNextRows(0,30,&cRowsObtained,&prghRows); // odtLog << L"Rows obtained: " << m_cTotalRows + cRowsObtained << L"\n"; TEST4C_(hr, S_OK, DB_S_ENDOFROWSET, DB_S_STOPLIMITREACHED, DB_S_ROWLIMITEXCEEDED); // verify that we have rows to process if(cRowsObtained==0) { // Hack for Kagera. Kagera will not return rows from many schemas when unrestricted, // so we are unable to capture any restrictions. In this case Kagera will return rows // when restricted to a table, and since we know at least one valid table, use that one if (g_fKagera && m_fCaptureRestrictions) { ULONG iRestrict = 0; // 0 based restriction index LPWSTR pwszRestrict = NULL; if (guidSchema == DBSCHEMA_COLUMN_PRIVILEGES || guidSchema == DBSCHEMA_COLUMNS || guidSchema == DBSCHEMA_CONSTRAINT_COLUMN_USAGE || guidSchema == DBSCHEMA_CONSTRAINT_TABLE_USAGE || guidSchema == DBSCHEMA_STATISTICS || guidSchema == DBSCHEMA_TABLE_PRIVILEGES || guidSchema == DBSCHEMA_TABLE_STATISTICS || guidSchema == DBSCHEMA_TABLES || guidSchema == DBSCHEMA_TABLES_INFO || guidSchema == DBSCHEMA_VIEWS) { // Use table name as restriction pwszRestrict = m_pTable->GetTableName(); iRestrict = 2; } else if (guidSchema == DBSCHEMA_INDEXES) { // Use table name as restriction pwszRestrict = m_pTable->GetTableName(); iRestrict = 4; } else if (guidSchema == DBSCHEMA_PRIMARY_KEYS) { // Use primary/foreign key table name as restriction pwszRestrict = g_pKeyTable1->GetTableName(); iRestrict = 2; } else if (guidSchema == DBSCHEMA_FOREIGN_KEYS) // This is really FK_TABLE_NAME, but it will suffice { // Use primary/foreign key table name as restriction pwszRestrict = g_pKeyTable1->GetTableName(); iRestrict = 5; } else if (guidSchema == DBSCHEMA_KEY_COLUMN_USAGE || guidSchema == DBSCHEMA_TABLE_CONSTRAINTS) { // Use table name as restriction pwszRestrict = m_pTable->GetTableName(); iRestrict = 5; } // Set the restriction to use V_VT(&m_rgRestrictValid[iRestrict]) = VT_BSTR; V_BSTR(&m_rgRestrictValid[iRestrict]) = SysAllocString(pwszRestrict); // Clean up array binding information and release memory associated with empty rowset if (pIAccessor && hAccessor != DB_NULL_HACCESSOR) CHECK(pIAccessor->ReleaseAccessor(hAccessor, NULL), S_OK); SAFE_RELEASE(pIAccessor); SAFE_RELEASE(m_pIRowset); SAFE_FREE(m_rgDBCOLUMNINFO); SAFE_FREE(m_pStringsBuffer); SAFE_FREE(m_rgDBBINDING); SAFE_FREE(prghRows); // Call again with a table name restriction hr=m_pIDBSchemaRowset->GetRowset(NULL, guidSchema, m_pSchemaInfo->cRestrictions, m_rgRestrictValid, IID_IRowset, 0, NULL, (IUnknown **)&m_pIRowset); TESTC_(hr, S_OK); // get bindings and column info if(!CHECK(hr=GetAccessorAndBindings( m_pIRowset, // @parmopt [IN] Rowset to create Accessor for DBACCESSOR_ROWDATA, // @parmopt [IN] Properties of the Accessor &hAccessor, // @parmopt [OUT] Accessor created &m_rgDBBINDING, // @parmopt [OUT] Array of DBBINDINGS &m_cDBBINDING, // @parmopt [OUT] Count of bindings &cbRowSize, // @parmopt [OUT] Length of a row, DATA DBPART_VALUE|DBPART_STATUS |DBPART_LENGTH, ALL_COLS_BOUND, // @parmopt [IN] Which columns will be used in the bindings FORWARD, // @parmopt [IN] Order to bind columns in accessor NO_COLS_BY_REF, // @parmopt [IN] Which column types to bind by reference &m_rgDBCOLUMNINFO, // @parmopt [OUT] Array of DBCOLUMNINFO &m_cDBCOLUMNINFO, // @parmopt [OUT] Count of Columns, also count of ColInfo elements &m_pStringsBuffer, DBTYPE_EMPTY, // @parmopt [IN] Modifier to be OR'd with each binding type. 0, // @parmopt [IN] Used only if eColsToBind = USE_COLS_TO_BIND_ARRAY NULL, // @parmopt [IN] Used only if eColsToBind = USE_COLS_TO_BIND_ARRAY NULL, // @parmopt [IN] Corresponds to what ordinals are specified for each binding, if NO_COLS_OWNED_BY_PROV, // @parmopt [IN] Which columns' memory is to be owned by the provider DBPARAMIO_NOTPARAM, // @parmopt [IN] Parameter kind specified for all bindings BLOB_LONG, // @parmopt [IN] how to bind BLOB Columns NULL),S_OK)) // @parmopt [OUT] returned status array from CreateAccessor goto CLEANUP; // Call GetNextRows again hr=GetNextRows(0,30,&cRowsObtained,&prghRows); // Make sure we don't leak the restriction VariantClear(&m_rgRestrictValid[iRestrict]); // Theoretically we now have some rows, but if not we're still in the same boat we were before } if (cRowsObtained == 0) { TESTC_(hr, DB_S_ENDOFROWSET); break; } } // Only verify required number of rows if (m_cTotalRows < ulRowsToVerify) { // Make sure we don't call verify with no valid restrictions. // ASSERT((m_restrict != ALLRES) || (m_currentBitMask == 0)); // Loop over rows obtained, getting data for each for(iRow=0;iRowGetData(prghRows[iRow],hAccessor,m_pRow), S_OK) // If we are just capturing restrictions then don't do verification if (m_fCaptureRestrictions) { // Adjust our restriction row if the rowset doesn't have enough rows if (m_cTotalRows - 1 + cRowsObtained < m_ulRestrictRow) m_ulRestrictRow = m_cTotalRows - 1 + cRowsObtained; TESTC(FillRestrictions(m_cTotalRows, m_pRow)) } else { // Verify the row fVerifyRow &= VerifyRowCommon(m_cTotalRows,m_pRow); // Reset to point to the next available row location m_pRowPrev = m_pRow; if (m_pRow == pRowBuff) m_pRow += cbRowSize; else m_pRow = pRowBuff; } // If we know we've filled the restriction then break out of loop // Otherwise we continue for all rows if (m_fCaptureRestrictions && m_fCaptured) { m_fCaptureRestrictions = FALSE; fContinue = FALSE; break; } } } else m_cTotalRows += cRowsObtained; TESTC_(m_pIRowset->ReleaseRows(cRowsObtained,prghRows,NULL,NULL,NULL),S_OK) SAFE_FREE(prghRows); } switch (m_eRowCount) { case MIN_VALUE: // Warn if we didn't get any rows but expected some if (m_ulRowCount && !m_cTotalRows) odtLog << L"Warning - this rowset didn't return any rows so no values were checked.\n"; // Fail if we got some rows but less than minimum expected if (m_cTotalRows) TESTC(m_cTotalRows >= m_ulRowCount); break; case MIN_REQUIRED: // Fail if we got less than minimum expected if (!COMPARE(m_cTotalRows >= m_ulRowCount, TRUE)) odtLog << L"Min row count not retrieved. Expected: >= " << m_ulRowCount << L" Received: " << m_cTotalRows << L"\n"; break; case EXACT_VALUE: // ASSERT(m_cTotalRows == m_ulRowCount); if (m_cTotalRows != m_ulRowCount) odtLog << L"Expected " << m_ulRowCount << " rows, received " << m_cTotalRows << " rows.\n"; TESTC(m_cTotalRows == m_ulRowCount); break; default: ASSERT(!L"Unexpected row count value for schema rowset."); } CLEANUP: // If we were capturing restrictions but didn't capture them for some reason // then return FALSE if (m_fCaptureRestrictions && !m_fCaptured) { fVerifyRow = FALSE; m_fCaptureRestrictions = FALSE; // Don't continue to capture COMPARE(TRUE, FALSE); } if (pIAccessor && hAccessor != DB_NULL_HACCESSOR) CHECK(pIAccessor->ReleaseAccessor(hAccessor, NULL), S_OK); SAFE_RELEASE(pIAccessor); SAFE_RELEASE(m_pIRowset); m_cDBCOLUMNINFO = 0; m_cDBBINDING = 0; // m_pRowPrev and m_pRow just point into pRowBuff, so don't free them, but // set to NULL to avoid using in later variations. m_pRow = NULL; m_pRowPrev = NULL; if(!m_cDBCOLUMNINFO_Prev) { PROVIDER_FREE(m_rgDBCOLUMNINFO); PROVIDER_FREE(m_pStringsBuffer); } else { m_rgDBCOLUMNINFO = NULL; // This is not freed, since it's used in m_rgDBCOLUMNINFO_prev m_pStringsBuffer = NULL; // "" } // Free the memory PROVIDER_FREE(m_rgDBBINDING); PROVIDER_FREE(pRowBuff); return fVerifyRow; } BOOL CHelper::CheckResults(HRESULT hr, REFIID riid, IUnknown * pIUnknown) { BOOL fResult = FALSE; if (SUCCEEDED(hr)) { // Verify the interface requested is usable TESTC(DefaultInterfaceTesting(pIUnknown, ROWSET_INTERFACE, riid)) // Verify the properties are correct on the rowset // TODO: // Get a rowset interface TESTC(VerifyInterface(pIUnknown, IID_IRowset, ROWSET_INTERFACE, (IUnknown**)&m_pIRowset)) // Make sure the rowset is correct VerifyRowset(m_pIRowset); } else { // Should not be a rowset TESTC(pIUnknown == NULL); } fResult = TRUE; CLEANUP: SAFE_RELEASE(m_pIRowset); return fResult; } BOOL CHelper::VerifyRowCommon(DBCOUNTITEM iRow, BYTE * pData) { ULONG iBind=0; // Binding Count DATA * pColumn=NULL; // Data Structure CCol col; BOOL fResults=TRUE; DBORDINAL iOrdinal = 0; // Perform common checks for each schema fResults &= VerifySort(iRow, pData); // Many schemas identify a fully qualified table name. Validate this name is valid // by attempting to open the table. fResults &= VerifyValidTable(iRow, pData); // check each column we're bound to. for (iBind=0; iBind < m_cDBBINDING; iBind++) { // grab column pColumn = (DATA *) (pData + m_rgDBBINDING[iBind].obStatus); iOrdinal = m_rgDBCOLUMNINFO[iBind].iOrdinal; // PRVTRACE(L"Row[%lu],Col[%s]:%s:", iRow,m_rgDBCOLUMNINFO[iBind].pwszName,m_pSchemaInfo->pwszName); // Perform common checks for each column fResults &= VerifyColumnCommon(iBind, pColumn); } return fResults; } // Compare each value in order for the sort columns. The // current row values must be >= previous row values. BOOL CHelper::VerifySort(DBCOUNTITEM iRow, BYTE * pData) { BOOL fResult = TRUE; ULONG cSortCols = m_pSchemaInfo->cSort; ULONG iSort; BOOL fGreater = TRUE; // If not two rows then we can't determine sort if (!m_pRowPrev) return TRUE; if (!COMPARE(m_pSchemaInfo->pulSort != NULL, TRUE)) return FALSE; for (iSort = 0; iSort < cSortCols; iSort++) { ULONG iSortCol = m_pSchemaInfo->pulSort[iSort]; DBTYPE wType = m_pSchemaInfo->pColList[iSortCol-1].wType; LPBYTE pCurrCol = GetValuePtr(iSortCol, pData, m_rgDBBINDING); LPBYTE pPrevCol = GetValuePtr(iSortCol, m_pRowPrev, m_rgDBBINDING); LONG fComp; // We assume NULLs are equal if (!pCurrCol && !pPrevCol) continue; // If one of the values is NULL then we have to use DBPROP_NULLCOLLATION to decide // if they're sorted properly if ((pCurrCol == NULL) || (pPrevCol == NULL)) { if (pCurrCol == pPrevCol) fComp = 0; // Equal else if (pPrevCol == NULL && (m_ulNullCollation == DBPROPVAL_NC_LOW || m_ulNullCollation == DBPROPVAL_NC_START)) fComp = 1; // NULL was less than current value else if (pCurrCol == NULL && (m_ulNullCollation == DBPROPVAL_NC_HIGH || m_ulNullCollation == DBPROPVAL_NC_END)) fComp = 1; // Previous value was less than NULL else fComp = -1; // NULL was not properly sorted } else { // If the values don't compare properly, then it's a failure fComp = RelativeCompare(pCurrCol, pPrevCol, wType, 0, 0, 0, 0); } if (fComp > 0) { // We found a larger value fGreater = TRUE; break; } else if (fComp == 0) continue; else { // We found a smaller value, error fGreater = FALSE; CCOMPARE(m_ECHelper, fGreater == TRUE, EC_INCORRECT_SORT, L"Sort is incorrect", FALSE); break; } } if (!fGreater) fResult = FALSE; return fResult; } BOOL CHelper::VerifyValidTable(DBCOUNTITEM iRow, LPBYTE pData) { // We will only do this for certain specific schemas if (m_guidSchema == DBSCHEMA_TABLES || m_guidSchema == DBSCHEMA_TABLES_INFO || m_guidSchema == DBSCHEMA_COLUMNS) { // Try to open a rowset on the table. The first 3 bindings contain // Catalog, Schema, and Table Name, respectively GetColumnInfo(pData, m_rgDBBINDING); } return TRUE; } BOOL CHelper::VerifyLength(DBORDINAL iBind, DATA * pColumn) { DBTYPE wType = m_rgDBCOLUMNINFO[iBind].wType; size_t ulLength = GetDBTypeSize(wType); BOOL fResult = TRUE; // GetDBTypeSize won't return a value for variable length columns if (!ulLength) { switch(wType) { case DBTYPE_STR: ulLength = strlen((LPSTR)&pColumn->bValue); break; case DBTYPE_WSTR: ulLength = wcslen((LPWSTR)&pColumn->bValue)*sizeof(WCHAR); break; } } if (wType == DBTYPE_BYTES) { // We can't get the length of a BYTES column so we will just // attempt to access every byte in the hopes of crashing if // the length isn't valid. BYTE bVal; ULONG iByte; for (iByte = 0; iByte < pColumn->ulLength; iByte++) bVal = pColumn->bValue[iByte]; fResult = TRUE; } else fResult = COMPARE(pColumn->ulLength, ulLength); // Also, if the length is greater than cbMaxLen in the binding then // our status should be DBSTATUS_S_TRUNCATED if (pColumn->ulLength > m_rgDBBINDING[iBind].cbMaxLen) fResult &= COMPARE(pColumn->sStatus, DBSTATUS_S_TRUNCATED); return fResult; } BOOL CHelper::VerifyColumnCommon(DBORDINAL iBind, DATA * pColumn) { BOOL fResults = TRUE; DBORDINAL iOrdinal = m_rgDBBINDING[iBind].iOrdinal; // Can't verify column values if status is not OK if(pColumn->sStatus==DBSTATUS_S_OK) { // If restrictions were specified, validate they were honored fResults &= VerifyRestriction(iOrdinal, pColumn); // If the column requires a set of specific values, make sure // it's one of the acceptable values. fResults &= VerifyValue(iOrdinal, pColumn); // Perform column type-specific verification fResults &= VerifyTypeSpecific(iOrdinal, pColumn); // Verify the length fResults &= VerifyLength(iBind, pColumn); // Call the specific validation routine for this particular schema fResults &= VerifyColumn(iOrdinal, pColumn); } else if(pColumn->sStatus==DBSTATUS_S_ISNULL) { // Some columns may not contain a NULL, validate NULL is // OK for this column fResults &= VerifyNull(iOrdinal,pColumn); // Length should be 0 for NULL // COMPARE(pColumn->ulLength, 0); // Per spec, provider ignores length for NULL data // Call the specific validation routine for this particular schema // Some schema columns have varying instances where they can be NULL fResults &= VerifyColumn(iOrdinal, pColumn); } else { // A non-success status was returned, flag this as a failure // We don't think truncation is valid here PRVTRACE(L"%s=",m_rgDBCOLUMNINFO[iBind].pwszName); // Post a failure and print the status if not OK fResults &= COMPARE(RowsetBindingStatus((DBSTATUSENUM)pColumn->sStatus), TRUE); } return fResults; } BOOL CHelper::VerifyNull(DBORDINAL iOrdinal, DATA * pColumn) { BOOL fNull = FALSE; // The column's status was DBSTATUS_S_ISNULL, make sure this is OK // for this column. // If this is a provider-specific column just return TRUE that // NULL is allowed. if (iOrdinal > m_pSchemaInfo->cColumns) return TRUE; // Otherwise return the value from our table fNull = CompareNull(iOrdinal); return fNull; } BOOL CHelper::VerifyNonEmptyString(DATA * pColumn, LPWSTR pwszTable, LPWSTR pwszColumn) { DBSTATUS ulStatus = pColumn->sStatus; LPBYTE pValue = pColumn->bValue; BOOL fReturn = TRUE; if (!pwszTable) pwszTable = L""; if (!pwszColumn) pwszColumn = L""; if (ulStatus == DBSTATUS_S_OK) { // For now, just make sure the length is right so we read the value if (!COMPARE(wcslen((WCHAR *)pValue)*sizeof(WCHAR), pColumn->ulLength)) { odtLog << pwszTable << L": " << pwszColumn << L": " << L"Length is incorrect.\n"; fReturn=FALSE; } // We really don't expect empty strings for any of these if (!COMPARE(wcslen((WCHAR *)pValue) > 0, TRUE)) { odtLog << pwszTable << L": " << pwszColumn << L": " << L"Empty string returned.\n"; fReturn=FALSE; } } else if (!COMPARE(ulStatus, DBSTATUS_S_ISNULL)) { odtLog << pwszTable << L": " << pwszColumn << L": " << L"Invalid status returned.\n"; fReturn=FALSE; } return fReturn; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // CHelper::VerifyColumnMatch // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CHelper::VerifyColumnMatch(DBORDINAL iOrdinal1, DBORDINAL iOrdinal2) { LPWSTR pwszCol1 = (LPWSTR)GetValuePtr(iOrdinal1, m_pRow); LPWSTR pwszCol2 = (LPWSTR)GetValuePtr(iOrdinal2, m_pRow); if (!pwszCol1 && !pwszCol2) return TRUE; TESTC(pwszCol1 != NULL && pwszCol2 != NULL); TESTC(!wcscmp(pwszCol1, pwszCol2)); return TRUE; CLEANUP: return FALSE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // CHelper::VerifyTypeSpecific // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CHelper::VerifyTypeSpecific(DBORDINAL iOrdinal, DATA * pColumn) { DBTYPE wType = m_rgDBCOLUMNINFO[iOrdinal - m_rgDBCOLUMNINFO[0].iOrdinal].wType; BOOL fResult = FALSE; switch(wType) { case DBTYPE_WSTR: // We expect DBSTATUS_S_OK columns to have a non-empty string // Actually, we will comment this out, because there is nothing in the spec to prevent a provider // returning an empty string for some columns. // TESTC(wcslen((LPWSTR)pColumn->bValue) > 0); break; case DBTYPE_DATE: { // We expect a valid date, try to convert to bstr VARIANT vDate; HRESULT hr = E_FAIL; VariantInit(&vDate); V_VT(&vDate) = VT_DATE; V_DATE(&vDate) = *(DOUBLE *)&pColumn->bValue; hr = VariantChangeType(&vDate, &vDate, 0, VT_BSTR); VariantClear(&vDate); TESTC_(hr, S_OK); } break; default: // Do nothing break; } fResult = TRUE; CLEANUP: return fResult; } BOOL CHelper::VerifyValue(DBORDINAL iOrdinal, DATA * pColumn) { ULONG cValidVals; LPBYTE pValidVals; DBTYPE wType; ULONG ulTypeSize; BOOL fMatch = FALSE; // If this is a bookmark column, just return TRUE // If this is a provider-specific column that we do not know about then just return TRUE that // the value is allowed. if (!iOrdinal || iOrdinal > m_pSchemaInfo->cColumns) return TRUE; // If the column doesn't have a set of defined values, just return TRUE if (!m_pSchemaInfo->pColList[iOrdinal-1].cValidVals) return TRUE; // Get the values from the table cValidVals = m_pSchemaInfo->pColList[iOrdinal-1].cValidVals; pValidVals = (LPBYTE)m_pSchemaInfo->pColList[iOrdinal-1].pValidVals; wType = m_pSchemaInfo->pColList[iOrdinal-1].wType; ulTypeSize = GetDBTypeSize(wType); // GetDBTypeSize returns 0 for variable length types switch(wType) { case DBTYPE_STR: ulTypeSize = sizeof(LPSTR); break; case DBTYPE_WSTR: ulTypeSize = sizeof(LPWSTR); break; } // We must have a non-zero type size if (!COMPARE(ulTypeSize > 0, TRUE)) return FALSE; // If there is a count of values, make sure there is a set of values // so hopefully we don't crash if the table is bad if (!COMPARE(cValidVals && pValidVals, TRUE)) return FALSE; // Otherwise make sure it matches one of the values in our table for (ULONG iVal = 0; iVal < cValidVals; iVal++) { LPBYTE pValidVal = pValidVals; DBLENGTH cbBackEnd = ulTypeSize, cbConsumer = ulTypeSize; switch(wType) { case DBTYPE_STR: pValidVal = *(LPBYTE *)pValidVals; cbBackEnd = strlen((LPSTR)pValidVal); cbConsumer = strlen((LPSTR)pColumn->bValue); case DBTYPE_WSTR: pValidVal = *(LPBYTE *)pValidVals; cbBackEnd = wcslen((LPWSTR)pValidVal)*sizeof(WCHAR); cbConsumer = wcslen((LPWSTR)pColumn->bValue)*sizeof(WCHAR); break; } if (CompareDBTypeData(&pColumn->bValue, pValidVal, wType, cbBackEnd, 0, 0, NULL, FALSE, DBTYPE_EMPTY, cbConsumer)) { fMatch = TRUE; break; } pValidVals += ulTypeSize; } // Post a failure if we didn't find a match. // Providers are allowed to return provider if (!fMatch) { if (*(m_pSchemaInfo->pguid) == DBSCHEMA_TABLES && iOrdinal == TABLES_TABLE_TYPE) { // Providers are allowed to return provider specific values for TABLE_TYPE, so // we can only post a warning if the value doesn't match expected TABLE_TYPE's COMPAREW(fMatch, TRUE); } else COMPARE(fMatch, TRUE); odtLog << L"The value returned for column " << m_pSchemaInfo->pColList[iOrdinal-1].pwszName << L" was not in the list of valid values.\n"; } return fMatch; } BOOL CHelper::VerifyRestriction(DBORDINAL iOrdinal, DATA * pColumn) { // If this is a restriction column, make sure it matches expected BOOL fResult = FALSE; ULONG iRestrict; VARIANT * pVariant = NULL; // If we didn't pass any restrictions, just return TRUE if (!m_prgRestrictUsed) return TRUE; // If this is the bookmark column just return true if (!iOrdinal) return TRUE; // If this is not a restriction column for this schema just return TRUE for (iRestrict = 0; iRestrict < m_pSchemaInfo->cRestrictions; iRestrict++) { // Don't check restrictions we didn't actually use if (iRestrict >= m_cRestrictionsUsed) break; if (iOrdinal == m_pSchemaInfo->pulRestrictions[iRestrict]) { // This is a restriction column, is it restricted? if (V_VT(&m_prgRestrictUsed[iRestrict]) == VT_EMPTY) return TRUE; // Convert column value to a variant pVariant = DBTYPE2VARIANT(&pColumn->bValue, m_pSchemaInfo->pColList[iOrdinal-1].wType); TESTC(pVariant != NULL); // Compare the variants. Use case insensitive compare for BSTR restrictions TESTC(CompareVariant(pVariant, &m_prgRestrictUsed[iRestrict], FALSE)); // We found the restriction column, break out of the loop break; } } fResult = TRUE; CLEANUP: if (pVariant) VariantClear(pVariant); SAFE_FREE(pVariant); return TRUE; } HRESULT CHelper::GetColumnInfo(LPBYTE pData, DBBINDING * pBinding) { IOpenRowset * pIOpenRowset = NULL; IColumnsInfo * pIColumnsInfo = NULL; DBID dbid = DB_NULLID; HRESULT hr = E_FAIL; ULONG iBind = 0, iFirst = 0; LPWSTR pwszCat = NULL; LPWSTR pwszSch = NULL; LPWSTR pwszTable = NULL; LPWSTR pwszQualifiedName = NULL; DBPROPSET * prgPropSets = NULL; ULONG cPropSets = 0; // pData buffer contains bindings to TABLE_CATALOG, TABLE_SCHEMA, and TABLE_NAME, in that // order. // Skip any bookmark if (!pBinding[iBind].iOrdinal) iFirst++; for (iBind = 0; iBind < 3; iBind++) { // If value isn't bound then we assume NULL if (!VALUE_IS_BOUND(pBinding[iBind+iFirst])) continue; // Get a pointer to catalog, schema, and table name if (STATUS_IS_BOUND(pBinding[iBind+iFirst])) { // Check the status, which should always be OK or NULL if (STATUS_BINDING(pBinding[iBind+iFirst], pData) != DBSTATUS_S_OK) { COMPARE(STATUS_BINDING(pBinding[iBind+iFirst], pData), DBSTATUS_S_ISNULL); continue; } } // If status wasn't bound we assume OK, and length doesn't matter for null terminated string switch(pBinding[iBind+iFirst].iOrdinal) { case 1: pwszCat = (LPWSTR)&VALUE_BINDING(pBinding[iBind+iFirst], pData); break; case 2: pwszSch = (LPWSTR)&VALUE_BINDING(pBinding[iBind+iFirst], pData); break; case 3: pwszTable = (LPWSTR)&VALUE_BINDING(pBinding[iBind+iFirst], pData); break; default: COMPARE(pBinding[iBind+iFirst].iOrdinal < 4, TRUE); COMPARE(pBinding[iBind+iFirst].iOrdinal > 0, TRUE); } } // HACK FOR ORACLE if (pwszSch && wcslen(pwszSch) == 0) pwszSch = NULL; // Now we have either NULL or valid pointers to catalog, schema, table names TESTC_(m_pTable->GetQualifiedName(pwszCat, pwszSch, pwszTable,&pwszQualifiedName, TRUE), S_OK); // If we already have information for this table then just don't bother if (m_pwszTableName && !wcscmp(pwszQualifiedName, m_pwszTableName)) { m_ulTableOrdinal++; // If we couldn't actually retrieve the colinfo for this table then // return S_FALSE if (!m_prgColInfo) return S_FALSE; // Otherwise return success else return S_OK; } // Copy the table name into member var SAFE_FREE(m_pwszTableName); m_pwszTableName = pwszQualifiedName; // Initialize out params m_ulTableOrdinal = 1; // Note that schema rowset never reports bookmarks SAFE_FREE(m_prgColInfo); SAFE_FREE(m_pwszStringsBuffer); // Get IOpenRowset interface TESTC(VerifyInterface(m_pIDBSchemaRowset, IID_IOpenRowset, SESSION_INTERFACE, (IUnknown**)&pIOpenRowset)); // Create DBID from table name dbid.eKind = DBKIND_NAME; dbid.uName.pwszName = m_pwszTableName; // When retrieving column information for TABLES_INFO rowset we want a bookmark also if (m_guidSchema == DBSCHEMA_TABLES_INFO && SupportedProperty(DBPROP_BOOKMARKS, DBPROPSET_ROWSET, m_pCSchemaTest->m_pIDBInitialize, ROWSET_INTERFACE)) { TESTC_(SetProperty(DBPROP_BOOKMARKS, DBPROPSET_ROWSET, &cPropSets, &prgPropSets, DBTYPE_BOOL, VARIANT_TRUE), S_OK); } // Call OpenRowset hr = pIOpenRowset->OpenRowset(NULL, &dbid, NULL, IID_IColumnsInfo, cPropSets, prgPropSets, (IUnknown **)&pIColumnsInfo); if (FAILED(hr)) odtLog << m_pwszTableName << L": Unable to open table.\n"; // It's possible the table was deleted between the time we called GetRowset and attempting // to open the table, so we have to allow DB_E_NOTABLE, but post a warning. // It's also possible we don't have permission for the table. switch(hr) { case DB_E_NOTABLE: case DB_SEC_E_PERMISSIONDENIED: // Only post the warning when debugmode is FULL if (GetModInfo()->GetDebugMode() & DEBUGMODE_FULL) TESTW_(hr, S_OK); goto CLEANUP; default: TESTC_(hr, S_OK); } // Make sure we've got a valid interface ptr TESTC(pIColumnsInfo != NULL); // Now call GetColumnInfo. We already know cColumns so no need to return in member // var. TESTC_(hr = pIColumnsInfo->GetColumnInfo(&m_cColInfo, &m_prgColInfo, &m_pwszStringsBuffer), S_OK); CLEANUP: SAFE_RELEASE(pIOpenRowset); SAFE_RELEASE(pIColumnsInfo); return hr; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // GetRowset, execute method and check results // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - HRESULT CHelper::GetRowsetHelper ( IUnknown * pIUnknown, ULONG cRestrictions, VARIANT * prgRestrictions, REFIID riid, ULONG cPropertySets, DBPROPSET rgPropertySets[], IUnknown ** ppRowset, GUID guidSchema, BOOL fFreeRowset ) { HRESULT hr = E_FAIL; IUnknown * pIRowsetUnknown = NULL; if (m_fUseCommonArgumentDefaults) { // If we were not passed a valid schema then // just use the one for our helper class. if (guidSchema == GUID_NULL) guidSchema = m_guidSchema; switch(m_eRestrictArray) { case RT_CACHED: prgRestrictions = m_rgRestrict; break; case RT_SUPPORTED: prgRestrictions = m_rgRestrictValid; break; case RT_CUSTOM: prgRestrictions = m_rgRestrictUsed; break; default: COMPARE(0, 1); return E_FAIL; } // Set desired restrictions switch(cRestrictions) { // Pass a 0, NULL restriction case RV_NULL: cRestrictions = 0; prgRestrictions = NULL; break; // Pass all restrictions case RV_ALL: cRestrictions = m_pSchemaInfo->cRestrictions; break; // default: // COMPARE(cRestrictions <= m_pSchemaInfo->cRestrictions, TRUE); } // If not passed a rowset pointer, just use an internal one if (!ppRowset) ppRowset = (IUnknown **)&pIRowsetUnknown; } // Track which set of restrictions was actually used so we can validate them m_prgRestrictUsed = prgRestrictions; m_cRestrictionsUsed = cRestrictions; // Now get Schema rowset. hr=m_pIDBSchemaRowset->GetRowset(pIUnknown, guidSchema, cRestrictions, prgRestrictions, riid, cPropertySets, rgPropertySets, ppRowset); if (ppRowset) pIRowsetUnknown = *ppRowset; // Check results of GetRowset CheckResults(hr, riid, pIRowsetUnknown); if (fFreeRowset && ppRowset) SAFE_RELEASE(*ppRowset); return hr; } // Assertions schema specific functions class CAssertionsHelper : public CHelper { private: protected: BOOL VerifyColumn(DBORDINAL iOrdinal, DATA * pColumn); public: CAssertionsHelper(void) {m_guidSchema = DBSCHEMA_ASSERTIONS;} }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // CAssertionsHelper::VerifyColumn // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CAssertionsHelper::VerifyColumn(DBORDINAL iOrdinal, DATA * pColumn) { BOOL fResults = FALSE; switch(iOrdinal) { case 1:// CONSTRAINT CATALOG PRVTRACE(L"= %s\n",(TYPE_WSTR)pColumn->bValue); break; case 2://CONSTRAINT SCHEMA PRVTRACE(L"= %s\n",(TYPE_WSTR)pColumn->bValue); break; case 3://CONSTRAINT NAME PRVTRACE(L"= %s\n",(WCHAR *)pColumn->bValue); break; case 4: //IS_DEFERRABLE case 5: //INITIALLY_DEFERRED if(*(TYPE_BOOL *)pColumn->bValue==VARIANT_TRUE) PRVTRACE(L"TRUE\n"); else PRVTRACE(L"FALSE\n"); break; case 6: // DESCRIPTION PRVTRACE(L"= %s\n",(TYPE_WSTR)pColumn->bValue ); break; default: break; } return fResults; } // Catalogs schema specific functions class CCatalogsHelper : public CHelper { private: protected: public: CCatalogsHelper(void) {m_guidSchema = DBSCHEMA_CATALOGS;} }; // Catalogs schema specific functions class CLargeRestrictionCatalogsHelper : public CCatalogsHelper { private: protected: virtual BOOL VerifyRestriction(DBORDINAL iOrdinal, DATA * pColumn); public: CLargeRestrictionCatalogsHelper(void) {} }; BOOL CLargeRestrictionCatalogsHelper::VerifyRestriction(DBORDINAL iOrdinal, DATA * pColumn) { return CCatalogsHelper::VerifyRestriction(iOrdinal, pColumn); } // Character Sets schema specific functions class CCharacterSetsHelper : public CHelper { private: protected: public: CCharacterSetsHelper(void) {m_guidSchema = DBSCHEMA_CHARACTER_SETS;} }; // Check Constraints schema specific functions class CCheckConstraintsHelper : public CHelper { private: protected: BOOL InsertRows(void); public: CCheckConstraintsHelper(void) {m_guidSchema = DBSCHEMA_CHECK_CONSTRAINTS;} }; BOOL CCheckConstraintsHelper::InsertRows(void) { return CreateCheckConstraints(); } // CheckConstraintsByTable schema specific functions class CCheckConstraintsByTableHelper : public CHelper { private: protected: BOOL VerifyColumn(DBORDINAL iOrdinal, DATA * pColumn); BOOL InsertRows(void); public: CCheckConstraintsByTableHelper(void) {m_guidSchema = DBSCHEMA_CHECK_CONSTRAINTS_BY_TABLE;} }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // CCheckConstraintsByTableHelper::InsertRows // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CCheckConstraintsByTableHelper::InsertRows(void) { return CreateCheckConstraints(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // CCheckConstraintsByTableHelper::VerifyColumn // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CCheckConstraintsByTableHelper::VerifyColumn(DBORDINAL iOrdinal, DATA * pColumn) { BOOL fResults = TRUE; // For now switch(iOrdinal) { case CCBTS_TABLE_CATALOG: // Verify matches DBPROPSET_DATASOURCE, DBPROP_CURRENTCATALOG break; case CCBTS_TABLE_SCHEMA: // Verify matches DBPROPSET_DATASOURCEINFO, DBPROP_USERNAME when tablename // is automaketable name break; case CCBTS_TABLE_NAME: break; case CCBTS_CONSTRAINT_CATALOG: // Validate matches TABLE_CATALOG? case CCBTS_CONSTRAINT_SCHEMA: // Validate matches TABLE_CATALOG? case CCBTS_CONSTRAINT_NAME: // Validate non-NULL case CCBTS_CHECK_CLAUSE: // Validate this matches check clause we created for automaketable case CCBTS_DESCRIPTION: break; default: // Provider-specific column, can't validate break; } return fResults; } // Collations schema specific functions class CCollationsHelper : public CHelper { private: protected: public: CCollationsHelper(void) {m_guidSchema = DBSCHEMA_COLLATIONS;} }; // Column Domain Usage schema specific functions class CColumnDomainUsageHelper : public CHelper { private: protected: public: CColumnDomainUsageHelper(void) {m_guidSchema = DBSCHEMA_COLUMN_DOMAIN_USAGE;} }; // Column Privileges schema specific functions class CColumnPrivilegesHelper : public CHelper { private: protected: public: CColumnPrivilegesHelper(void) {m_guidSchema = DBSCHEMA_COLUMN_PRIVILEGES;} }; // Columns schema specific functions class CColumnsHelper : public CHelper { private: CErrorCache m_EC; // Columns error cache protected: BOOL VerifyColumn(DBORDINAL iOrdinal, DATA * pColumn); public: CColumnsHelper(void) {m_guidSchema = DBSCHEMA_COLUMNS;} BOOL Init(CSchemaTest * pThis); }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // CColumnsHelper::Init // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CColumnsHelper::Init(CSchemaTest * pThis) { if (CHelper::Init(pThis)) return m_EC.Init(GetModInfo()->GetDebugMode()); else return FALSE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // CColumnsHelper::VerifyColumn // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CColumnsHelper::VerifyColumn(DBORDINAL iOrdinal, DATA * pColumn) { LPWSTR pwszSchemaName = (LPWSTR)GetValuePtr(COLS_TABLE_SCHEMA, m_pRow); LPWSTR pwszTableName = (LPWSTR)GetValuePtr(COLS_TABLE_NAME, m_pRow); LPWSTR pwszColumnName = (LPWSTR)GetValuePtr(COLS_COLUMN_NAME, m_pRow); LPWSTR pwszColumnDefault = (LPWSTR)GetValuePtr(COLS_COLUMN_DEFAULT, m_pRow); ULONG * pulOrdinal = (ULONG *)GetValuePtr(COLS_ORDINAL_POSITION, m_pRow); LPBYTE pValue = GetValuePtr(iOrdinal, m_pRow); BOOL fResult = FALSE; ULONG iIndex = 0; DBSTATUS ulStatus = pColumn->sStatus; DBTYPE wType = 0; // Compute index into colinfo given this ordinal if (m_prgColInfo && pulOrdinal) iIndex = *pulOrdinal + !m_prgColInfo[0].iOrdinal - 1; // Need the column name to verify // Note: We may be able to get by without this by computing the index via // counting the rows in this table, but since providers don't have to return // rows in ordinal order this is likely to be wrong. TESTC(pwszColumnName != NULL); // If we don't have the right index we can't verify if (m_prgColInfo && m_prgColInfo[iIndex].pwszName && RelCompareString(pwszColumnName, m_prgColInfo[iIndex].pwszName)) { // Names didn't match, so we have to search for the index for (iIndex = 0; iIndex < m_cColInfo; iIndex++) if (!RelCompareString(pwszColumnName, m_prgColInfo[iIndex].pwszName)) break; } // Make sure we found the matching index. If we didn't get m_prgColInfo then // we don't index into it below. if (m_prgColInfo) { TESTC(iIndex < m_cColInfo); wType = m_prgColInfo[iIndex].wType; } else wType = (DBTYPE)GetValuePtr(COLS_DATA_TYPE, m_pRow); switch(iOrdinal) { case COLS_TABLE_CATALOG: break; case COLS_TABLE_SCHEMA: break; case COLS_TABLE_NAME: break; case COLS_COLUMN_NAME: break; case COLS_COLUMN_GUID: break; case COLS_TYPE_GUID: break; case COLS_COLUMN_PROPID: break; case COLS_ORDINAL_POSITION: // Status is OK, warning if ordinals don't match // Providers are not required to return results in ordinal order, since // sort is only on catalog, schema, and name, so only a warning. // If restriction is only on column then the ordinal may not match anyway. // We will assume if the index for the matching ordinal contains // the proper column name that it was the right ordinal. if (pulOrdinal && m_prgColInfo && !COMPARE(*pulOrdinal, m_prgColInfo[iIndex].iOrdinal)) odtLog << pwszTableName << L": " << m_prgColInfo[iIndex].pwszName << L": " << L"Ordinal didn't match expected value.\n"; break; case COLS_COLUMN_FLAGS: if (m_prgColInfo) { COMPARE(m_prgColInfo[iIndex].dwFlags, *(DBCOLUMNFLAGS *)pValue); } break; case COLS_CHARACTER_MAXIMUM_LENGTH: if (m_prgColInfo) { switch(m_prgColInfo[iIndex].wType) { // case DBTYPE_BOOL: // We assume BOOL is not a "bit" column per spec. case DBTYPE_UDT: case DBTYPE_BYTES: case DBTYPE_STR: case DBTYPE_WSTR: if (COMPARE(ulStatus, DBSTATUS_S_OK)) { if (m_prgColInfo[iIndex].ulColumnSize == ~0) { if (!COMPARE(*(ULONG *)pValue, 0)) odtLog << m_pwszTableName << L": " << m_prgColInfo[iIndex].pwszName << L": " << L"Must be 0 for column without defined max length.\n"; } else CCOMPARE(m_EC, *(ULONG *)pValue == m_prgColInfo[iIndex].ulColumnSize, EC_BAD_CHARACTER_MAXIMUM_LENGTH, L"CHARACTER_MAXIMUM_LENGTH value did not match GetColumnInfo", FALSE); } else odtLog << pwszTableName << L": " << m_prgColInfo[iIndex].pwszName << L": " << L"Cannot be NULL for variable length column.\n"; break; // NULL for all other data types default: if (!COMPARE(ulStatus, DBSTATUS_S_ISNULL)) odtLog << m_pwszTableName << L": " << m_prgColInfo[iIndex].pwszName << L": " << L"Status was not DBSTATUS_S_ISNULL for non-char, binary, or bit column\n"; } } break; case COLS_CHARACTER_OCTET_LENGTH: if (m_prgColInfo) { switch(m_prgColInfo[iIndex].wType) { case DBTYPE_UDT: case DBTYPE_BYTES: case DBTYPE_STR: case DBTYPE_WSTR: if (COMPARE(ulStatus, DBSTATUS_S_OK)) { if (m_prgColInfo[iIndex].ulColumnSize == ~0) { if (!COMPARE(*(ULONG *)pValue, 0)) odtLog << m_pwszTableName << L": " << m_prgColInfo[iIndex].pwszName << L": " << L"Must be 0 for column without defined max length.\n"; } else { DBLENGTH ulOctetLen = m_prgColInfo[iIndex].ulColumnSize; if (m_prgColInfo[iIndex].wType == DBTYPE_WSTR) ulOctetLen *= sizeof(WCHAR); CCOMPARE(m_EC, ulOctetLen == *(ULONG *)pValue, EC_BAD_CHARACTER_OCTET_LENGTH, L"CHARACTER_OCTET_LENGTH value did not match GetColumnInfo", FALSE); } } break; // NULL for all other data types default: if (!COMPARE(ulStatus, DBSTATUS_S_ISNULL)) odtLog << m_pwszTableName << L": " << m_prgColInfo[iIndex].pwszName << L": " << L"Status was not DBSTATUS_S_ISNULL for non-char, binary, or bit column\n"; } } break; case COLS_DATETIME_PRECISION: if (m_prgColInfo) { switch(m_prgColInfo[iIndex].wType) { case DBTYPE_DBTIMESTAMP: // The following types are new for 9.0 and do support DATETIME_PRECISION per spec #ifdef __UTC_ case DBTYPE_DBUTCDATETIME: case DBTYPE_DBTIME_EX: case DBTYPE_DBDATE: #endif // DATETIME_PRECISION matches IColumnsInfo bScale vaue if (COMPARE(ulStatus, DBSTATUS_S_OK) && !COMPARE((ULONG)m_prgColInfo[iIndex].bScale, *(ULONG *)pValue)) /* CCOMPARE(m_EC, *(ULONG *)pValue == (ULONG)m_prgColInfo[iIndex].bScale, EC_BAD_DATETIME_PRECISION, L"DATETIME_PRECISION value did not match GetColumnInfo", FALSE); */ odtLog << m_pwszTableName << L": " << m_prgColInfo[iIndex].pwszName << L"DATETIME_PRECISION value did not match GetColumnInfo" << L" \n"; break; // NULL for all other data types default: if (!COMPARE(ulStatus, DBSTATUS_S_ISNULL)) odtLog << m_pwszTableName << L": " << m_prgColInfo[iIndex].pwszName << L": " << L"Status was not DBSTATUS_S_ISNULL for non-char, binary, or bit column\n"; } } break; case COLS_COLUMN_HASDEFAULT: // We can't actually try the default value except for our test table, so we don't know // if it actually would work or not for other tables. // Note that COLUMN_DEFAULT may be NULL even if HASDEFAULT is TRUE but the converse // is not true. if (COMPARE(ulStatus, DBSTATUS_S_OK)) { // If the COLUMN_DEFAULT is non-NULL, then HASDEFAULT should be TRUE, otherwise // we're not sure if (pwszColumnDefault && !COMPARE(*(VARIANT_BOOL *)pValue, VARIANT_TRUE)) odtLog << pwszTableName << L": " << rgwszCOLUMNS[iOrdinal-1] << L": " << L"Invalid value returned.\n"; // TODO: If the current table is the automaketable for this test try to use the default // value and make sure it matches expected. } else odtLog << pwszTableName << L": " << m_prgColInfo[iIndex].pwszName << L": " << L"Invalid status returned.\n"; break; case COLS_COLUMN_DEFAULT: if (ulStatus == DBSTATUS_S_OK) { // For now, just make sure the length is right so we read the default value if (!COMPARE(wcslen(pwszColumnDefault)*sizeof(WCHAR), pColumn->ulLength)) odtLog << m_pwszTableName << L": " << m_prgColInfo[iIndex].pwszName << L": " << L"Default value has the wrong length.\n"; // TODO: If the current table is the automaketable for this test try to use the default // value and make sure it matches expected. } break; case COLS_IS_NULLABLE: if (m_prgColInfo) { DBCOLUMNFLAGS dwNullableFlag = m_prgColInfo[iIndex].dwFlags & DBCOLUMNFLAGS_ISNULLABLE; DBCOLUMNFLAGS dwISNULLABLEFlag = *(VARIANT_BOOL *)pValue == VARIANT_TRUE ? DBCOLUMNFLAGS_ISNULLABLE : 0; if (!COMPARE(dwNullableFlag, dwISNULLABLEFlag)) odtLog << m_pwszTableName << L": " << m_prgColInfo[iIndex].pwszName << L": " << L"DBCOLUMNFLAGS_ISNULLABLE incorrect value returned.\n"; /* // Turn this column's value into DBCOLUMNFLAGS and use CompareColumnFlags VARIANT_BOOL fNullable = m_prgColInfo[iIndex].dwFlags & DBCOLUMNFLAGS_ISNULLABLE ? VARIANT_TRUE : VARIANT_FALSE; if (!COMPARE(fNullable, *(VARIANT_BOOL *)pValue)) odtLog << m_pwszTableName << L": " << m_prgColInfo[iIndex].pwszName << L": " << L"DBCOLUMNFLAGS_ISNULLABLE incorrect value returned.\n"; */ } break; case COLS_DATA_TYPE: // This column cannot contain NULL if (COMPARE(ulStatus, DBSTATUS_S_OK) && m_prgColInfo && !COMPARE(m_prgColInfo[iIndex].wType, *(DBTYPE *)pValue)) odtLog << m_pwszTableName << L": " << m_prgColInfo[iIndex].pwszName << L": " << L"Invalid value returned for data type. Expected: " << m_prgColInfo[iIndex].wType << L" Received: " << *(DBTYPE *)pValue << L" \n"; break; case COLS_NUMERIC_PRECISION: if (m_prgColInfo) { if (IsNumericType(m_prgColInfo[iIndex].wType)) { if (COMPARE(ulStatus, DBSTATUS_S_OK)) { CCOMPARE(m_EC, *(USHORT *)pValue == (USHORT)m_prgColInfo[iIndex].bPrecision, EC_COLUMNS_BAD_NUMERIC_PRECISION, L"NUMERIC_PRECISION is incorrect", FALSE); } } // NULL for all other data types else if (!COMPARE(ulStatus, DBSTATUS_S_ISNULL)) odtLog << m_pwszTableName << L": " << m_prgColInfo[iIndex].pwszName << L": " << L"Status was not DBSTATUS_S_ISNULL for non-numeric column\n"; } break; case COLS_NUMERIC_SCALE: if (m_prgColInfo) { if (m_prgColInfo[iIndex].wType == DBTYPE_DECIMAL || m_prgColInfo[iIndex].wType == DBTYPE_NUMERIC || m_prgColInfo[iIndex].wType == DBTYPE_VARNUMERIC) { CCOMPARE(m_EC, ulStatus == DBSTATUS_S_OK, EC_COLUMNS_NULL_NUMERIC_SCALE, L"NUMERIC_SCALE cannot be NULL for numeric column", FALSE); if (ulStatus==DBSTATUS_S_OK) { SHORT sScale = (SHORT)m_prgColInfo[iIndex].bScale; // Account for negative scale values if (m_prgColInfo[iIndex].dwFlags & DBCOLUMNFLAGS_SCALEISNEGATIVE) sScale = -sScale; if (!COMPARE(*(SHORT *)pValue, sScale)) odtLog << m_pwszTableName << L": " << m_prgColInfo[iIndex].pwszName << L": " << L"Invalid value returned.\n"; } } // NULL for all other data types else if (!COMPARE(ulStatus, DBSTATUS_S_ISNULL)) odtLog << m_pwszTableName << L": " << m_prgColInfo[iIndex].pwszName << L": " << L"Status was not DBSTATUS_S_ISNULL for non-DECIMAL, NUMERIC column\n"; } break; case COLS_CHARACTER_SET_CATALOG: case COLS_CHARACTER_SET_SCHEMA: case COLS_CHARACTER_SET_NAME: case COLS_COLLATION_CATALOG: case COLS_COLLATION_SCHEMA: case COLS_COLLATION_NAME: case COLS_DOMAIN_CATALOG: case COLS_DOMAIN_SCHEMA: case COLS_DOMAIN_NAME: VerifyNonEmptyString(pColumn, m_pwszTableName, m_prgColInfo ? m_prgColInfo[iIndex].pwszName: L""); break; case COLS_DESCRIPTION: break; } fResult = TRUE; CLEANUP: return fResult; } // Constraint Column Usage schema specific functions class CConstraintTableUsageHelper : public CHelper { private: protected: public: CConstraintTableUsageHelper(void) {m_guidSchema = DBSCHEMA_CONSTRAINT_TABLE_USAGE;} }; // Constraint Column Usage schema specific functions class CConstraintColumnUsageHelper : public CHelper { private: protected: BOOL InsertRows(void); public: CConstraintColumnUsageHelper(void) {m_guidSchema = DBSCHEMA_CONSTRAINT_COLUMN_USAGE;} }; BOOL CConstraintColumnUsageHelper::InsertRows(void) { return CreateCheckConstraints(); } // Foreign Keys schema specific functions class CForeignKeysHelper : public CHelper { private: protected: public: CForeignKeysHelper(void) {m_guidSchema = DBSCHEMA_FOREIGN_KEYS;} }; // Indexes schema specific functions class CIndexesHelper : public CHelper { private: CErrorCache m_EC; // Indexes error cache protected: BOOL CompareNull(DBORDINAL iOrdinal); public: CIndexesHelper(void) {m_guidSchema = DBSCHEMA_INDEXES;} BOOL Init(CSchemaTest * pThis); }; BOOL CIndexesHelper::CompareNull(DBORDINAL iOrdinal) { switch (iOrdinal) { case IS_NULLS: return CCOMPARE(m_EC, m_pSchemaInfo->pColList[iOrdinal-1].fAllowNull == TRUE, EC_INDEXES_NULLS_ISNULL, L"NULLS column cannot be DBSTATUS_S_ISNULL", FALSE); case IS_INDEX_NAME: return CCOMPARE(m_EC, m_pSchemaInfo->pColList[iOrdinal-1].fAllowNull == TRUE, EC_INDEXES_INDEX_NAME_ISNULL, L"INDEX_NAME column cannot be DBSTATUS_S_ISNULL", FALSE); case IS_UNIQUE: return CCOMPARE(m_EC, m_pSchemaInfo->pColList[iOrdinal-1].fAllowNull == TRUE, EC_INDEXES_UNIQUE_ISNULL, L"UNIQUE column cannot be DBSTATUS_S_ISNULL", FALSE); case IS_AUTO_UPDATE: return CCOMPARE(m_EC, m_pSchemaInfo->pColList[iOrdinal-1].fAllowNull == TRUE, EC_INDEXES_AUTO_UPDATE_ISNULL, L"AUTO_UPDATE column cannot be DBSTATUS_S_ISNULL", FALSE); } return CHelper::CompareNull(iOrdinal); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // CIndexesHelper::Init // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CIndexesHelper::Init(CSchemaTest * pThis) { if (CHelper::Init(pThis)) return m_EC.Init(GetModInfo()->GetDebugMode()); else return FALSE; } // Key Column Usage schema specific functions class CKeyColumnUsageHelper : public CHelper { private: protected: public: CKeyColumnUsageHelper(void) {m_guidSchema = DBSCHEMA_KEY_COLUMN_USAGE;} }; // Primary Keys schema specific functions class CPrimaryKeysHelper : public CHelper { private: protected: public: CPrimaryKeysHelper(void) {m_guidSchema = DBSCHEMA_PRIMARY_KEYS;} }; // Procedures schema specific functions class CProceduresHelper : public CHelper { private: CErrorCache m_EC; // Error cache protected: BOOL CompareNull(DBORDINAL iOrdinal); public: CProceduresHelper(void) {m_guidSchema = DBSCHEMA_PROCEDURES;} BOOL Init(CSchemaTest * pThis); }; BOOL CProceduresHelper::CompareNull(DBORDINAL iOrdinal) { if (iOrdinal == PRS_PROCEDURE_DEFINITION) return CCOMPARE(m_EC, m_pSchemaInfo->pColList[iOrdinal-1].fAllowNull == TRUE, EC_PROCEDURES_PROC_DEF_ISNULL, L"PROCEDURE_DEFINITION column cannot be DBSTATUS_S_ISNULL", FALSE); else return CHelper::CompareNull(iOrdinal); } BOOL CProceduresHelper::Init(CSchemaTest * pThis) { if (CHelper::Init(pThis)) return m_EC.Init(GetModInfo()->GetDebugMode()); else return FALSE; } // Procedure Columns schema specific functions class CProcedureColumnsHelper : public CHelper { private: CErrorCache m_EC; // Error cache protected: BOOL CompareNull(DBORDINAL iOrdinal); BOOL VerifyValue(DBORDINAL iOrdinal, DATA * pColumn); public: CProcedureColumnsHelper(void) {m_guidSchema = DBSCHEMA_PROCEDURE_COLUMNS;} BOOL Init(CSchemaTest * pThis); }; BOOL CProcedureColumnsHelper::CompareNull(DBORDINAL iOrdinal) { if (iOrdinal == PCS_COLS_IS_NULLABLE) return CCOMPARE(m_EC, m_pSchemaInfo->pColList[iOrdinal-1].fAllowNull == TRUE, EC_PROC_COLS_IS_NULLABLE_ISNULL, L"IS_NULLABLE column cannot be DBSTATUS_S_ISNULL", FALSE); else return CHelper::CompareNull(iOrdinal); } BOOL CProcedureColumnsHelper::Init(CSchemaTest * pThis) { if (CHelper::Init(pThis)) return m_EC.Init(GetModInfo()->GetDebugMode()); else return FALSE; } BOOL CProcedureColumnsHelper::VerifyValue(DBORDINAL iOrdinal, DATA * pColumn) { ULONG cValidVals; LPBYTE pValidVals; DBTYPE wType; ULONG ulTypeSize; BOOL fMatch = FALSE; // If this is a bookmark column, just return TRUE // If this is a provider-specific column just return TRUE that // the value is allowed. if (!iOrdinal || iOrdinal > m_pSchemaInfo->cColumns) return TRUE; // If the column doesn't have a set of defined values, just return TRUE if (!m_pSchemaInfo->pColList[iOrdinal-1].cValidVals) return TRUE; // Get the values from the table cValidVals = m_pSchemaInfo->pColList[iOrdinal-1].cValidVals; pValidVals = (LPBYTE)m_pSchemaInfo->pColList[iOrdinal-1].pValidVals; wType = m_pSchemaInfo->pColList[iOrdinal-1].wType; ulTypeSize = GetDBTypeSize(wType); // GetDBTypeSize returns 0 for variable length types switch(wType) { case DBTYPE_STR: ulTypeSize = sizeof(LPSTR); break; case DBTYPE_WSTR: ulTypeSize = sizeof(LPWSTR); break; } // We must have a non-zero type size if (!COMPARE(ulTypeSize > 0, TRUE)) return FALSE; // If there is a count of values, make sure there is a set of values // so hopefully we don't crash if the table is bad if (!COMPARE(cValidVals && pValidVals, TRUE)) return FALSE; // Otherwise make sure it matches one of the values in our table for (ULONG iVal = 0; iVal < cValidVals; iVal++) { LPBYTE pValidVal = pValidVals; DBLENGTH cbBackEnd = ulTypeSize, cbConsumer = ulTypeSize; switch(wType) { case DBTYPE_STR: pValidVal = *(LPBYTE *)pValidVals; cbBackEnd = strlen((LPSTR)pValidVal); cbConsumer = strlen((LPSTR)pColumn->bValue); case DBTYPE_WSTR: pValidVal = *(LPBYTE *)pValidVals; cbBackEnd = wcslen((LPWSTR)pValidVal)*sizeof(WCHAR); cbConsumer = wcslen((LPWSTR)pColumn->bValue)*sizeof(WCHAR); break; } if (CompareDBTypeData(&pColumn->bValue, pValidVal, wType, cbBackEnd, 0, 0, NULL, FALSE, DBTYPE_EMPTY, cbConsumer)) { fMatch = TRUE; break; } pValidVals += ulTypeSize; } // Post a failure if we didn't find a match if (iOrdinal == PCS_COLS_IS_NULLABLE) { // Only post this failure once CCOMPARE(m_EC, fMatch == TRUE, EC_INVALID_IS_NULLABLE, L"IS_NULLABLE value was not in list of valid values", FALSE); } else if (!COMPARE(fMatch, TRUE)) odtLog << L"The value returned for column " << m_pSchemaInfo->pColList[iOrdinal-1].pwszName << L" was not in the list of valid values.\n"; return fMatch; } // Procedure Parameters schema specific functions class CProcedureParametersHelper : public CHelper { private: LPWSTR m_pwszQualifiedName; DB_UPARAMS m_cParams; DB_UPARAMS m_cPropParams; DBPARAMINFO * m_pParamInfo; LPWSTR m_pNamesBuffer; SHORT m_iOrdinalPrev; UWORD m_iOrdinalStart; protected: BOOL VerifyColumn(DBORDINAL iOrdinal, DATA * pColumn); BOOL GetParamInfo(void); BOOL InsertRows(void); public: CProcedureParametersHelper(void) { m_guidSchema = DBSCHEMA_PROCEDURE_PARAMETERS; m_pwszQualifiedName = NULL; m_pParamInfo = NULL; m_pNamesBuffer = NULL; } ~CProcedureParametersHelper(void) { SAFE_FREE(m_pwszQualifiedName); SAFE_FREE(m_pParamInfo); SAFE_FREE(m_pNamesBuffer); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // CProcedureParametersHelper::InsertRows // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CProcedureParametersHelper::InsertRows(void) { return CreateStoredProcs(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // CProcedureParametersHelper::GetParamInfo // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CProcedureParametersHelper::GetParamInfo(void) { BOOL fRet = FALSE; LPWSTR pwszProcCat = (LPWSTR)GetValuePtr(PPS_PROCEDURE_CATALOG, m_pRow); LPWSTR pwszProcSchema = (LPWSTR)GetValuePtr(PPS_PROCEDURE_SCHEMA, m_pRow); LPWSTR pwszProcName = (LPWSTR)GetValuePtr(PPS_PROCEDURE_NAME, m_pRow); DBTYPE * pwType = (DBTYPE *)GetValuePtr(PPS_DATA_TYPE, m_pRow); UWORD * piOrdinal = (UWORD *)GetValuePtr(PPS_ORDINAL_POSITION, m_pRow); LPWSTR pwszQualifiedName= NULL; IDBCreateSession * pIDBCreateSession = NULL; IDBCreateCommand * pIDBCreateCommand = NULL; ICommand * pICmd = NULL; ICommandWithParameters * pICmdWPar = NULL; ICommandText * pICmdText = NULL; ICommandPrepare * pICmdPrep = NULL; LPWSTR pwszCmdFormat1 = L"{call %s}"; // {call procname} LPWSTR pwszCmdFormat2 = L"{call %s(%s)}"; // {call procname(procparams)} LPWSTR pwszCmdFormat1r = L"{?=call %s}"; // {call procname} LPWSTR pwszCmdFormat2r = L"{?=call %s(%s)}"; // {call procname(procparams)} LPWSTR pwszProcVersion = NULL; ULONG iParam, ccCmdBufSize = 1000; HRESULT hr = S_OK; LPWSTR pwszCmd = NULL; WCHAR wszMarkers[MAX_PARAM_COUNT*2] = L""; // Each parameter requires ",?" LPWSTR pwszCmdFmt = pwszCmdFormat1; size_t ulValidLen = 0; BOOL fFoundParamCount = FALSE; TESTC(pwszProcCat != NULL); TESTC(pwszProcSchema && pwszProcName && pwType); // If the proc name contains a semicolon, then we have to build the fully // qualified name w/o the ;nn part because those are not really part of the // name. This should only occur for SQL Server wcstok(pwszProcName, L";"); // Create fully qualified name from the 3 values TESTC_(m_pTable->GetQualifiedName( pwszProcCat, pwszProcSchema, pwszProcName, &pwszQualifiedName, TRUE), S_OK); // Deal with remaining numeric portion of proc version. if (pwszProcVersion = wcstok(NULL, L";")) { // Put back the semicolon in the proc name pwszProcVersion[-1] = L';'; // Realloc the qualified name to allow space for the version. SAFE_REALLOC(pwszQualifiedName, WCHAR, wcslen(pwszQualifiedName)+wcslen(pwszProcVersion-1)+sizeof(WCHAR)); // Concat on the version wcscat(pwszQualifiedName, pwszProcVersion-1); } // Have to assume the ordinal position increments if (!piOrdinal) { m_iOrdinalPrev++; } // If this matches the previously obtained fully qualified name then // we have the same proc, just exit. if (m_pwszQualifiedName && !wcscmp(pwszQualifiedName, m_pwszQualifiedName)) return TRUE; // Allocate some space for command buffer SAFE_ALLOC(pwszCmd, WCHAR, ccCmdBufSize); pwszCmd[0] = L'\0'; // Init to empty // This is a different stored proc, get the parameter information SAFE_FREE(m_pwszQualifiedName); m_pwszQualifiedName = pwszQualifiedName; SAFE_FREE(m_pNamesBuffer); // Reset our previous ordinal info and starting ordinal for this proc if (piOrdinal) { m_iOrdinalStart = *piOrdinal; m_iOrdinalPrev = *piOrdinal-1; } else { // Have to assume the ordinal position starts at 1 m_iOrdinalPrev = 0; m_iOrdinalStart = 1; } // ---------------------------------------------------------------- // Spawn off an entirely new connection to work around provider bug // ---------------------------------------------------------------- TESTC(VerifyInterface(g_pIDBInitialize, IID_IDBCreateSession, DATASOURCE_INTERFACE, (IUnknown **)&pIDBCreateSession)); TESTC_(pIDBCreateSession->CreateSession(NULL, IID_IDBCreateCommand, (IUnknown **)&pIDBCreateCommand), S_OK); // Get a fresh command object TESTC_(pIDBCreateCommand->CreateCommand( NULL, IID_ICommand, (IUnknown **)&pICmd), S_OK); // pICmd = m_pTable->get_ICommandPTR(); // ---------------------------------------------------------------- // Remove above block and associated variables when provider bug is fixed. // ---------------------------------------------------------------- TESTC(VerifyInterface(pICmd, IID_ICommandText, COMMAND_INTERFACE, (IUnknown **)&pICmdText)) TESTC(VerifyInterface(pICmd, IID_ICommandPrepare, COMMAND_INTERFACE, (IUnknown **)&pICmdPrep)) // We should always be able to get ICommandWithParameters if there is PROCEDURE_PARAMETERS rowset TESTC(VerifyInterface(pICmd, IID_ICommandWithParameters, COMMAND_INTERFACE, (IUnknown **)&pICmdWPar)); m_cParams=0; if (m_cTotalRows == 1) { odtLog << L"Bug here - can't prepare command on 2nd cmd obj if schema open on first cmd obj?\n"; // COMPAREW(0,1); } // If there is a return param, use that form // if (m_iOrdinalStart == 0) pwszCmdFmt = pwszCmdFormat1r; // Assume there may be up to 50 params for (iParam = 0; iParam < MAX_PARAM_COUNT; iParam++) { if (wcslen(pwszCmdFmt) + wcslen(m_pwszQualifiedName) + wcslen(wszMarkers) > ccCmdBufSize) { // Double the command buffer size and reallocate ccCmdBufSize *= 2; SAFE_REALLOC(pwszCmd, WCHAR, ccCmdBufSize); } // Build the command swprintf(pwszCmd, pwszCmdFmt, m_pwszQualifiedName, wszMarkers); // swprintf(pwszCmd, pwszCmdFmt, pwszProcName, wszMarkers); TESTC_(pICmdText->SetCommandText(DBGUID_DEFAULT, pwszCmd), S_OK); hr = pICmdPrep->Prepare(1); // We expect S_OK or DB_E_ERRORSINCOMMAND here if (E_FAIL == hr) { CHECKW(hr, DB_E_ERRORSINCOMMAND); } else { TEST2C_(hr, S_OK, DB_E_ERRORSINCOMMAND); } // ODBC drivers are allowed to succeed for Prepare() even if param count // is more than actual number of parameters. For ODBC, need to use // GetParameterInfo to keep the driver honest. if (hr == S_OK) { // Don't leak previous param info SAFE_FREE(m_pParamInfo); SAFE_FREE(m_pNamesBuffer); // Temporarily print command executed // odtLog << L"Prepared: " << pwszCmd << L"\n"; // Get new param info hr = pICmdWPar->GetParameterInfo(&m_cParams, &m_pParamInfo, &m_pNamesBuffer); TEST2C_(hr, S_OK, E_FAIL); } // Some providers will return S_OK for more param markers than required, but // m_cParams will be set to the proper number of parameters if (FAILED(hr) || m_cParams < iParam) { // Post failure if provider returns param count less than requested for S_OK // COMPARE(hr != S_OK || m_cParams >= iParam+1, TRUE); // Strip off the last param if (iParam > 1) // If iParam == 1 then 0 params were allowed { pwszCmd[ulValidLen-2] = L'\0'; wcscat(pwszCmd, L")"); } else { // We can get here if provider specifies there is a return param // but fails the prepare if there is a return param present, or if // the provider specifies there is no return param but fails prepare // w/o params, or if there are no additional params beyond the return // param. // ASSERT(ulValidLen > 0); TESTC(ulValidLen != 0); pwszCmd[ulValidLen-1] = L'\0'; } // Add back the closing bracket wcscat(pwszCmd, L"}"); // Set and Prepare again TESTC_(pICmdText->SetCommandText(DBGUID_DEFAULT, pwszCmd), S_OK); TESTC_(pICmdPrep->Prepare(1), S_OK); TESTC_(pICmdWPar->GetParameterInfo(&m_cParams, &m_pParamInfo, &m_pNamesBuffer), S_OK); fFoundParamCount = TRUE; break; } else { TESTC_(hr, S_OK); ulValidLen = wcslen(pwszCmd); m_cParams = iParam; } if (iParam) wcscat(wszMarkers, L","); wcscat(wszMarkers, L"?"); pwszCmdFmt = pwszCmdFormat2; if (m_iOrdinalStart == 0) pwszCmdFmt = pwszCmdFormat2r; else pwszCmdFmt = pwszCmdFormat2; } TESTC(fFoundParamCount); fRet = TRUE; CLEANUP: SAFE_RELEASE(pICmdWPar); SAFE_RELEASE(pICmdText); SAFE_RELEASE(pICmdPrep); SAFE_RELEASE(pICmd); SAFE_RELEASE(pIDBCreateCommand); SAFE_RELEASE(pIDBCreateSession); SAFE_FREE(pwszCmd); return fRet; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // CProcedureParametersHelper::VerifyColumn // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CProcedureParametersHelper::VerifyColumn(DBORDINAL iOrdinal, DATA * pColumn) { // At this time there is no schema-specific testing for PROCEDURE_PARAMETERS schema BOOL fResult = FALSE; DBSTATUS ulStatus = pColumn->sStatus; LPBYTE pValue = GetValuePtr(iOrdinal, m_pRow); UWORD * piOrdinal = (UWORD *)GetValuePtr(PPS_ORDINAL_POSITION, m_pRow); LPWSTR pwszProcName = (LPWSTR)GetValuePtr(PPS_PROCEDURE_NAME, m_pRow); LPWSTR pwszParamName = (LPWSTR)GetValuePtr(PPS_PARAMETER_NAME, m_pRow); USHORT * pusParamType = (USHORT *)GetValuePtr(PPS_PARAMETER_TYPE, m_pRow); DBTYPE * pwType = (DBTYPE *)GetValuePtr(PPS_DATA_TYPE, m_pRow); USHORT usParamType = 0; DBORDINAL iParamOrdinal = 0; ULONG iParamIndex= 0; DBORDINAL ord1, ord2; DBTYPE wTypeInfo, wType; wType = *pwType; if (pusParamType) usParamType = *pusParamType; if (m_cTotalRows == 1 && ((iOrdinal == 0) || (iOrdinal == 1))) { // Always reset param info if first row and ordinal in case it's left // over from previous test variation. SAFE_FREE(m_pwszQualifiedName); SAFE_FREE(m_pParamInfo); SAFE_FREE(m_pNamesBuffer); m_cParams = 0; } TESTC(piOrdinal != NULL); TESTC(GetParamInfo()); // ASSERT(m_pParamInfo != NULL); TESTC(m_pParamInfo != NULL); // Should always have param info iParamOrdinal = *piOrdinal; // If we have the right index, then the ordinals will be related // If no return param, both ordinals start at one, otherwise not // Proc param ordinals are 0-based if return param ord2 = (DBORDINAL)(*piOrdinal); // Search for proper ordinal in parameter info for (iParamIndex = 0; iParamIndex < m_cParams; iParamIndex++) { if (!wcscmp(m_pParamInfo[iParamIndex].pwszName, pwszParamName)) { ord1 = m_pParamInfo[iParamIndex].iOrdinal - !(m_iOrdinalStart); break; } } // Make sure we found the ordinal TESTC(iParamIndex < m_cParams); // If we restricted on the parameter name, then we can't know if the ordinals // are correct w/o going out and calling GetSchema w/o param name restriction // to find out if there is a return param. So only test ordinals when not // restricted on param name. if (!m_prgRestrictUsed || V_VT(&m_prgRestrictUsed[3]) == VT_EMPTY) { TESTC(ord1 == ord2); } wTypeInfo = m_pParamInfo[iParamIndex].wType; //wType reported by GetParameterInfo COMPARE(wType, wTypeInfo); // We don't check provider-specific columns if (iOrdinal > m_pSchemaInfo->cColumns) return TRUE; switch(iOrdinal) { case PPS_PROCEDURE_CATALOG: break; case PPS_PROCEDURE_SCHEMA: break; case PPS_PROCEDURE_NAME: break; case PPS_PARAMETER_NAME: TESTC(ulStatus == DBSTATUS_S_OK); TESTC(!wcscmp(m_pParamInfo[iParamIndex].pwszName, pwszParamName)); break; case PPS_ORDINAL_POSITION: // Ordinals are always sequential. Ordinals in proc params schema are 0-based if // there is a return param, while ordinals in GetParameterInfo are always 1-based. TESTC(*piOrdinal - m_iOrdinalPrev == 1); m_iOrdinalPrev++; break; case PPS_PARAMETER_TYPE: { usParamType = *(USHORT *)pValue; DBPARAMFLAGS dwFlags = m_pParamInfo[iParamIndex].dwFlags; // Note we check for at least one of the valid values in the generic // CHelper::VerifyValue // If this is the return param, then ordinal is 0 if (iParamOrdinal == 0) { TESTC(usParamType == DBPARAMTYPE_RETURNVALUE); } else if ((dwFlags & DBPARAMFLAGS_ISINPUT) && (dwFlags & DBPARAMFLAGS_ISOUTPUT)) { TESTC(usParamType == DBPARAMTYPE_INPUTOUTPUT); } else if (dwFlags & DBPARAMFLAGS_ISINPUT) { TESTC(usParamType == DBPARAMTYPE_INPUT); } else if (dwFlags & DBPARAMFLAGS_ISOUTPUT) { TESTC(usParamType == DBPARAMTYPE_OUTPUT); } } break; case PPS_PARAMETER_HASDEFAULT: break; case PPS_PARAMETER_DEFAULT: break; case PPS_IS_NULLABLE: { DBPARAMFLAGS dwFlags = m_pParamInfo[iParamIndex].dwFlags; VARIANT_BOOL vbIsNullable = VARIANT_TRUE; // Note: Error is posted if value is NULL based on schema info in VerifiyNull if (pValue != NULL) { vbIsNullable = *(VARIANT_BOOL *)pValue; if (dwFlags & DBPARAMFLAGS_ISNULLABLE) { TESTC(vbIsNullable == VARIANT_TRUE); } else { TESTC(vbIsNullable == VARIANT_FALSE); } } } break; case PPS_DATA_TYPE: TESTC(ulStatus == DBSTATUS_S_OK); TESTC(wType == *(DBTYPE *)pValue); // Redundant test, tested above comparing to wTypeInfo break; case PPS_CHARACTER_MAXIMUM_LENGTH: break; case PPS_CHARACTER_OCTET_LENGTH: break; case PPS_NUMERIC_PRECISION: if (!IsNumericType(wType) || DBTYPE_VARNUMERIC == wType) { TESTC(ulStatus == DBSTATUS_S_ISNULL); } else { TESTC(ulStatus == DBSTATUS_S_OK); TESTC((USHORT)m_pParamInfo[iParamIndex].bPrecision == *(USHORT *)pValue); } break; case PPS_NUMERIC_SCALE: switch(wType) { case DBTYPE_DECIMAL: case DBTYPE_NUMERIC: case DBTYPE_VARNUMERIC: TESTC(ulStatus == DBSTATUS_S_OK); TESTC((USHORT)m_pParamInfo[iParamIndex].bScale == *(USHORT *)pValue); break; default: TESTC(ulStatus == DBSTATUS_S_ISNULL); } break; case PPS_DESCRIPTION: if (ulStatus != DBSTATUS_S_ISNULL) VerifyNonEmptyString(pColumn, pwszProcName, pwszParamName); break; case PPS_TYPE_NAME: // TODO: Make sure the type name is one from PROVIDER_TYPES, and the // DBType matches the name. // COMPAREW(0, 1); VerifyNonEmptyString(pColumn, pwszProcName, pwszParamName); VerifyColumnMatch(PPS_TYPE_NAME, PPS_LOCAL_TYPE_NAME); break; case PPS_LOCAL_TYPE_NAME: VerifyNonEmptyString(pColumn, pwszProcName, pwszParamName); break; } fResult = TRUE; CLEANUP: return fResult; } // Provider Types schema specific functions class CProviderTypesHelper : public CHelper { private: DBTYPE m_dbPrevType; BOOL m_fBestMatchFound; protected: BOOL VerifyColumn(DBORDINAL iOrdinal, DATA * pColumn); public: CProviderTypesHelper(void); }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // CProviderTypesHelper::CProviderTypesHelper // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CProviderTypesHelper::CProviderTypesHelper(void) { m_guidSchema = DBSCHEMA_PROVIDER_TYPES; m_dbPrevType = DBTYPE_VECTOR; // DBTYPE_VECTOR by itself is not valid m_fBestMatchFound = FALSE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // CProviderTypesHelper::VerifyColumn // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CProviderTypesHelper::VerifyColumn(DBORDINAL iOrdinal, DATA * pColumn) { DBTYPE * pdbTypeRow = (DBTYPE *)GetValuePtr(PTS_DATA_TYPE, m_pRow); VARIANT_BOOL * pvbBestMatch = (VARIANT_BOOL *)GetValuePtr(PTS_BEST_MATCH, m_pRow); DBSTATUS ulStatus = pColumn->sStatus; BOOL fResult = FALSE; switch(iOrdinal) { // Currently only have tests for BEST_MATCH. Most PROVIDER_TYPES schema testing is done in // ADO Connection test which caches the entire rowset and verifies no changes from previous // runs. case PTS_BEST_MATCH: { // PROVIDER_TYPES has only two restrictions. The first is on data type and second on BEST_MATCH. // If we are restricted on BEST_MATCH then we will either always get all VARIANT_TRUE or all // VARIANT_FALSE, so we cannot test for one and only one BEST_MATCH == VARIANT_TRUE. if (m_cRestrictionsUsed > 1) break; // MSDASQL does not support BEST_MATCH and always returns NULL. In general, since the column // is BOOL and NULL is not a valid value we should disallow this behavior, so only allow for MSDASQL. if (IsMSDASQL() && ulStatus == DBSTATUS_S_ISNULL) break; TESTC(ulStatus == DBSTATUS_S_OK); // Reset best match found flag if on the first row if (m_cTotalRows == 1) { m_fBestMatchFound = FALSE; m_dbPrevType = DBTYPE_VECTOR; } if (*pdbTypeRow != m_dbPrevType) { if (m_dbPrevType != DBTYPE_VECTOR) { TESTC(m_fBestMatchFound); } m_fBestMatchFound = FALSE; m_dbPrevType = *pdbTypeRow; } else if (m_fBestMatchFound) { TESTC(*pvbBestMatch == VARIANT_FALSE); } if (*pvbBestMatch == VARIANT_TRUE) m_fBestMatchFound = TRUE; break; } } fResult = TRUE; CLEANUP: return fResult; } // Table Constraints schema specific functions class CTableConstraintsHelper : public CHelper { private: protected: public: CTableConstraintsHelper(void) {m_guidSchema = DBSCHEMA_TABLE_CONSTRAINTS;} }; // Table Privileges schema specific functions class CTablePrivilegesHelper : public CHelper { private: protected: public: CTablePrivilegesHelper(void) {m_guidSchema = DBSCHEMA_TABLE_PRIVILEGES;} }; // Tables schema specific functions class CTablesHelper : public CHelper { private: protected: BOOL VerifyColumn(DBORDINAL iOrdinal, DATA * pColumn); public: CTablesHelper(void) {m_guidSchema = DBSCHEMA_TABLES;} }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // CTablesHelper::VerifyColumn // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CTablesHelper::VerifyColumn(DBORDINAL iOrdinal, DATA * pColumn) { BOOL fResults = FALSE; // At this time there is no schema-specific testing for TABLES schema switch(iOrdinal) { case 0: // Bookmarks on and bound // TODO: Add code to validate bookmarks are expected and they work. break; case TABLES_TABLE_CATALOG: break; case TABLES_TABLE_SCHEMA: break; case TABLES_TABLE_NAME: break; case TABLES_TABLE_TYPE: break; case TABLES_TABLE_GUID: break; case TABLES_DESCRIPTION: break; case TABLES_TABLE_PROPID: break; case TABLES_DATE_CREATED: case TABLES_DATE_MODIFIED: break; default: odtLog << L"Unexpected column in schema rowset.\n"; TESTC(FALSE); } fResults = TRUE; CLEANUP: return fResults; } // Tables Info schema specific functions class CTablesInfoHelper : public CHelper { private: protected: BOOL VerifyColumn(DBORDINAL iOrdinal, DATA * pColumn); public: CTablesInfoHelper(void) {m_guidSchema = DBSCHEMA_TABLES_INFO;} }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // CTablesInfoHelper::VerifyColumn // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CTablesInfoHelper::VerifyColumn(DBORDINAL iOrdinal, DATA * pColumn) { LPWSTR pwszTableName = (LPWSTR)GetValuePtr(TIS_TABLE_NAME, m_pRow); LPWSTR pwszTableType = (LPWSTR)GetValuePtr(TIS_TABLE_TYPE, m_pRow); VARIANT_BOOL bBookMarks = (VARIANT_BOOL)GetValuePtr(TIS_BOOKMARKS, m_pRow); LPBYTE pValue = GetValuePtr(iOrdinal, m_pRow); BOOL fResult = FALSE; ULONG iIndex = 0; DBSTATUS ulStatus = pColumn->sStatus; switch(iOrdinal) { case TIS_TABLE_CATALOG: break; case TIS_TABLE_SCHEMA: break; case TIS_TABLE_NAME: break; case TIS_TABLE_TYPE: // Note: We already test that the value is one of the valid ones in VerifyValue break; case TIS_TABLE_GUID: break; case TIS_BOOKMARKS: // Note: We already test that the value is one of the valid ones in VerifyValue break; case TIS_BOOKMARK_TYPE: // This column is NULL if BOOKMARKS column is VARIANT_FALSE if (bBookMarks == VARIANT_FALSE) { TESTC(ulStatus == DBSTATUS_S_ISNULL); } else { TESTC(ulStatus == DBSTATUS_S_OK); // Note: We already test that the value is one of the valid ones in VerifyValue } break; case TIS_BOOKMARK_DATATYPE: if (bBookMarks == VARIANT_FALSE) { TESTC(ulStatus == DBSTATUS_S_ISNULL); } else { TESTC(ulStatus == DBSTATUS_S_OK); if (m_prgColInfo && m_prgColInfo[0].iOrdinal == 0) { TESTC(m_prgColInfo[0].wType == *(DBTYPE *)pValue); } } break; case TIS_BOOKMARK_MAXIMUM_LENGTH: if (bBookMarks == VARIANT_FALSE) { TESTC(ulStatus == DBSTATUS_S_ISNULL); } else { TESTC(ulStatus == DBSTATUS_S_OK); if (m_prgColInfo && m_prgColInfo[0].iOrdinal == 0) { TESTC(m_prgColInfo[0].ulColumnSize == *(ULONG *)pValue); } } break; case TIS_BOOKMARK_INFORMATION: break; case TIS_TABLE_VERSION: break; case TIS_CARDINALITY: // Only valid for TABLE types, must be NULL for other types if (pwszTableType && ( !wcscmp(pwszTableType, L"TABLE") || !wcscmp(pwszTableType, L"SYSTEM TABLE") || !wcscmp(pwszTableType, L"GLOBAL TEMPORARY") || !wcscmp(pwszTableType, L"LOCAL TEMPORARY") || !wcscmp(pwszTableType, L"EXTERNAL TABLE"))) { // We expect a valid non-null cardinality TESTC(ulStatus == DBSTATUS_S_OK); } else { // This is not a TABLE type, so cardinality must be null TESTC(ulStatus == DBSTATUS_S_ISNULL); // TODO: For the base table we created, this should have the right number of rows. // For random tables counting the rows could possibly be done but is likely too time intensive. } break; case TIS_DESCRIPTION: break; case TIS_TABLE_PROPID: break; } fResult = TRUE; CLEANUP: return fResult; } // Table Statistics schema specific functions class CTableStatisticsHelper : public CHelper { private: CErrorCache m_EC; // Table Statistics error cache BOOL m_fFoundCardinality; BOOL m_fFoundHistogram; BOOL m_fCardinalityIncludesBlob; LPWSTR m_pwszStatName; BOOL m_fDetailCheck; ULONG m_iOrdinalExpected; IOpenRowset * m_pIOpenRowset; ULONG_PTR m_ulTableStatistics; LPWSTR * m_ppwszStatCols; DBORDINAL m_cStatCols; protected: BOOL VerifyColumn(DBORDINAL iOrdinal, DATA * pColumn); BOOL CheckHistogramColInfo(IRowset * pIHistogramRowset, DBTYPE wRangeColType, DBORDINAL * pcBinding, DBBINDING ** ppBinding, DBLENGTH * pcbRowSize, HACCESSOR * phAccessor); // Returns cardinality (COUNT) information for the given table using ulColIndex index into // columns info for table. DBCOUNTITEM Cardinality(LPWSTR pwszTableName, ULONG ulColIndex, CARDINALITY eCardinality, DBBINDING * pStartBind = NULL, DBBINDING * pEndBind = NULL, LPBYTE pDataHist = NULL, DBLENGTH cbRowSize = 0); public: CTableStatisticsHelper(void); ~CTableStatisticsHelper(void); BOOL Init(CSchemaTest * pThis); }; CTableStatisticsHelper::CTableStatisticsHelper(void) { m_guidSchema = DBSCHEMA_TABLE_STATISTICS; m_pIOpenRowset = NULL; m_pwszStatName = NULL; m_ppwszStatCols = NULL; m_cStatCols = 0; } // CTableStatisticsHelper destructor CTableStatisticsHelper::~CTableStatisticsHelper(void) { // If a histogram was found then make sure support is indicated. // Note that if a histogram was not found we cannot infer lack of support // as there may not happen to be any created at this time, so only post // a warning if (m_fFoundHistogram) COMPARE(!!(m_ulTableStatistics & DBPROPVAL_TS_HISTOGRAM), TRUE); else COMPAREW(!!(m_ulTableStatistics & DBPROPVAL_TS_HISTOGRAM), FALSE); // If a cardinality info was found then make sure support is indicated. // Note that if a cardinality was not found we cannot infer lack of support // as there may not happen to be any created at this time, so only post // a warning if (m_fFoundCardinality) COMPARE(!!(m_ulTableStatistics & DBPROPVAL_TS_CARDINALITY), TRUE); else COMPAREW(!!(m_ulTableStatistics & DBPROPVAL_TS_CARDINALITY), FALSE); SAFE_RELEASE(m_pIOpenRowset); if (m_ppwszStatCols) { for (DBORDINAL iCol = 0; iCol < m_cStatCols; iCol++) SAFE_FREE(m_ppwszStatCols[iCol]); SAFE_FREE(m_ppwszStatCols); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // CTableStatisticsHelper::Init // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL CTableStatisticsHelper::Init(CSchemaTest * pThis) { LPWSTR pwszUpdateStats = NULL; size_t ccUpdateStats = 0; LPWSTR pwszUpdateStatsFormat = pThis->m_pwszUpdateStatsFormat; BOOL fSuccess = FALSE; IRowset * pIRowset = NULL; HACCESSOR hAccessor = DB_NULL_HACCESSOR; DBBINDING * prgDBBINDING = NULL; DBCOUNTITEM cDBBINDING = 0; DBLENGTH cbRowSize = 0; HRESULT hr = S_OK; DBCOUNTITEM cRowsObtained; HROW * prghRows = NULL; // array of hrows LPBYTE pData = NULL; LPWSTR pwszQualifiedName = NULL; VARIANT rgRestrict[NUMELEM(rgTablesRestrict)]; ULONG cRestrict = NUMELEM(rgTablesRestrict); HRESULT hrUpdate = E_FAIL; // Schema specific vars init m_fFoundCardinality = FALSE; m_fFoundHistogram = FALSE; m_ulTableStatistics = 0; m_pwszStatName = NULL; m_fDetailCheck = FALSE; m_iOrdinalExpected = 0; m_pIOpenRowset = pThis->m_pIOpenRowset; // Addref the IOpenRowset so it won't go away while we're using m_pIOpenRowset->AddRef(); // Initialize the helper if (!CHelper::Init(pThis)) return FALSE; // Get DBPROP_TABLESTATISTICS GetProperty(g_propTableStatistics, DBPROPSET_DATASOURCEINFO, pThis->m_pIDBInitialize, &m_ulTableStatistics); // Execute the provider-specific command to update all table statistics so they will // be accurate for the test. Both Oracle and SQL Server have a stored proc that can // be called to update all table's statistics in the user's schema, but these have // problems. On SQL Server, the proc can only be run by admin, and against Oracle, // the proc is not supported for older servers (7.x). So brute force method is // required (very slow). if (pwszUpdateStatsFormat) { // Get the max size for a table name DBLITERALINFO* pTableLiteral = m_pTable->GetLiteralInfo(DBLITERAL_TABLE_NAME); TESTC(pTableLiteral != NULL); // Compute max size for a statement that will update a table // We assume Catalog Name, Schema Name, and Table Name will have // the same max length, and additionally that tables will be fully // qualified and quoted, since we don't know if there will be different // catalogs, schemas and we don't know there are not table names that // require quotes in the TABLES schema. // 8 == two quotes for each name portion, plus 2 separators for the portions ccUpdateStats = wcslen(pwszUpdateStatsFormat) + (pTableLiteral->cchMaxLen * 3 + 8) +1; SAFE_ALLOC(pwszUpdateStats, WCHAR, ccUpdateStats); // Initialize restrictions memset(rgRestrict, 0, sizeof(VARIANT) * cRestrict); // Set restriction on table type V_VT(&rgRestrict[3]) = VT_BSTR; V_BSTR(&rgRestrict[3]) = SysAllocString(L"TABLE"); // Get the TABLES schema rowset TESTC_(m_pIDBSchemaRowset->GetRowset(NULL, DBSCHEMA_TABLES, cRestrict, rgRestrict, IID_IRowset, 0, NULL, (IUnknown **)&pIRowset), S_OK); // Get accessor and bindings for tables schema TESTC_(GetAccessorAndBindings( pIRowset, // @parmopt [IN] Rowset to create Accessor for DBACCESSOR_ROWDATA, // @parmopt [IN] Properties of the Accessor &hAccessor, // @parmopt [OUT] Accessor created &prgDBBINDING, // @parmopt [OUT] Array of DBBINDINGS &cDBBINDING, // @parmopt [OUT] Count of bindings &cbRowSize, // @parmopt [OUT] Length of a row, DATA DBPART_VALUE|DBPART_STATUS |DBPART_LENGTH, ALL_COLS_BOUND, // @parmopt [IN] Which columns will be used in the bindings FORWARD, // @parmopt [IN] Order to bind columns in accessor NO_COLS_BY_REF, // @parmopt [IN] Which column types to bind by reference NULL, // @parmopt [OUT] Array of DBCOLUMNINFO NULL, // @parmopt [OUT] Count of Columns, also count of ColInfo elements NULL, DBTYPE_EMPTY, // @parmopt [IN] Modifier to be OR'd with each binding type. 0, // @parmopt [IN] Used only if eColsToBind = USE_COLS_TO_BIND_ARRAY NULL, // @parmopt [IN] Used only if eColsToBind = USE_COLS_TO_BIND_ARRAY NULL, // @parmopt [IN] Corresponds to what ordinals are specified for each binding, if NO_COLS_OWNED_BY_PROV, // @parmopt [IN] Which columns' memory is to be owned by the provider DBPARAMIO_NOTPARAM, // @parmopt [IN] Parameter kind specified for all bindings BLOB_LONG, // @parmopt [IN] how to bind BLOB Columns NULL),S_OK); // @parmopt [OUT] returned status array from CreateAccessor // Allocate a buffer to hold a row SAFE_ALLOC(pData, BYTE, cbRowSize); while (hr == S_OK) { // Loop through schema and update stats for each table hr=pIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &prghRows); if (hr != DB_S_ENDOFROWSET) TESTC_(hr, S_OK); if (cRowsObtained) { // Get data for the row TESTC_(pIRowset->GetData(prghRows[0],hAccessor,pData), S_OK) // Create a fully qualified table name TESTC_(m_pTable->GetQualifiedName( (LPWSTR)GetValuePtr(TABLES_TABLE_CATALOG, pData, prgDBBINDING), (LPWSTR)GetValuePtr(TABLES_TABLE_SCHEMA, pData, prgDBBINDING), (LPWSTR)GetValuePtr(TABLES_TABLE_NAME, pData, prgDBBINDING), &pwszQualifiedName, TRUE), S_OK); swprintf(pwszUpdateStats, pwszUpdateStatsFormat, pwszQualifiedName); hrUpdate = m_pTable->BuildCommand(pwszUpdateStats, IID_IRowset, EXECUTE_IFNOERROR, 0, NULL, NULL, NULL, NULL); // Table could have been dropped after schema was retrieved, or we // may not have permission. if (hrUpdate != DB_E_NOTABLE && hrUpdate != DB_SEC_E_PERMISSIONDENIED) CHECK(hrUpdate, S_OK); if (hrUpdate != S_OK) odtLog << pwszUpdateStats << L"\n"; SAFE_FREE(pwszQualifiedName); ReleaseInputBindingsMemory(cDBBINDING, prgDBBINDING, pData, FALSE); pIRowset->ReleaseRows(cRowsObtained, prghRows, NULL, NULL, NULL); } } odtLog << "\n==========================================================\n"; // odtLog << "Executed command: " << pwszUpdateStats << "\n"; odtLog << "Statistics for all tables in user's schema were updated.\n"; odtLog << "==========================================================\n\n"; } fSuccess = TRUE; CLEANUP: VariantClear(&rgRestrict[4]); SAFE_FREE(pwszQualifiedName); SAFE_FREE(pwszUpdateStats); SAFE_FREE(prgDBBINDING); if (pIRowset && prghRows && *prghRows) pIRowset->ReleaseRows(cRowsObtained, prghRows, NULL, NULL, NULL); SAFE_RELEASE(pIRowset); if (fSuccess) return m_EC.Init(GetModInfo()->GetDebugMode()); else return TEST_FAIL; } // Compare histogram rowset columns info BOOL CTableStatisticsHelper::CheckHistogramColInfo(IRowset * pIHistogramRowset, DBTYPE wRangeColType, DBORDINAL * pcBinding, DBBINDING ** ppBinding, DBLENGTH * pcbRowSize, HACCESSOR * phAccessor) { HACCESSOR hAccessor = DB_NULL_HACCESSOR; DBLENGTH cbRowSize = 0; BOOL fColInfo = FALSE; DBCOUNTITEM cActualCols = 0; // Count of columns returned in histogram rowset LPWSTR pwszCmd = NULL; IAccessor * pIAcc = NULL; ICommand * pICmd = NULL; DBBINDING * prgUDTBinding = NULL; DB_LORDINAL * pNonUDTOrdinals = NULL; // Save off member vars so we can call CheckAgainstIColumnsInfo() DBBINDING * pBinding = m_rgDBBINDING; DBCOUNTITEM cBinding = m_cDBBINDING; DBCOLUMNINFO * pColInfo = m_rgDBCOLUMNINFO; DBCOUNTITEM cColInfo = m_cDBCOLUMNINFO; LPWSTR pStringsBuf = m_pStringsBuffer; m_cDBCOLUMNINFO = 0; m_rgDBCOLUMNINFO = NULL; m_pStringsBuffer = NULL; // Update expected type for RANGE_HI_KEY HistogramRowset[0].pColList[0].wType = wRangeColType; // Update count of columns if needed. if (HistogramRowset[0].pulColCount) { HistogramRowset[0].cColumns = HistogramRowset[0].pulColCount[0]; } // get bindings and column info if(!CHECK(GetAccessorAndBindings( pIHistogramRowset, // @parmopt [IN] Rowset to create Accessor for DBACCESSOR_ROWDATA, // @parmopt [IN] Properties of the Accessor &hAccessor, // @parmopt [OUT] Accessor created &m_rgDBBINDING, // @parmopt [OUT] Array of DBBINDINGS &m_cDBBINDING, // @parmopt [OUT] Count of bindings &cbRowSize, // @parmopt [OUT] Length of a row, DATA DBPART_VALUE|DBPART_STATUS |DBPART_LENGTH, ALL_COLS_BOUND, // @parmopt [IN] Which columns will be used in the bindings FORWARD, // @parmopt [IN] Order to bind columns in accessor NO_COLS_BY_REF, // @parmopt [IN] Which column types to bind by reference &m_rgDBCOLUMNINFO, // @parmopt [OUT] Array of DBCOLUMNINFO &m_cDBCOLUMNINFO, // @parmopt [OUT] Count of Columns, also count of ColInfo elements &m_pStringsBuffer, DBTYPE_EMPTY, // @parmopt [IN] Modifier to be OR'd with each binding type. 0, // @parmopt [IN] Used only if eColsToBind = USE_COLS_TO_BIND_ARRAY NULL, // @parmopt [IN] Used only if eColsToBind = USE_COLS_TO_BIND_ARRAY NULL, // @parmopt [IN] Corresponds to what ordinals are specified for each binding, if NO_COLS_OWNED_BY_PROV, // @parmopt [IN] Which columns' memory is to be owned by the provider DBPARAMIO_NOTPARAM, // @parmopt [IN] Parameter kind specified for all bindings BLOB_LONG, // @parmopt [IN] how to bind BLOB Columns NULL),S_OK)) // @parmopt [OUT] returned status array from CreateAccessor goto CLEANUP; fColInfo = CheckAgainstIColumnsInfo(&HistogramRowset[0]); // CheckAgainstIColumnsInfo doesn't test for any extra columns, so warn here // if there are extras cActualCols = m_cDBCOLUMNINFO - !m_rgDBCOLUMNINFO[0].iOrdinal; // Check for extra columns in histogram rowset. This is only a warning // since it's allowed to return extra columns. Cache the warning so we don't // get it for every histogram over and over. CCOMPARE(m_EC, HistogramRowset[0].cColumns == cActualCols, EC_EXTRA_COLUMN, L"Extra column in Histogram rowset.", TRUE); CLEANUP: // Populate output params if (pcBinding) *pcBinding = cActualCols; if (ppBinding) *ppBinding = m_rgDBBINDING; else SAFE_FREE(m_rgDBBINDING); if (pcbRowSize) *pcbRowSize = cbRowSize; if (phAccessor) *phAccessor = hAccessor; else if (pIAcc && (hAccessor != DB_NULL_HACCESSOR)) CHECK(pIAcc->ReleaseAccessor(hAccessor, NULL), S_OK); SAFE_RELEASE(pIAcc); SAFE_RELEASE(pICmd); SAFE_FREE(m_rgDBCOLUMNINFO); SAFE_FREE(m_pStringsBuffer); SAFE_FREE(pwszCmd); SAFE_FREE(prgUDTBinding); SAFE_FREE(pNonUDTOrdinals); // Restore member vars to avoid side effects m_rgDBBINDING = pBinding; m_cDBBINDING = cBinding; m_rgDBCOLUMNINFO= pColInfo; m_cDBCOLUMNINFO = cColInfo; m_pStringsBuffer= pStringsBuf; return fColInfo; } DBCOUNTITEM CTableStatisticsHelper::Cardinality(LPWSTR pwszTableName, ULONG ulColIndex, CARDINALITY eCardinality, DBBINDING * pStartBind, DBBINDING * pEndBind, LPBYTE pDataRows, DBLENGTH cbRowSize) { HRESULT hr = S_OK; ULONG ulIndexFirst = 0; size_t cChars = 0; LPWSTR pwszColList = NULL; LPWSTR pwszSelectFmt = (LPWSTR)wszSELECT_DISTINCTCOLLIST; LPWSTR pwszSelect = NULL; LPWSTR pwszGreaterFmt = L"%s > ?"; LPWSTR pwszLessThanEqFmt = L"%s <= ?"; LPWSTR pwszEqFmt = L"%s = ?"; LPWSTR pwszRange = NULL; DBCOUNTITEM ulCardinality = 0; IRowset * pIRowset = NULL; IAccessor * pIAccessor = NULL; ICommand * pICommand = NULL; IAccessor * pICmdAccessor = NULL; DBBINDING dbCountBind; DBBINDING dbParamBind[2]; // Only two params required for all cases ULONG cParams = 0; // HACCESSOR hAcc = DB_NULL_HACCESSOR; HACCESSOR hParamAcc = DB_NULL_HACCESSOR; HROW * phRows = NULL; ULONG * pulCardinality = NULL; DBORDINAL iCol; DBCOUNTITEM cRowsObtained; DBPARAMS dbParams; DBBINDSTATUS rgStatus[2]; ULONG * pulOrdinal = (ULONG *)GetValuePtr(TSS_ORDINAL_POSITION, m_pRow); ULONG ulOrdinal; if (eCardinality == TUPLE_CARDINALITY) { if (!COMPARE(pulOrdinal != NULL, TRUE)) return 0; ulOrdinal = *pulOrdinal; } // Previously used the count aggregate function, but that was bad because: // 1) Doesn't include NULL rows // 2) Fails against GUID column on some providers. // select count(*) from (select distinct col1,col2 from
where col1 > ? and // col1 <= ?) t1 // Now we use just the select distinct, but this still will fail for BLOB columns, // so we have to avoid calling this function for BLOBS. // TODO: If this function is made more sophisticated we can actually call for BLOBS. // Possible improvements 1) Use conversion function, 2) actually retrieve data // ourselves and count distinct values. // select distinct col1,col2 from
where col1 > ? and col1 <= ? // Assume no Blob columns are included in cardinality results. Most important // for Tuple cardinality m_fCardinalityIncludesBlob = FALSE; // Initialize binding structures memset(&dbCountBind, 0, sizeof(DBBINDING)); memset(&dbParamBind, 0, sizeof(DBBINDING)*2); // Initialize dbParams memset(&dbParams, 0, sizeof(DBPARAMS)); // Note we use params for this to avoid having to convert range limits to strings and // obtain the appropriate literal prefix and suffix. I am assuming that any provider // that has gone to the trouble to provide extensive support for query processors has // also supported parameters. switch (eCardinality) { // Both range rows and eq rows are non-distinct, and all the cardinalities // for histogram are for only one column. But they all need a 'where' clause case EQ_ROWS_CARDINALITY: // We don't have a range for this cardinality, we're only looking for // values equal to RANGE_HIGH_KEY ASSERT(!pStartBind); // Fall through case RANGE_ROWS_CARDINALITY: // Both of these counts are non-distinct, so change our select // clause to not return distinct counts. pwszSelectFmt = (LPWSTR)wszSELECT_COLLISTFROMTBL; // Fall through case DISTINCT_RANGE_ROWS_CARDINALITY: { size_t cchWhere = wcslen(wszWHERE); // Length of " where " size_t cchColName = wcslen(m_prgColInfo[ulColIndex].pwszName); LPWSTR pwszFmt = pwszLessThanEqFmt; if (eCardinality == EQ_ROWS_CARDINALITY) pwszFmt = pwszEqFmt; // Fill out param info if (pStartBind) { cchWhere += wcslen(pwszGreaterFmt) -2 + cchColName + wcslen(wszAND); // Set parameter binding info memcpy(&dbParamBind[cParams], pStartBind, sizeof(DBBINDING)); dbParamBind[cParams].eParamIO = DBPARAMIO_INPUT; dbParamBind[cParams].iOrdinal = cParams+1; cParams++; } if (pEndBind) { cchWhere += wcslen(pwszFmt) -2 + cchColName; // Set parameter binding info memcpy(&dbParamBind[cParams], pEndBind, sizeof(DBBINDING)); dbParamBind[cParams].eParamIO = DBPARAMIO_INPUT; dbParamBind[cParams].iOrdinal = cParams+1; cParams++; } // Now we know all the pieces for the range clause, allocate memory and create SAFE_ALLOC(pwszRange, WCHAR, cchWhere+1); wcscpy(pwszRange, wszWHERE); // Put in the starting range clause if (pStartBind) { swprintf(pwszRange+wcslen(pwszRange), pwszGreaterFmt, m_prgColInfo[ulColIndex].pwszName); wcscat(pwszRange, wszAND); } // Put in ending range clause (always needed) swprintf(pwszRange+wcslen(pwszRange), pwszFmt, m_prgColInfo[ulColIndex].pwszName); } // Fall through case COLUMN_CARDINALITY: ulIndexFirst = ulColIndex; // Fall through case TUPLE_CARDINALITY: // Compute memory for column list (column name plus comma) for (iCol = 0; iCol < m_cStatCols; iCol++) cChars+=wcslen(m_ppwszStatCols[iCol])+1; // Allocate memory for col list SAFE_ALLOC(pwszColList, WCHAR, cChars+1); pwszColList[0] = L'\0'; // Put non-BLOB columns in final list // Note we leave out BLOB cols because providers can't do a // select distinct on a BLOB, which may have some impact on // the cardinality results. for (iCol = 0; iCol < m_cStatCols; iCol++) { LPWSTR pwszCol = m_ppwszStatCols[iCol]; ULONG iColInfo; // Locate this stat column in the columns info for (iColInfo = 0; iColInfo < m_cColInfo; iColInfo++) { if (!wcscmp(m_prgColInfo[iColInfo].pwszName, pwszCol)) break; } TESTC(iColInfo < m_cColInfo); if (m_prgColInfo[iColInfo].dwFlags & DBCOLUMNFLAGS_ISLONG) { m_fCardinalityIncludesBlob = TRUE; continue; } // Put in comma separator if needed if (pwszColList[0]) wcscat(pwszColList, L","); wcscat(pwszColList, pwszCol); } // Compute memory required for select distinct statement // Length of select, 2 parenthesis, table name, table alias name cChars+=wcslen(pwszSelectFmt)+wcslen(pwszTableName); // Add space for 'where' clause if needed if (pwszRange) cChars+=wcslen(pwszRange); // Allocate mem for select SAFE_ALLOC(pwszSelect, WCHAR, cChars+1); // select distinct col1,col2 from
swprintf(pwszSelect, pwszSelectFmt, pwszColList, pwszTableName); // Tack on where clause if needed if (pwszRange) wcscat(pwszSelect, pwszRange); // Free the range clause SAFE_FREE(pwszRange); break; case TABLE_CARDINALITY: pwszSelectFmt = (LPWSTR)wszSELECT_ALLFROMTBL; cChars+=wcslen(pwszSelectFmt)+wcslen(pwszTableName); // Allocate mem for select SAFE_ALLOC(pwszSelect, WCHAR, cChars+1); // Create select stmt swprintf(pwszSelect, pwszSelectFmt, pwszTableName); break; } // Execute the command if (cParams) { // Get the command object for the table object pICommand = m_pTable->get_ICommandPTR(); // Addref the command object so we can release later. pICommand->AddRef(); // Get accessor interface TESTC(VerifyInterface(pICommand, IID_IAccessor, COMMAND_INTERFACE, (IUnknown **)&pICmdAccessor)); // Create the parameter accessor TESTC_(pICmdAccessor->CreateAccessor(DBACCESSOR_PARAMETERDATA, cParams, dbParamBind, cbRowSize, &hParamAcc, rgStatus), S_OK); // Fill DBPARAMS info dbParams.pData = pDataRows; dbParams.cParamSets = 1; dbParams.hAccessor = hParamAcc; } if (!CHECK(m_pTable->BuildCommand(pwszSelect, IID_IRowset, EXECUTE_IFNOERROR, 0, NULL, &dbParams, NULL, (IUnknown **)&pIRowset, &pICommand), S_OK)) goto CLEANUP; // Get accessor and bindings // dbCountBind.obStatus = offsetof(DATA, sStatus); // dbCountBind.obLength = offsetof(DATA, ulLength); // dbCountBind.obValue = offsetof(DATA, bValue); // dbCountBind.wType = DBTYPE_UI4; // dbCountBind.iOrdinal = 1; // dbCountBind.dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS; // TESTC(VerifyInterface(pIRowset, IID_IAccessor, ROWSET_INTERFACE, (IUnknown **)&pIAccessor)); // TESTC_(pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 1, &dbCountBind, 0, &hAcc, NULL), S_OK); // hr = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 1, &dbCountBind, 0, &hAcc, NULL); // TESTC_(hr, S_OK); // Count the rows while(hr != DB_S_ENDOFROWSET) { TEST3C_(hr = pIRowset->GetNextRows(NULL, 0, 10000, &cRowsObtained, &phRows), S_OK, DB_S_ENDOFROWSET, DB_S_ROWLIMITEXCEEDED); if (hr == S_OK) { TESTC(cRowsObtained); } ulCardinality+=cRowsObtained; if (cRowsObtained) { CHECK(pIRowset->ReleaseRows(cRowsObtained, phRows, NULL, NULL, NULL), S_OK); *phRows = DB_NULL_HROW; } } CLEANUP: // Release rows if (pIRowset && phRows && *phRows != DB_NULL_HROW) CHECK(pIRowset->ReleaseRows(cRowsObtained, phRows, NULL, NULL, NULL), S_OK); // Release parameter accessor if (pICmdAccessor && hParamAcc != DB_NULL_HACCESSOR) CHECK(pICmdAccessor->ReleaseAccessor(hParamAcc, NULL), S_OK); SAFE_FREE(phRows); SAFE_FREE(pwszColList); SAFE_FREE(pwszSelect); SAFE_RELEASE(pICommand); SAFE_RELEASE(pIRowset); SAFE_RELEASE(pIAccessor); SAFE_RELEASE(pICmdAccessor); return ulCardinality; } BOOL CTableStatisticsHelper::VerifyColumn(DBORDINAL iOrdinal, DATA * pColumn) { CCol col; BOOL fResults = TRUE; HRESULT hrOpenTable = E_FAIL; LPWSTR pwszTableName = (LPWSTR)GetValuePtr(TSS_TABLE_NAME, m_pRow); LPWSTR pwszStatName = (LPWSTR)GetValuePtr(TSS_STATISTICS_NAME, m_pRow); LPWSTR pwszColumnName = (LPWSTR)GetValuePtr(TSS_COLUMN_NAME, m_pRow); ULONG * pulTableCardinality = (ULONG *)GetValuePtr(TSS_TABLE_CARDINALITY, m_pRow); ULONG * pulOrdinal = (ULONG *)GetValuePtr(TSS_ORDINAL_POSITION, m_pRow); ULONG ulStatType = 0; ULONG ulIndex = 0; DBID dbidTable = DB_NULLID; BOOL fNewTable = (!m_pwszTableName || !pwszTableName || (pwszTableName && RelCompareString(pwszTableName, m_pwszTableName))); BOOL fNewStat = fNewTable | (!m_pwszStatName || !pwszStatName || (pwszStatName && RelCompareString(pwszStatName, m_pwszStatName))); CARDINALITY eCardinality = TUPLE_CARDINALITY; LPWSTR pwszCat = (LPWSTR)GetValuePtr(TSS_TABLE_CATALOG, m_pRow); LPWSTR pwszSch = (LPWSTR)GetValuePtr(TSS_TABLE_SCHEMA, m_pRow); LPWSTR pwszQualifiedName = NULL; LPWSTR pwszQualifiedStatName = NULL; // Reset any previous table or stat name saved if (m_cTotalRows == 1) { fNewTable = TRUE; fNewStat = TRUE; } if (iOrdinal == 1) { // Initial allocation if (!m_ppwszStatCols) { m_cStatCols = 0; SAFE_ALLOC(m_ppwszStatCols, LPWSTR, MAX_STATS_COLS); memset(m_ppwszStatCols, 0, MAX_STATS_COLS * sizeof(LPWSTR *)); } TESTC(m_cStatCols < MAX_STATS_COLS-1); // Reset list of stats columns for each new statistic if (fNewStat) { for (DBORDINAL iCol = 0; iCol < m_cStatCols; iCol++) SAFE_FREE(m_ppwszStatCols[iCol]); m_cStatCols = 0; // No columns currently in this new statistic } // Add this stat column to the list of statistics columns m_ppwszStatCols[m_cStatCols++] = wcsDuplicate(pwszColumnName); } TESTC_(m_pTable->GetQualifiedName(pwszCat, pwszSch, pwszTableName,&pwszQualifiedName, TRUE), S_OK); TESTC_(m_pTable->GetQualifiedName( (LPWSTR)GetValuePtr(TSS_STATISTICS_CATALOG, m_pRow), (LPWSTR)GetValuePtr(TSS_STATISTICS_SCHEMA, m_pRow), pwszStatName, &pwszQualifiedStatName, TRUE), S_OK); // ********************************************************************* // For current time, set this on for debugging test code. // ********************************************************************* m_fDetailCheck = TRUE; if (m_fDetailCheck) { ULONG * pulStatType = (ULONG *)GetValuePtr(TSS_STATISTICS_TYPE, m_pRow); // Attempt to open table and get columns info if (fNewTable) { hrOpenTable = GetColumnInfo(m_pRow, m_rgDBBINDING); // Should be S_OK, or perhaps DB_E_NOTABLE if (DB_E_NOTABLE != hrOpenTable) { // The first time we attempt to open the table we get the appropriate error, // and from then on for the same table we get S_FALSE. We can't test much w/o // columnsinfo, so just skip. if (S_FALSE == hrOpenTable) goto CLEANUP; CHECK(hrOpenTable, S_OK); } else // We warn here because it's possible the table name is // bogus, or just deleted. CHECKW(hrOpenTable, S_OK); } else // If we obtained col info for the table we successfully opened it. hrOpenTable = (m_prgColInfo) ? S_OK : E_FAIL; // Set index into columns info given column name if (m_prgColInfo && pwszColumnName) { for (ulIndex = 0; ulIndex < m_cColInfo; ulIndex++) { if (!wcscmp(m_prgColInfo[ulIndex].pwszName, pwszColumnName)) break; } } // Set up table dbid dbidTable.eKind = DBKIND_NAME; // dbidTable.uName.pwszName = pwszTableName; dbidTable.uName.pwszName = pwszQualifiedName; // Get statistic type if (pulStatType) ulStatType = *pulStatType; } // Set cardinality eCardinality = TUPLE_CARDINALITY; switch(iOrdinal) { case TSS_TABLE_CATALOG: break; case TSS_TABLE_SCHEMA: break; case TSS_TABLE_NAME: break; case TSS_STATISTICS_CATALOG: break; case TSS_STATISTICS_SCHEMA: break; case TSS_STATISTICS_NAME: break; case TSS_STATISTICS_TYPE: { TYPE_UI2 ulStatType = 0; // Column cannot be NULL if (COMPARE(pColumn->sStatus, DBSTATUS_S_OK)) { ulStatType = *(TYPE_UI2 *)pColumn->bValue; // Make sure no other bits are set than those spec'd COMPARE(0, ulStatType & (~(DBSTAT_HISTOGRAM | DBSTAT_COLUMN_CARDINALITY | DBSTAT_TUPLE_CARDINALITY))); // If we claim histogram support then NO_OF_RANGES cannot be null // but may be 0 if the table is empty. if (ulStatType & DBSTAT_HISTOGRAM) COMPARE(GetValuePtr(TSS_NO_OF_RANGES, m_pRow) != NULL, TRUE); else { CCOMPARE(m_EC, GetValuePtr(TSS_NO_OF_RANGES, m_pRow) == NULL, EC_NULL_RANGE_COUNT, L"DBSTAT_HISTOGRAM not set but NO_OF_RANGES is non-NULL", FALSE); } // If we claim column cardinality support then it must not be null if (ulStatType & DBSTAT_COLUMN_CARDINALITY) { m_fFoundCardinality = TRUE; COMPARE(GetValuePtr(TSS_COLUMN_CARDINALITY, m_pRow) != NULL, TRUE); } else COMPARE(GetValuePtr(TSS_COLUMN_CARDINALITY, m_pRow) == NULL, TRUE); // If we claim tuple cardinality support then not be null if (ulStatType & DBSTAT_TUPLE_CARDINALITY) { m_fFoundCardinality = TRUE; COMPARE(GetValuePtr(TSS_TUPLE_CARDINALITY, m_pRow) != NULL, TRUE); } else COMPARE(GetValuePtr(TSS_TUPLE_CARDINALITY, m_pRow) == NULL, TRUE); // DetailCheckStatType(ulStatType, m_pRow); // Detail check if (m_fDetailCheck) { IRowset * pIRowset = NULL; DBID dbidStat; LPWSTR pwszStatName = (LPWSTR)GetValuePtr(TSS_STATISTICS_NAME, m_pRow); HRESULT hrOpenHistogram = E_FAIL; dbidStat.eKind = DBKIND_GUID_NAME; // dbidStat.uName.pwszName = pwszStatName; dbidStat.uName.pwszName = pwszQualifiedStatName; dbidStat.uGuid.guid = g_guidHistogramRowset; // Attempt to open histogram rowset hrOpenHistogram = m_pIOpenRowset->OpenRowset(NULL, &dbidTable, &dbidStat, IID_IRowset, 0, NULL, (IUnknown **)&pIRowset); // If there's a histogram then validate values if (ulStatType & DBSTAT_HISTOGRAM) { // Histograms are only supported on first column // of a multicolumn statistic. if (pulOrdinal && *pulOrdinal == 1) { // Record we found at least one histogram. m_fFoundHistogram = TRUE; ULONG * pcRanges = (ULONG *)GetValuePtr(TSS_NO_OF_RANGES, m_pRow); // It's possible the table was deleted after we opened // the schema rowset if (S_OK == hrOpenHistogram) { // odtLog << L"Opened histogram rowset for table: " << pwszTableName << L" statistic: " // << pwszStatName << L"\n"; if (CHECK(pIRowset != NULL, TRUE)) { HRESULT hrGetNextRows = S_OK; ULONG cRows = 0; HROW * phRows = NULL; DBCOUNTITEM cRowsObtained = 0; DBCOUNTITEM cBinding = 0, iBind; DBLENGTH cbRowSize = 0; DBBINDING * pBinding = NULL; HACCESSOR hAccessor = DB_NULL_HACCESSOR; LPBYTE pDataRows = NULL; // Check histogram rowset columns info if (m_prgColInfo && !COMPARE(CheckHistogramColInfo( pIRowset, m_prgColInfo[ulIndex].wType, &cBinding, &pBinding, &cbRowSize, &hAccessor ), TRUE)) odtLog << L"Histogram colinfo doesn't match.\n"; // Make sure the provider returned valid info if (cBinding > 0 && pBinding && cbRowSize > 0 && hAccessor != DB_NULL_HACCESSOR) { LPBYTE pDataHist = NULL; DBBINDING dbBind; DBCOUNTITEM ulRangeCount = 0; DBCOUNTITEM ulTotal = 0; // We need the table cardinality so if not available // we must compute ourselves if (pulTableCardinality) ulTotal = *pulTableCardinality; else ulTotal = Cardinality(pwszQualifiedName, 0, TABLE_CARDINALITY); // Create a binding structure for the other row // data memcpy(&dbBind, pBinding, sizeof(DBBINDING)); dbBind.obStatus+=cbRowSize; dbBind.obLength+=cbRowSize; dbBind.obValue+=cbRowSize; // Allocate memory for two rows of histogram SAFE_ALLOC(pDataRows, BYTE, cbRowSize*2); pDataHist = pDataRows; while ((hrGetNextRows = pIRowset->GetNextRows( NULL, 0, 1, &cRowsObtained, &phRows)) == S_OK) { cRows++; if (COMPARE(cRowsObtained, 1) && COMPARE(phRows != NULL, TRUE) && CHECK(pIRowset->GetData(phRows[0], hAccessor, pDataHist), S_OK)) { LPBYTE pRANGE_HI_KEY = GetValuePtr(HR_RANGE_HI_KEY, pDataHist, pBinding); TYPE_R8 * pRANGE_ROWS = (TYPE_R8 *)GetValuePtr(HR_RANGE_ROWS, pDataHist, pBinding); TYPE_R8 * pEQ_ROWS = (TYPE_R8 *)GetValuePtr(HR_EQ_ROWS, pDataHist, pBinding); TYPE_I8 * pDISTINCT_RANGE_ROWS = (TYPE_I8 *)GetValuePtr(HR_DISTINCT_RANGE_ROWS, pDataHist, pBinding); DBBINDING * pPrevBind=NULL; DBBINDING * pCurrentBind = pBinding; double fFraction, fPercent; // Set pointers to previous and current bindings for RANGE_HIGH_KEY if (cRows > 1) { if (pDataHist == pDataRows) { pCurrentBind = pBinding; pPrevBind = &dbBind; } else { pCurrentBind = &dbBind; pPrevBind = pBinding; } } // Validate this row // Check each status for unexpected values for (iBind = 0; iBind < cBinding; iBind++) { if (STATUS_BINDING(pBinding[iBind], pDataHist) != DBSTATUS_S_OK && STATUS_BINDING(pBinding[iBind], pDataHist) != DBSTATUS_S_ISNULL && !COMPARE(STATUS_BINDING(pBinding[iBind], pDataHist), DBSTATUS_S_OK)) odtLog << L"Histogram rowset column " << iBind << L" returned an unexpected status: " << STATUS_BINDING(pBinding[iBind], pDataHist) << L"\n"; } // RANGE_HI_KEY is mandatory if (!COMPARE(pRANGE_HI_KEY != NULL, TRUE)) odtLog << L"Table: " << pwszQualifiedName << L" Statistic: " << pwszQualifiedStatName << L" returned NULL for mandatory RANGE_HI_KEY\n"; // One of RANGE_ROWS or EQ_ROWS is required COMPARE(pRANGE_ROWS != NULL || pEQ_ROWS != NULL, TRUE); // Validate sort is by RANGE_HI_KEY, ascending order // Validate data for each returned column // RANGE_HI_KEY /* Actually, this may not necessarily be a value in the column It may not even be within the range of values in the table, so we really can't test this. // Must be a value in the column if (pRANGE_HI_KEY) { ulRangeCount = Cardinality(pwszQualifiedName, ulIndex, EQ_ROWS_CARDINALITY, NULL, pCurrentBind, pDataRows, cbRowSize*2); // Fail if no value in table == RANGE_HIGH_KEY if (!COMPARE(ulRangeCount > 0, TRUE)) odtLog << pwszTableName << L": RANGE_HI_KEY not in base table.\n"; } */ // RANGE_ROWS // Fraction of number of rows that fall in this histogram // range. Select rows in this range and // divide by table cardinality. if (pRANGE_ROWS) { // Can't compute cardinality for BLOB at this time if (m_prgColInfo[ulIndex].dwFlags & DBCOLUMNFLAGS_ISLONG) { odtLog << L"Test cannot compute cardinality for LONG columns.\n"; odtLog << L"Comparison skipped.\n"; } else { ulRangeCount = Cardinality(pwszQualifiedName, ulIndex, RANGE_ROWS_CARDINALITY, pPrevBind, pCurrentBind, pDataRows, cbRowSize*2); fFraction = (float)(DB_LORDINAL)ulRangeCount/(float)(DB_LORDINAL)ulTotal; // Compute percentage error in result, avoid division by 0 if (fFraction > 0.0) fPercent = fabs((*(double *)pRANGE_ROWS - fFraction)/fFraction); else fPercent = 0.0; // Fail if off by more than 10% CCOMPARE(m_EC, fPercent < MAX_STATISTIC_ERROR, EC_BAD_RANGE_ROWS, L"RANGE_ROWS not within 10%", FALSE); } } // EQ_ROWS // Fraction of rows equal to RANGE_HIGH_KEY. // Select rows equal and divide by table cardinality. if (pEQ_ROWS) { ulRangeCount = Cardinality(pwszQualifiedName, ulIndex, EQ_ROWS_CARDINALITY, NULL, pCurrentBind, pDataRows, cbRowSize*2); fFraction = (float)(DB_LORDINAL)ulRangeCount/(float)(DB_LORDINAL)ulTotal; // Compute percentage error in result, avoid division by 0 if (fFraction > 0.0) fPercent = fabs((*(double *)pEQ_ROWS - fFraction)/fFraction); else fPercent = 0.0; // Fail if off by more than 10% CCOMPARE(m_EC, fPercent < MAX_STATISTIC_ERROR, EC_BAD_EQ_ROWS, L"EQ_ROWS not within 10%", FALSE); } // DISTINCT_RANGE_ROWS // Number of distinct values in this range. // Select distinct rows in this range. if (pDISTINCT_RANGE_ROWS) { ulRangeCount = Cardinality(pwszQualifiedName, ulIndex, DISTINCT_RANGE_ROWS_CARDINALITY, pPrevBind, pCurrentBind, pDataRows, cbRowSize*2); // Compute percentage error in result, avoid division by 0 if (ulRangeCount) fPercent = fabs(float((*(LONGLONG *)pDISTINCT_RANGE_ROWS - (LONGLONG)ulRangeCount))/(float)(DB_LORDINAL)ulRangeCount); else fPercent = 0.0; // Fail if off by more than 10% CCOMPARE(m_EC, fPercent < MAX_STATISTIC_ERROR, EC_BAD_DISTINCT_RANGE_ROWS, L"DISTINCT_RANGE_ROWS not within 10%", FALSE); } } else { odtLog << L"Unable to retrieve data from Histogram for column: " << (m_prgColInfo[ulIndex]).pwszName << ".\n"; } // Release the row CHECK(pIRowset->ReleaseRows(1, phRows, NULL, NULL, NULL), S_OK); // Point the pDataHist buffer to other half of total buffer pDataHist = pDataRows+cbRowSize*(cRows % 2); ReleaseInputBindingsMemory(cBinding, pBinding, pDataHist, FALSE); } // Free the row handles SAFE_FREE(phRows); // Release memory for the previous row we retrieved if (cRows) ReleaseInputBindingsMemory(cBinding, pBinding, pDataRows+cbRowSize*((cRows-1) % 2), FALSE); SAFE_FREE(pDataRows); // Make sure we got DB_S_ENDOFROWSET CHECK(hrGetNextRows, DB_S_ENDOFROWSET); // Make sure row count matches NO_OF_RANGES if (pcRanges && !COMPARE(cRows, *pcRanges)) { odtLog << L"NO_OF_RANGES did not match count of rows in Histogram rowset.\n"; odtLog << L"NO_OF_RANGES: " << *pcRanges << L" Row count: " << cRows << "\n"; odtLog << L"TABLE: " << pwszQualifiedName << L"\n"; odtLog << L"STATISTIC: " << pwszQualifiedStatName << L"\n"; } } } } else { CHECK(pIRowset == NULL, TRUE); // We allow the histogram failure if the table no longer // exists. if (!CHECK(hrOpenHistogram, DB_E_NOTABLE) || !COMPARE(FAILED(hrOpenTable), TRUE)) odtLog << L"Histogram rowset not returned.\n"; } } } else { // If the table was deleted the provider may return // DB_E_NOTABLE instead of DB_E_NOSTATISTIC if (hrOpenHistogram != DB_E_NOTABLE) { HRESULT hrExp = DB_E_NOSTATISTIC; CCHECK(m_EC, hrOpenHistogram, hrExp, EC_BAD_HR_OPENHISTOGRAM, L"Unexpected return code from OpenRowset on histogram.", FALSE); } } SAFE_RELEASE(pIRowset); } } break; } case TSS_COLUMN_NAME: // Sanity check // Column must have non-empty string and cannot be NULL if (COMPARE(pColumn->sStatus, DBSTATUS_S_OK)) { // Detail check if (m_fDetailCheck && SUCCEEDED(hrOpenTable) && m_prgColInfo) // Column name must match columns info for this ordinal COMPARE(RelCompareString(m_prgColInfo[ulIndex].pwszName, (TYPE_WSTR)pColumn->bValue), 0); } break; case TSS_COLUMN_GUID: // Sanity check: none // Detail check if (m_fDetailCheck && SUCCEEDED(hrOpenTable)) { // Column guid must match columns info if (S_OK == pColumn->sStatus) { COMPARE(m_prgColInfo[ulIndex].columnid.uGuid.guid == *(GUID *)pColumn->bValue, TRUE); } else { // Must be NULL // COMPARE(m_prgColInfo[ulIndex].columnid.uGuid.guid == DB_NULLGUID, TRUE); } } break; case TSS_COLUMN_PROPID: // Sanity check: none // Detail check if (m_fDetailCheck && SUCCEEDED(hrOpenTable)) { // Column propid must match columns info if (S_OK == pColumn->sStatus) COMPARE(m_prgColInfo[ulIndex].columnid.uName.ulPropid == *(ULONG *)pColumn->bValue, TRUE); // If status == DBSTATUS_S_ISNULL, then value is undefined and can't be // compared. And it appears ulPropid in columnsinfo is uninitialized. } break; case TSS_ORDINAL_POSITION: // The ordinal position must be sequential within the table { // Column cannot be null if (COMPARE(pColumn->sStatus, DBSTATUS_S_OK)) { // If we have a valid column name if (pwszTableName && pwszStatName) { if (fNewStat) { // This is a new statistic, ordinal must be 1 m_iOrdinalExpected = 1; SAFE_FREE(m_pwszTableName); SAFE_FREE(m_pwszStatName); m_pwszTableName = wcsDuplicate(pwszTableName); m_pwszStatName = wcsDuplicate(pwszStatName); } else m_iOrdinalExpected++; // Compare Ordinal returned with expected if (!COMPARE(m_iOrdinalExpected, *(TYPE_UI4 *)pColumn->bValue)) odtLog << pwszTableName << L": Invalid ordinal value returned.\n"; } } break; } case TSS_SAMPLE_PCT: case TSS_LAST_UPDATE_TIME: case TSS_NO_OF_RANGES: // This is tested for accuracy by counting rows in histogram rowset. break; case TSS_COLUMN_CARDINALITY: eCardinality = COLUMN_CARDINALITY; // Fall through case TSS_TUPLE_CARDINALITY: // This should equal number distinct rows in table for this column if (m_fDetailCheck && SUCCEEDED(hrOpenTable) && pColumn->sStatus == DBSTATUS_S_OK) { LPWSTR pwszCardinality = L"COLUMN_CARDINALITY"; if (eCardinality == TUPLE_CARDINALITY) pwszCardinality = L"TUPLE_CARDINALITY"; if (m_prgColInfo) { // Can't compute cardinality for BLOB at this time if (m_prgColInfo[ulIndex].dwFlags & DBCOLUMNFLAGS_ISLONG) { odtLog << L"Test cannot compute cardinality for LONG columns.\n"; odtLog << L"Comparison skipped.\n"; } else { DBCOUNTITEM cRows = Cardinality(pwszQualifiedName, ulIndex, eCardinality); WCHAR wszMessage[MAX_MSG_BUF] = L""; swprintf(wszMessage, L"%s is incorrect\nTable: %s Statistic: %s %s expected: %d received: %d\n", pwszCardinality, pwszQualifiedName, pwszQualifiedStatName, pwszCardinality, cRows, *(ULONG *)pColumn->bValue); // Note test bug here Cardinality() doesn't include BLOB columns, so if the // statistic includes BLOBs we skip the comparison. if (!m_fCardinalityIncludesBlob) { if(!CCOMPARE(m_EC, cRows == *(ULONG *)pColumn->bValue, EC_BAD_COL_OR_TUPLE_CARD, wszMessage, FALSE)) odtLog << L""; } } } } break; case TSS_TABLE_CARDINALITY: // Detail check // This should equal number of rows in table if (m_fDetailCheck && SUCCEEDED(hrOpenTable) && pColumn->sStatus == DBSTATUS_S_OK) { DBCOUNTITEM cRows = Cardinality(pwszQualifiedName, ulIndex, TABLE_CARDINALITY); CCOMPARE(m_EC, cRows == *(ULONG *)pColumn->bValue, EC_BAD_TABLE_CARDINALITY, L"Table cardinality is incorrect", FALSE); } break; case TSS_AVG_COLUMN_LENGTH: break; } CLEANUP: SAFE_FREE(pwszQualifiedName); SAFE_FREE(pwszQualifiedStatName); return fResults; } // Referential Constraints schema specific functions class CReferentialConstraintsHelper : public CHelper { private: protected: public: CReferentialConstraintsHelper(void) {m_guidSchema = DBSCHEMA_REFERENTIAL_CONSTRAINTS;} }; // Schemata schema specific functions class CSchemataHelper : public CHelper { private: protected: public: CSchemataHelper(void) {m_guidSchema = DBSCHEMA_SCHEMATA;} }; // Statistics schema specific functions class CStatisticsHelper : public CHelper { private: protected: public: CStatisticsHelper(void) {m_guidSchema = DBSCHEMA_STATISTICS;} }; // Trustee schema specific functions class CTrusteeHelper : public CHelper { private: protected: public: CTrusteeHelper(void) {m_guidSchema = DBSCHEMA_TRUSTEE;} }; // Views schema specific functions class CViewsHelper : public CHelper { private: protected: public: CViewsHelper(void) {m_guidSchema = DBSCHEMA_VIEWS;} }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Test Case Section // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // {{ TCW_TEST_CASE_MAP(CCommon) //-------------------------------------------------------------------- // @class test IDBSchemaRowset::GetRowset // class CCommon : public CSchemaTest { protected: CHelper * m_pCHelper; // @cmember Static array of variations DECLARE_TEST_CASE_DATA(); public: // {{ TCW_DECLARE_FUNCS // @cmember Execution Routine DECLARE_TEST_CASE_FUNCS(CCommon,CSchemaTest); // }} TCW_DECLARE_FUNCS_END CCommon(void) {m_pCHelper = NULL;} void SetHelper(CHelper * pCHelper) {m_pCHelper = pCHelper;} // @cmember Initialization Routine virtual BOOL Init(); // @cmember Termination Routine virtual BOOL Terminate(); // {{ TCW_TESTVARS() // @cmember S_OK: No restrictions, no props int Variation_1(); // @cmember E_INVALIDARG: rguidSchema = DBPROPSET_ROWSET int Variation_2(); // @cmember E_INVALIDARG: rguidSchema = GUID_NULL int Variation_3(); // @cmember DB_E_NOTSUPPORTED: provider does not support restrictions int Variation_4(); // @cmember S_OK: pass all supported restrictions int Variation_5(); // @cmember S_OK: less than max restrictions int Variation_6(); // @cmember E_INVALIDARG: more than max restrictions int Variation_7(); // @cmember E_NOINTERFACE: riid is not initialized int Variation_8(); // @cmember S_OK: restrictions valid for 1st and 3rd restrictions int Variation_9(); // @cmember S_OK: 2 cmd objects open on session int Variation_10(); // @cmember DB_E_ERRORSOCCURED: update properties on read-only rowset int Variation_11(); // @cmember DB_S_ERRORSOCCURED: DBPROP_IRowsetInfo & DBPROP_IRowsetChange int Variation_12(); // @cmember S_OK: DBPROP_BOOKMARKS int Variation_13(); // @cmember S_OK: empty variants = no restricions passed int Variation_14(); // @cmember S_OK or E_NOINTERFACE: all rowset riids int Variation_15(); // @cmember E_NOINTERFACE: riid = IID_IDBProperties int Variation_16(); // @cmember E_INVALIDARG: ppRowset = NULL int Variation_17(); // @cmember E_INVALIDARG: cRestrictions > 0, rgRestrictions = NULL int Variation_18(); // @cmember E_INVALIDARG: cProperty != 0, rgProperties = NULL int Variation_19(); // @cmember E_INVALIDARG: cPropertySets > 0, rgPropertySets = NULL int Variation_20(); // @cmember E_INVALIDARG: invalid restriction with wrong VT type int Variation_21(); // @cmember S_OK: request DBPROP_IColumnsRowset and, iid = IID_IColumnsRowset int Variation_22(); // @cmember S_OK: riid = IID_IRowsetInfo, call IRowset::GetSpecification int Variation_23(); // @cmember S_OK: riid = IID_IUnknown, get IRowset from IUnknown int Variation_24(); // @cmember S_OK: open rowset from schema, try to open rowset on command int Variation_25(); // @cmember S_OK: IRowsetScroll int Variation_26(); // @cmember E_INVALIDARG: Schema not supported int Variation_27(); // @cmember S_OK: Empty result set, pass first restriction that matches second restriction int Variation_28(); // @cmember S_OK: Empty result set, pass non-matching value for each restriction int Variation_29(); // @cmember First restriction int Variation_30(); // @cmember Second restriction int Variation_31(); // @cmember Third restriction int Variation_32(); // @cmember Fourth restriction int Variation_33(); // @cmember Fifth restriction int Variation_34(); // @cmember Sixth restriction int Variation_35(); // @cmember Seventh restriction int Variation_36(); // @cmember S_OK: all rowset properties as required int Variation_37(); // @cmember S_OK: all rowset properties as optional int Variation_38(); // @cmember S_OK: all rowset properties, 2 at time, 1 optional, 1 required int Variation_39(); // @cmember DB_E_ERRORSOCCURRED: non-rowset property sets, all properties in that set int Variation_40(); // @cmember Security: Maximum sized string restriction int Variation_41(); // @cmember Security: Max size plus one string restriction int Variation_42(); // @cmember Security: Extremely large string restriction int Variation_43(); // @cmember Security: Use %s in string restriction int Variation_44(); // @cmember Security: Use recursive variant in restriction int Variation_45(); // @cmember Security: Use unclosed quote in restriction int Variation_46(); // @cmember Synonyms: Use table synonym in table restriction int Variation_47(); // @cmember Synonyms: Use SYNONYM in table type restriction int Variation_48(); // @cmember Synonyms: Use synonym for table name restriction and SYNONYM in table type restriction. int Variation_49(); // @cmember Security: SQLBU #363546: Use max size string restriction of closing square brackets int Variation_50(); // @cmember Security: SQLBU #363546: Use extremely large string restriction of closing square brackets int Variation_51(); // @cmember SQLBU #395368: Use a sortid that does not have a SQL collation int Variation_52(); // }} TCW_TESTVARS_END }; // {{ TCW_TESTCASE(CCommon) #define THE_CLASS CCommon BEG_TEST_CASE(CCommon, CSchemaTest, L"test IDBSchemaRowset::GetRowset") TEST_VARIATION(1, L"S_OK: No restrictions, no props") TEST_VARIATION(2, L"E_INVALIDARG: rguidSchema = DBPROPSET_ROWSET") TEST_VARIATION(3, L"E_INVALIDARG: rguidSchema = GUID_NULL") TEST_VARIATION(4, L"DB_E_NOTSUPPORTED: provider does not support restrictions") TEST_VARIATION(5, L"S_OK: pass all supported restrictions") TEST_VARIATION(6, L"S_OK: less than max restrictions") TEST_VARIATION(7, L"E_INVALIDARG: more than max restrictions") TEST_VARIATION(8, L"E_NOINTERFACE: riid is not initialized") TEST_VARIATION(9, L"S_OK: restrictions valid for 1st and 3rd restrictions") TEST_VARIATION(10, L"S_OK: 2 cmd objects open on session") TEST_VARIATION(11, L"DB_E_ERRORSOCCURED: update properties on read-only rowset") TEST_VARIATION(12, L"DB_S_ERRORSOCCURED: DBPROP_IRowsetInfo & DBPROP_IRowsetChange") TEST_VARIATION(13, L"S_OK: DBPROP_BOOKMARKS") TEST_VARIATION(14, L"S_OK: empty variants = no restricions passed") TEST_VARIATION(15, L"S_OK or E_NOINTERFACE: all rowset riids") TEST_VARIATION(16, L"E_NOINTERFACE: riid = IID_IDBProperties") TEST_VARIATION(17, L"E_INVALIDARG: ppRowset = NULL") TEST_VARIATION(18, L"E_INVALIDARG: cRestrictions > 0, rgRestrictions = NULL") TEST_VARIATION(19, L"E_INVALIDARG: cProperty != 0, rgProperties = NULL") TEST_VARIATION(20, L"E_INVALIDARG: cPropertySets > 0, rgPropertySets = NULL") TEST_VARIATION(21, L"E_INVALIDARG: invalid restriction with wrong VT type") TEST_VARIATION(22, L"S_OK: request DBPROP_IColumnsRowset and, iid = IID_IColumnsRowset") TEST_VARIATION(23, L"S_OK: riid = IID_IRowsetInfo, call IRowset::GetSpecification") TEST_VARIATION(24, L"S_OK: riid = IID_IUnknown, get IRowset from IUnknown") TEST_VARIATION(25, L"S_OK: open rowset from schema, try to open rowset on command") TEST_VARIATION(26, L"S_OK: IRowsetScroll") TEST_VARIATION(27, L"E_INVALIDARG: Schema not supported") TEST_VARIATION(28, L"S_OK: Empty result set, pass first restriction that matches second restriction") TEST_VARIATION(29, L"S_OK: Empty result set, pass non-matching value for each restriction") TEST_VARIATION(30, L"First restriction") TEST_VARIATION(31, L"Second restriction") TEST_VARIATION(32, L"Third restriction") TEST_VARIATION(33, L"Fourth restriction") TEST_VARIATION(34, L"Fifth restriction") TEST_VARIATION(35, L"Sixth restriction") TEST_VARIATION(36, L"Seventh restriction") TEST_VARIATION(37, L"S_OK: all rowset properties as required") TEST_VARIATION(38, L"S_OK: all rowset properties as optional") TEST_VARIATION(39, L"S_OK: all rowset properties, 2 at time, 1 optional, 1 required") TEST_VARIATION(40, L"DB_E_ERRORSOCCURRED: non-rowset property sets, all properties in that set") TEST_VARIATION(41, L"Security: Maximum sized string restriction") TEST_VARIATION(42, L"Security: Max size plus one string restriction") TEST_VARIATION(43, L"Security: Extremely large string restriction") TEST_VARIATION(44, L"Security: Use %s in string restriction") TEST_VARIATION(45, L"Security: Use recursive variant in restriction") TEST_VARIATION(46, L"Security: Use unclosed quote in restriction") TEST_VARIATION(47, L"Synonyms: Use table synonym in table restriction") TEST_VARIATION(48, L"Synonyms: Use SYNONYM in table type restriction") TEST_VARIATION(49, L"Synonyms: Use synonym for table name restriction and SYNONYM in table type restriction.") TEST_VARIATION(50, L"Security: SQLBU #363546: Use max size string restriction of closing square brackets") TEST_VARIATION(51, L"Security: SQLBU #363546: Use extremely large string restriction of closing square brackets") TEST_VARIATION(52, L"SQLBU #395368: Use a sortid that does not have a SQL collation") END_TEST_CASE() #undef THE_CLASS // }} TCW_TESTCASE_END // }} TCW_TEST_CASE_MAP_END // {{ TCW_TEST_CASE_MAP(CGetSchema) //-------------------------------------------------------------------- // @class test IDBSchemaRowset::GetSchemas // class CGetSchema : public CSchemaTest { private: // @cmember Static array of variations DECLARE_TEST_CASE_DATA(); public: // {{ TCW_DECLARE_FUNCS // @cmember Execution Routine DECLARE_TEST_CASE_FUNCS(CGetSchema,CSchemaTest); // }} TCW_DECLARE_FUNCS_END // @cmember Initialization Routine virtual BOOL Init(); // @cmember Termination Routine virtual BOOL Terminate(); // {{ TCW_TESTVARS() // @cmember E_INVALIDARG: pcSchemas = NULL int Variation_1(); // @cmember S_OK: *prgSchemas = NULL, pcSchemas = 0 int Variation_2(); // @cmember S_OK: prgRestrictionSupported = NULL int Variation_3(); // @cmember E_INVALIDARG: prgSchemas = NULL int Variation_4(); // @cmember S_OK: open schema rowset, try to open rowset from command object int Variation_5(); // @cmember S_OK: don't initialize variables before sending int Variation_6(); // }} TCW_TESTVARS_END }; // {{ TCW_TESTCASE(CGetSchema) #define THE_CLASS CGetSchema BEG_TEST_CASE(CGetSchema, CSchemaTest, L"test IDBSchemaRowset::GetSchemas") TEST_VARIATION(1, L"E_INVALIDARG: pcSchemas = NULL") TEST_VARIATION(2, L"S_OK: *prgSchemas = NULL, pcSchemas = 0") TEST_VARIATION(3, L"S_OK: prgRestrictionSupported = NULL") TEST_VARIATION(4, L"E_INVALIDARG: prgSchemas = NULL") TEST_VARIATION(5, L"S_OK: open schema rowset, try to open rowset from command object") TEST_VARIATION(6, L"S_OK: don't initialize variables before sending") END_TEST_CASE() #undef THE_CLASS // }} TCW_TESTCASE_END // }} TCW_TEST_CASE_MAP_END // {{ TCW_TEST_CASE_MAP(CZombie) //-------------------------------------------------------------------- // @class testing IDBSchemaRowset in zombie situation // class CZombie : public CTransaction { private: // @cmember Static array of variations DECLARE_TEST_CASE_DATA(); public: // {{ TCW_DECLARE_FUNCS // @cmember Execution Routine DECLARE_TEST_CASE_FUNCS(CZombie,CTransaction); // }} TCW_DECLARE_FUNCS_END // @cmember Initialization Routine virtual BOOL Init(); // @cmember Termination Routine virtual BOOL Terminate(); int TestTxnGetRowset(ETXN eTxn,BOOL fRetaining, GUID schema); int TestTxnGetSchemas(ETXN eTxn,BOOL fRetaining); // {{ TCW_TESTVARS() // @cmember GetRowset: Commit with fRetaining set to TRUE int Variation_1(); // @cmember GetRowset: Commit with fRetaining set to FALSE int Variation_2(); // @cmember GetRowset: Abort with fRetaining set to TRUE int Variation_3(); // @cmember GetRowset: Abort with fRetaining set to FALSE int Variation_4(); // @cmember GetSchemas: Commit with fRetaining set to TRUE int Variation_5(); // @cmember GetSchemas: Commit with fRetaining set to FALSE int Variation_6(); // @cmember GetSchemas: Abort with fRetaining set to TRUE int Variation_7(); // @cmember GetSchemas: Abort with fRetaining set to FALSE int Variation_8(); // }} TCW_TESTVARS_END }; // {{ TCW_TESTCASE(CZombie) #define THE_CLASS CZombie BEG_TEST_CASE(CZombie, CTransaction, L"testing IDBSchemaRowset in zombie situation") TEST_VARIATION(1, L"GetRowset: Commit with fRetaining set to TRUE") TEST_VARIATION(2, L"GetRowset: Commit with fRetaining set to FALSE") TEST_VARIATION(3, L"GetRowset: Abort with fRetaining set to TRUE") TEST_VARIATION(4, L"GetRowset: Abort with fRetaining set to FALSE") TEST_VARIATION(5, L"GetSchemas: Commit with fRetaining set to TRUE") TEST_VARIATION(6, L"GetSchemas: Commit with fRetaining set to FALSE") TEST_VARIATION(7, L"GetSchemas: Abort with fRetaining set to TRUE") TEST_VARIATION(8, L"GetSchemas: Abort with fRetaining set to FALSE") END_TEST_CASE() #undef THE_CLASS // }} TCW_TESTCASE_END // }} TCW_TEST_CASE_MAP_END // {{ TCW_TEST_CASE_MAP(ExtendedErrors) //-------------------------------------------------------------------- // @class testing extended errors on IDBSchemaRowset // class ExtendedErrors : public CSchemaTest { private: // @cmember Static array of variations DECLARE_TEST_CASE_DATA(); CHelper * GetSchemaHelper(GUID guidSchema); public: // {{ TCW_DECLARE_FUNCS // @cmember Execution Routine DECLARE_TEST_CASE_FUNCS(ExtendedErrors,CSchemaTest); // }} TCW_DECLARE_FUNCS_END // @cmember Initialization Routine virtual BOOL Init(); // @cmember Termination Routine virtual BOOL Terminate(); // {{ TCW_TESTVARS() // @cmember Valid GetSchemas Call with previous error object existing int Variation_1(); // @cmember Valid GetRowset call with previous error object existing int Variation_2(); // @cmember Valid GetSchemas call with previous error object existing int Variation_3(); // @cmember Invalid GetRowset call with previous error object existing int Variation_4(); // @cmember Invalid GetSchemas call with previous error object existing int Variation_5(); // @cmember Invalid GetRowset call with previous error object existing int Variation_6(); // @cmember Open schema rowset DBSCHEMA_ASSERTIONS -- E_INVALIDARG int Variation_7(); // }} TCW_TESTVARS_END }; // {{ TCW_TESTCASE(ExtendedErrors) #define THE_CLASS ExtendedErrors BEG_TEST_CASE(ExtendedErrors, CSchemaTest, L"testing extended errors on IDBSchemaRowset") TEST_VARIATION(1, L"Valid GetSchemas Call with previous error object existing") TEST_VARIATION(2, L"Valid GetRowset call with previous error object existing") TEST_VARIATION(3, L"Valid GetSchemas call with previous error object existing") TEST_VARIATION(4, L"Invalid GetRowset call with previous error object existing") TEST_VARIATION(5, L"Invalid GetSchemas call with previous error object existing") TEST_VARIATION(6, L"Invalid GetRowset call with previous error object existing") TEST_VARIATION(7, L"Open schema rowset DBSCHEMA_ASSERTIONS -- E_INVALIDARG") END_TEST_CASE() #undef THE_CLASS // }} TCW_TESTCASE_END // }} TCW_TEST_CASE_MAP_END // {{ TCW_TEST_CASE_MAP(CBugRegressions) //*----------------------------------------------------------------------- // @class Test case for bug regressions // class CBugRegressions : public CSchemaTest { private: // @cmember Static array of variations DECLARE_TEST_CASE_DATA(); public: // {{ TCW_DECLARE_FUNCS // @cmember Execution Routine DECLARE_TEST_CASE_FUNCS(CBugRegressions,CSchemaTest); // }} TCW_DECLARE_FUNCS_END // @cmember Initialization Routine virtual BOOL Init(); // @cmember Termination Routine virtual BOOL Terminate(); // {{ TCW_TESTVARS() // @cmember GetRowset on schema TABLES after executing RETURN statement int Variation_1(); // }} TCW_TESTVARS_END } ; // {{ TCW_TESTCASE(CBugRegressions) #define THE_CLASS CBugRegressions BEG_TEST_CASE(CBugRegressions, CSchemaTest, L"Test case for bug regressions") TEST_VARIATION(1, L"GetRowset on schema TABLES after executing RETURN statement") END_TEST_CASE() #undef THE_CLASS // }} TCW_TESTCASE_END // }} TCW_TEST_CASE_MAP_END // {{ TCW_TEST_CASE_MAP(CTableStatistics) //*----------------------------------------------------------------------- // @class Test DBSCHEMA_TABLE_STATISTICS // class CTableStatistics : public CSchemaTest { private: // @cmember Static array of variations DECLARE_TEST_CASE_DATA(); public: // {{ TCW_DECLARE_FUNCS // @cmember Execution Routine DECLARE_TEST_CASE_FUNCS(CTableStatistics,CSchemaTest); // }} TCW_DECLARE_FUNCS_END // @cmember Initialization Routine virtual BOOL Init(); // @cmember Termination Routine virtual BOOL Terminate(); // {{ TCW_TESTVARS() // @cmember Validate DBPROP_OPENROWSETSUPPORT, DBPROPVAL_ORS_HISTOGRAM int Variation_1(); // }} TCW_TESTVARS_END } ; // {{ TCW_TESTCASE(CTableStatistics) #define THE_CLASS CTableStatistics BEG_TEST_CASE(CTableStatistics, CSchemaTest, L"Test DBSCHEMA_TABLE_STATISTICS") TEST_VARIATION(1, L"Validate DBPROP_OPENROWSETSUPPORT, DBPROPVAL_ORS_HISTOGRAM") END_TEST_CASE() #undef THE_CLASS // }} TCW_TESTCASE_END // }} TCW_TEST_CASE_MAP_END // }} END_DECLARE_TEST_CASES() #define COPY_TEST_CASE(theClass, baseClass) \ class theClass : public baseClass \ { \ public: \ static const WCHAR m_wszTestCaseName[]; \ DECLARE_TEST_CASE_FUNCS(theClass, baseClass); \ }; \ const WCHAR theClass::m_wszTestCaseName[] = { L#theClass }; \ #define TEST_CASE_WITH_HELPER(iCase, theClass, helperClass) \ case iCase: \ pCTestCase = new theClass(NULL); \ ((theClass*)pCTestCase)->SetHelper(new helperClass()); \ pCTestCase->SetOwningMod(iCase-1, pCThisTestModule); \ return pCTestCase; COPY_TEST_CASE(CAssertionsCommon, CCommon) COPY_TEST_CASE(CCatalogsCommon, CCommon) COPY_TEST_CASE(CCharacterSetsCommon, CCommon) COPY_TEST_CASE(CCheckConstraintsCommon, CCommon) COPY_TEST_CASE(CCheckConstraintsByTableCommon, CCommon) COPY_TEST_CASE(CCollationsCommon, CCommon) COPY_TEST_CASE(CColumnDomainUsageCommon, CCommon) COPY_TEST_CASE(CColumnPrivilegesCommon, CCommon) COPY_TEST_CASE(CColumnsCommon, CCommon) COPY_TEST_CASE(CConstraintColumnUsageCommon, CCommon) COPY_TEST_CASE(CForeignKeysCommon, CCommon) COPY_TEST_CASE(CIndexesCommon, CCommon) COPY_TEST_CASE(CKeyColumnUsageCommon, CCommon) COPY_TEST_CASE(CPrimaryKeysCommon, CCommon) COPY_TEST_CASE(CProceduresCommon, CCommon) COPY_TEST_CASE(CProcedureColumnsCommon, CCommon) COPY_TEST_CASE(CProcedureParametersCommon, CCommon) COPY_TEST_CASE(CProviderTypesCommon, CCommon) COPY_TEST_CASE(CReferentialConstraintsCommon, CCommon) COPY_TEST_CASE(CSchemataCommon, CCommon) COPY_TEST_CASE(CStatisticsCommon, CCommon) COPY_TEST_CASE(CTableConstraintsCommon, CCommon) COPY_TEST_CASE(CTablePrivilegesCommon, CCommon) COPY_TEST_CASE(CTablesInfoCommon, CCommon) COPY_TEST_CASE(CTablesCommon, CCommon) COPY_TEST_CASE(CTableStatisticsCommon, CCommon) COPY_TEST_CASE(CTrusteeCommon, CCommon) COPY_TEST_CASE(CViewsCommon, CCommon) #if 0 // {{ TCW_TESTMODULE(ThisModule) TEST_MODULE(6, ThisModule, gwszModuleDescrip) TEST_CASE(1, CCommon) TEST_CASE(2, CGetSchema) TEST_CASE(3, CZombie) TEST_CASE(4, ExtendedErrors) TEST_CASE(5, CBugRegressions) TEST_CASE(6, CTableStatistics) END_TEST_MODULE() // }} TCW_TESTMODULE_END #else TEST_MODULE(33, ThisModule, gwszModuleDescrip) TEST_CASE(1, CGetSchema) TEST_CASE_WITH_HELPER(2, CAssertionsCommon, CAssertionsHelper) TEST_CASE_WITH_HELPER(3, CCatalogsCommon, CCatalogsHelper) TEST_CASE_WITH_HELPER(4, CCharacterSetsCommon, CCharacterSetsHelper) TEST_CASE_WITH_HELPER(5, CCheckConstraintsCommon, CCheckConstraintsHelper) TEST_CASE_WITH_HELPER(6, CCheckConstraintsByTableCommon, CCheckConstraintsByTableHelper) TEST_CASE_WITH_HELPER(7, CCollationsCommon, CCollationsHelper) TEST_CASE_WITH_HELPER(8, CColumnDomainUsageCommon, CColumnDomainUsageHelper) TEST_CASE_WITH_HELPER(9, CColumnPrivilegesCommon, CColumnPrivilegesHelper) TEST_CASE_WITH_HELPER(10, CColumnsCommon, CColumnsHelper) TEST_CASE_WITH_HELPER(11, CConstraintColumnUsageCommon, CConstraintColumnUsageHelper) TEST_CASE_WITH_HELPER(12, CForeignKeysCommon, CForeignKeysHelper) TEST_CASE_WITH_HELPER(13, CIndexesCommon, CIndexesHelper) TEST_CASE_WITH_HELPER(14, CKeyColumnUsageCommon, CKeyColumnUsageHelper) TEST_CASE_WITH_HELPER(15, CPrimaryKeysCommon, CPrimaryKeysHelper) TEST_CASE_WITH_HELPER(16, CProceduresCommon, CProceduresHelper) TEST_CASE_WITH_HELPER(17, CProcedureColumnsCommon, CProcedureColumnsHelper) TEST_CASE_WITH_HELPER(18, CProcedureParametersCommon, CProcedureParametersHelper) TEST_CASE_WITH_HELPER(19, CProviderTypesCommon, CProviderTypesHelper) TEST_CASE_WITH_HELPER(20, CReferentialConstraintsCommon, CReferentialConstraintsHelper) TEST_CASE_WITH_HELPER(21, CSchemataCommon, CSchemataHelper) TEST_CASE_WITH_HELPER(22, CStatisticsCommon, CStatisticsHelper) TEST_CASE_WITH_HELPER(23, CTableConstraintsCommon, CTableConstraintsHelper) TEST_CASE_WITH_HELPER(24, CTablePrivilegesCommon, CTablePrivilegesHelper) TEST_CASE_WITH_HELPER(25, CTablesInfoCommon, CTablesInfoHelper) TEST_CASE_WITH_HELPER(26, CTablesCommon, CTablesHelper) TEST_CASE_WITH_HELPER(27, CTableStatisticsCommon, CTableStatisticsHelper) TEST_CASE_WITH_HELPER(28, CTrusteeCommon, CTrusteeHelper) TEST_CASE_WITH_HELPER(29, CViewsCommon, CViewsHelper) TEST_CASE(30, CZombie) TEST_CASE(31, ExtendedErrors) TEST_CASE(32, CBugRegressions) TEST_CASE(33, CTableStatistics) END_TEST_MODULE() #endif // {{ TCW_TC_PROTOTYPE(CCommon) //*----------------------------------------------------------------------- //| Test Case: CCommon - test IDBSchemaRowset::GetRowset //| Created: 09/23/96 //*----------------------------------------------------------------------- //-------------------------------------------------------------------- // @mfunc TestCase Initialization Routine // // @rdesc TRUE or FALSE // BOOL CCommon::Init() { // {{ TCW_INIT_BASECLASS_CHECK if(CSchemaTest::Init()) // }} { if (COMPARE(m_pCHelper != NULL, TRUE)) return m_pCHelper->Init(this); } return FALSE; } // {{ TCW_VAR_PROTOTYPE(1) //*----------------------------------------------------------------------- // @mfunc S_OK: No restrictions, no props // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_1() { HRESULT hrExp = S_OK; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } // Test method CHECK(m_pCHelper->GetRowsetHelper(NULL, RV_NULL), hrExp); m_pCHelper->SetRowCount(MIN_VALUE, 1); return TEST_PASS; } // }} // {{ TCW_VAR_PROTOTYPE(2) //*----------------------------------------------------------------------- // @mfunc E_INVALIDARG: rguidSchema = DBPROPSET_ROWSET // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_2() { // Test method CHECK(m_pCHelper->GetRowsetHelper(NULL, RV_NULL, NULL, IID_IRowset, 0, NULL, NULL, DBPROPSET_ROWSET), E_INVALIDARG); return TEST_PASS; } // }} // {{ TCW_VAR_PROTOTYPE(3) //*----------------------------------------------------------------------- // @mfunc E_INVALIDARG: rguidSchema = GUID_NULL // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_3() { IRowset * pIRowset = NULL; // Have to turn off setting of default arguments m_pCHelper->UseArgumentDefaults(FALSE); // Test method CHECK(m_pCHelper->GetRowsetHelper(NULL, 0, NULL, IID_IRowset, 0, NULL, (IUnknown **)&pIRowset, GUID_NULL), E_INVALIDARG); // Set default args back on m_pCHelper->UseArgumentDefaults(TRUE); return TEST_PASS; } // }} // {{ TCW_VAR_PROTOTYPE(4) //*----------------------------------------------------------------------- // @mfunc DB_E_NOTSUPPORTED: provider does not support restrictions // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_4() { HRESULT hr = E_FAIL; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } if (!m_pCHelper->HasUnsupportedRestriction()) { odtLog << L"No unsupported restrictions.\n"; return TEST_SKIPPED; } // Set to use all cached restrictions, supported or not m_pCHelper->SetRestrictionArray(RT_CACHED); // Test method hr = m_pCHelper->GetRowsetHelper(NULL, RV_ALL); // Provider may return E_INVALIDARG here, but we prefer DB_E_NOTSUPPORTED if (hr != E_INVALIDARG) CHECK(hr, DB_E_NOTSUPPORTED); // Set back to use supported restrictions m_pCHelper->SetRestrictionArray(RT_SUPPORTED); return TEST_PASS; } // }} // {{ TCW_VAR_PROTOTYPE(5) //*----------------------------------------------------------------------- // @mfunc S_OK: pass all supported restrictions // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_5() { if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } // Test method CHECK(m_pCHelper->GetRowsetHelper(), S_OK); return TEST_PASS; } // }} // {{ TCW_VAR_PROTOTYPE(6) //*----------------------------------------------------------------------- // @mfunc S_OK: less than max restrictions // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_6() { ULONG cRestrictions = m_pCHelper->RestrictionCount(); if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } // Test method CHECK(m_pCHelper->GetRowsetHelper(NULL, cRestrictions-1), S_OK); return TEST_PASS; } // }} // {{ TCW_VAR_PROTOTYPE(7) //*----------------------------------------------------------------------- // @mfunc E_INVALIDARG: more than max restrictions // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_7() { ULONG cRestrictions = m_pCHelper->RestrictionCount(); // Test method. Note spec change that providers may return E_INVALIDARG or // DB_E_NOTSUPPORTED for this case. TEST2C_(m_pCHelper->GetRowsetHelper(NULL, cRestrictions+1), DB_E_NOTSUPPORTED, E_INVALIDARG); CLEANUP: return TEST_PASS; } // }} // {{ TCW_VAR_PROTOTYPE(8) //*----------------------------------------------------------------------- // @mfunc E_NOINTERFACE: riid is not initialized // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_8() { GUID iid; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } memset(&iid, 0x0c, sizeof(GUID)); // Test method CHECK(m_pCHelper->GetRowsetHelper(NULL, 0, NULL, iid), E_NOINTERFACE); return TEST_PASS; } // }} // {{ TCW_VAR_PROTOTYPE(9) //*----------------------------------------------------------------------- // @mfunc S_OK: restrictions valid for 1st and 3rd restrictions // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_9() { if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } if (!m_pCHelper->IsSupportedRestriction(RV_ONE) && !m_pCHelper->IsSupportedRestriction(RV_THREE)) { odtLog << L"1st and 3rd restrictions not supported.\n"; return TEST_SKIPPED; } m_pCHelper->SetRestrictionArray(RT_CUSTOM); m_pCHelper->ClearRestrictions(); if (m_pCHelper->IsSupportedRestriction(RV_ONE)) m_pCHelper->SetValidRestriction(RV_ONE); else odtLog << L"1st retriction not supported, setting only 3rd.\n"; if (m_pCHelper->IsSupportedRestriction(RV_THREE)) m_pCHelper->SetValidRestriction(RV_THREE); else odtLog << L"3rd retriction not supported, setting only 1st.\n"; // Test method CHECK(m_pCHelper->GetRowsetHelper(), S_OK); m_pCHelper->SetRestrictionArray(RT_SUPPORTED); return TEST_PASS; } // }} // {{ TCW_VAR_PROTOTYPE(10) //*----------------------------------------------------------------------- // @mfunc S_OK: 2 cmd objects open on session // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_10() { ICommand * pICommand = NULL; BOOL fResult = FALSE; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } // If the provider doesn't support commands then // m_pIDBCreateCommand is NULL if (!m_pIDBCreateCommand) { odtLog << L"Commands not supported.\n"; return TEST_SKIPPED; } // create a second object open on the session object TESTC_(m_pIDBCreateCommand->CreateCommand( NULL, IID_ICommand, (IUnknown **)&pICommand), S_OK); // test method CHECK(m_pCHelper->GetRowsetHelper(), S_OK); fResult = TEST_PASS; CLEANUP: SAFE_RELEASE(pICommand); return fResult; } // }} // {{ TCW_VAR_PROTOTYPE(11) //*----------------------------------------------------------------------- // @mfunc DB_E_ERRORSOCCURED: update properties on read-only rowset // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_11() { ULONG ulIndex=0; ULONG ulIndexProperties=0; ULONG ulprop=0; DBPROPSET * pPropSet = NULL; ULONG cPropSet = 0; DBTYPE wPropType; LPVOID lpvPropVal; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } // for each invalid property for(ulIndexProperties=0;ulIndexPropertiesget_ICommandPTR() && (GetProperty(rgUpdateProperties[ulIndexProperties],DBPROPSET_ROWSET,m_pTable->get_ICommandPTR())))) { odtLog << L"---" << rgwszUpdateProperties[ulIndexProperties] << L"-\n" ; // Most props are BOOL, but DBPROP_UPDATABILITY is I4 if (rgUpdateProperties[ulIndexProperties] == DBPROP_UPDATABILITY) { wPropType = DBTYPE_I4; lpvPropVal = (LPVOID)(DBPROPVAL_UP_CHANGE|DBPROPVAL_UP_INSERT|DBPROPVAL_UP_DELETE); } else { wPropType = DBTYPE_BOOL; lpvPropVal = (LPVOID)VARIANT_TRUE; } TESTC_(SetProperty(rgUpdateProperties[ulIndexProperties], DBPROPSET_ROWSET, &cPropSet, &pPropSet, wPropType, &lpvPropVal), S_OK); // test method CHECK(m_pCHelper->GetRowsetHelper(NULL, RV_ALL, NULL, IID_IRowset, cPropSet, pPropSet), DB_E_ERRORSOCCURRED); // There is some ambiguity on what DBPROPSTATUS to allow for schema rowsets since they are // r/o and therefore don't support some rowset props. We prefer DBPROPSTATUS_CONFLICTING // since that conflicts with DBPROP_UPDATABILITY, but we will allow others here such // as DBPROPSTATUS_NOTSETTABLE. if (pPropSet[0].rgProperties[0].dwStatus != DBPROPSTATUS_NOTSETTABLE) { VerifyPropStatus(cPropSet, pPropSet, rgUpdateProperties[ulIndexProperties], DBPROPSET_ROWSET, DBPROPSTATUS_CONFLICTING); } // Free the property info for next iteration FreeProperties(&cPropSet, &pPropSet); } else odtLog << L"Property not supported or not writable, " << rgwszUpdateProperties[ulIndexProperties] << ENDL; } CLEANUP: FreeProperties(&cPropSet, &pPropSet); return TEST_PASS; } // }} // {{ TCW_VAR_PROTOTYPE(12) //*----------------------------------------------------------------------- // @mfunc DB_S_ERRORSOCCURED: DBPROP_IRowsetInfo & DBPROP_IRowsetChange // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_12() { BOOL fResult = TRUE; DBPROPSET * pPropSet = NULL; ULONG cPropSet = 0; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } if(!IsRowsetPropertySupported(DBPROP_IRowsetInfo)) { odtLog << L"Mandatory interface IRowsetInfo is not supported or not writable\n"; return TEST_SKIPPED; } if(!IsRowsetPropertySupported(DBPROP_IRowsetChange)) { odtLog << L"IRowsetChange is not supported or not writable\n"; return TEST_SKIPPED; } TESTC_(SetProperty(DBPROP_IRowsetInfo, DBPROPSET_ROWSET, &cPropSet, &pPropSet, DBTYPE_BOOL, VARIANT_TRUE), S_OK); TESTC_(SetProperty(DBPROP_IRowsetChange, DBPROPSET_ROWSET, &cPropSet, &pPropSet, DBTYPE_BOOL, VARIANT_TRUE), S_OK); // test method TESTC_(m_pCHelper->GetRowsetHelper(NULL, RV_ALL, NULL, IID_IRowset, cPropSet, pPropSet), DB_S_ERRORSOCCURRED); if (!VerifyPropStatus(cPropSet, pPropSet, DBPROP_IRowsetInfo, DBPROPSET_ROWSET, DBPROPSTATUS_CONFLICTING)) goto CLEANUP; if (!VerifyPropStatus(cPropSet, pPropSet, DBPROP_IRowsetChange, DBPROPSET_ROWSET, DBPROPSTATUS_CONFLICTING)) goto CLEANUP; fResult = TRUE; CLEANUP: FreeProperties(&cPropSet, &pPropSet); return fResult; } // }} // {{ TCW_VAR_PROTOTYPE(13) //*----------------------------------------------------------------------- // @mfunc S_OK: DBPROP_BOOKMARKS // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_13() { BOOL fResult = TRUE; DBPROPSET * pPropSet = NULL; ULONG cPropSet = 0; HRESULT hr = E_FAIL; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } if(!IsRowsetPropertySupported(DBPROP_BOOKMARKS)) { odtLog << L"Bookmark not supported\n"; return TEST_SKIPPED; } TESTC_(SetProperty(DBPROP_BOOKMARKS, DBPROPSET_ROWSET, &cPropSet, &pPropSet, DBTYPE_BOOL, VARIANT_TRUE), S_OK); // test method hr = m_pCHelper->GetRowsetHelper(NULL, RV_ALL, NULL, IID_IRowset, cPropSet, pPropSet); if (S_OK == hr) { if (!VerifyPropStatus(cPropSet, pPropSet, DBPROP_BOOKMARKS, DBPROPSET_ROWSET, DBPROPSTATUS_OK)) goto CLEANUP; } else { TESTC_(hr, DB_E_ERRORSOCCURRED); if (!VerifyPropStatus(cPropSet, pPropSet, DBPROP_BOOKMARKS, DBPROPSET_ROWSET, DBPROPSTATUS_CONFLICTING)) goto CLEANUP; } fResult = TRUE; CLEANUP: FreeProperties(&cPropSet, &pPropSet); return fResult; } // }} // {{ TCW_VAR_PROTOTYPE(14) //*----------------------------------------------------------------------- // @mfunc S_OK: empty variants = no restricions passed // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_14() { if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } // Use our custom restriction array m_pCHelper->SetRestrictionArray(RT_CUSTOM); // Set them all to VT_EMPTY m_pCHelper->ClearRestrictions(); // Test method CHECK(m_pCHelper->GetRowsetHelper(), S_OK); // Set back to supported restrictions m_pCHelper->SetRestrictionArray(RT_SUPPORTED); m_pCHelper->SetRowCount(MIN_VALUE, 1); return TEST_PASS; } // }} // {{ TCW_VAR_PROTOTYPE(15) //*----------------------------------------------------------------------- // @mfunc S_OK or E_NOINTERFACE: all rowset riids // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_15() { ULONG i, cRowsetIIDs = 0; INTERFACEMAP* rgRowsetIIDs = NULL; IUnknown * pIUnknown = NULL; HRESULT hr = E_FAIL; BOOL fResult = FALSE; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } //Obtain the Rowset IIDs TESTC(GetInterfaceArray(ROWSET_INTERFACE, &cRowsetIIDs, &rgRowsetIIDs)); //Loop through all rowset IIDs... for(i=0; iGetRowsetHelper(NULL, RV_ALL, NULL, *rgRowsetIIDs[i].pIID, 0, NULL, &pIUnknown, GUID_NULL, FALSE); // Allow S_OK or E_NOINTERFACE if (S_OK != hr) { CHECK(hr, E_NOINTERFACE); } //Success, verify this interface... if(hr == S_OK) { if(!ValidInterface(*rgRowsetIIDs[i].pIID, pIUnknown)) TERROR(L"Interface Incorrect for " << GetInterfaceName(*rgRowsetIIDs[i].pIID) << "\n"); TESTC(DefaultObjectTesting(pIUnknown, ROWSET_INTERFACE)); } else { //Make sure this is allowed to not be required TCOMPARE_(!rgRowsetIIDs[i].fMandatory); } SAFE_RELEASE(pIUnknown); } fResult = TRUE; CLEANUP: return fResult; } // }} // {{ TCW_VAR_PROTOTYPE(16) //*----------------------------------------------------------------------- // @mfunc E_NOINTERFACE: riid = IID_IDBProperties // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_16() { if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } // Test method CHECK(m_pCHelper->GetRowsetHelper(NULL, 0, NULL, IID_IDBProperties), E_NOINTERFACE); return TEST_PASS; } // }} // {{ TCW_VAR_PROTOTYPE(17) //*----------------------------------------------------------------------- // @mfunc E_INVALIDARG: ppRowset = NULL // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_17() { if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } // Have to turn off setting of default arguments m_pCHelper->UseArgumentDefaults(FALSE); // Test method CHECK(m_pCHelper->GetRowsetHelper(NULL, 0, NULL, IID_IRowset, 0, NULL, NULL, m_pCHelper->GetSchema()), E_INVALIDARG); // Set default args back on m_pCHelper->UseArgumentDefaults(TRUE); return TEST_PASS; } // }} // {{ TCW_VAR_PROTOTYPE(18) //*----------------------------------------------------------------------- // @mfunc E_INVALIDARG: cRestrictions > 0, rgRestrictions = NULL // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_18() { IRowset * pIRowset = NULL; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } // Have to turn off setting of default arguments m_pCHelper->UseArgumentDefaults(FALSE); // Test method CHECK(m_pCHelper->GetRowsetHelper(NULL, 1, NULL, IID_IRowset, 0, NULL, (IUnknown **)&pIRowset, m_pCHelper->GetSchema()), E_INVALIDARG); // Set default args back on m_pCHelper->UseArgumentDefaults(TRUE); return TEST_PASS; } // }} // {{ TCW_VAR_PROTOTYPE(19) //*----------------------------------------------------------------------- // @mfunc E_INVALIDARG: cProperty != 0, rgProperties = NULL // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_19() { DBPROPSET rgPropSet[1]; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } rgPropSet[0].cProperties = 1; rgPropSet[0].guidPropertySet = DBPROPSET_ROWSET; rgPropSet[0].rgProperties = NULL; // Test method CHECK(m_pCHelper->GetRowsetHelper(NULL, RV_ALL, NULL, IID_IRowset, 1, rgPropSet), E_INVALIDARG); return TEST_PASS; } // }} // {{ TCW_VAR_PROTOTYPE(20) //*----------------------------------------------------------------------- // @mfunc E_INVALIDARG: cPropertySets > 0, rgPropertySets = NULL // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_20() { if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } // Test method CHECK(m_pCHelper->GetRowsetHelper(NULL, RV_ALL, NULL, IID_IRowset, 1, NULL), E_INVALIDARG); return TEST_PASS; } // }} // {{ TCW_VAR_PROTOTYPE(21) //*----------------------------------------------------------------------- // @mfunc E_INVALIDARG: invalid restriction with wrong VT type // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_21() { ULONG ulIndex=0; HRESULT hrTemp = E_FAIL; IDispatch * pIDispatch = new CDispatch; BOOL fSetInvalidRestriction = FALSE; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } m_pCHelper->SetRestrictionArray(RT_CUSTOM); m_pCHelper->ClearRestrictions(); if (m_pCHelper->IsSupportedRestriction(RV_ONE)) { m_pIDBSchemaRowset->AddRef(); m_pCHelper->SetInvalidRestriction(RV_ONE, (LPVOID)m_pIDBSchemaRowset, VT_UNKNOWN); fSetInvalidRestriction = TRUE; } if (m_pCHelper->IsSupportedRestriction(RV_TWO)) { pIDispatch->AddRef(); m_pCHelper->SetInvalidRestriction(RV_TWO, (LPVOID)pIDispatch, VT_DISPATCH); fSetInvalidRestriction = TRUE; } if (m_pCHelper->IsSupportedRestriction(RV_THREE)) { m_pCHelper->SetInvalidRestriction(RV_THREE, (LPVOID)(LONG_PTR)hrTemp, VT_ERROR); fSetInvalidRestriction = TRUE; } if (m_pCHelper->IsSupportedRestriction(RV_FOUR)) { m_pCHelper->SetInvalidRestriction(RV_FOUR, (LPVOID)(IUnknown **)&(m_pIDBSchemaRowset), VT_BYREF|VT_UNKNOWN); fSetInvalidRestriction = TRUE; } if (m_pCHelper->IsSupportedRestriction(RV_FIVE)) { m_pCHelper->SetInvalidRestriction(RV_FIVE, (LPVOID)&pIDispatch, VT_BYREF|VT_DISPATCH); fSetInvalidRestriction = TRUE; } if (m_pCHelper->IsSupportedRestriction(RV_SIX)) { m_pCHelper->SetInvalidRestriction(RV_SIX, (LPVOID)&hrTemp, VT_BYREF|VT_ERROR); fSetInvalidRestriction = TRUE; } if (m_pCHelper->IsSupportedRestriction(RV_SEVEN)) { m_pCHelper->SetInvalidRestriction(RV_SEVEN, (LPVOID)&hrTemp, VT_BYREF|VT_ERROR); fSetInvalidRestriction = TRUE; } if (!fSetInvalidRestriction) { odtLog << L"No restrictions supported.\n"; goto CLEANUP; } CHECK(m_pCHelper->GetRowsetHelper(), E_INVALIDARG); CLEANUP: // Clear the bogus restrictions m_pCHelper->ClearRestrictions(); m_pCHelper->SetRestrictionArray(RT_SUPPORTED); SAFE_RELEASE(pIDispatch); return TEST_PASS; } // }} // {{ TCW_VAR_PROTOTYPE(22) //*----------------------------------------------------------------------- // @mfunc S_OK: request DBPROP_IColumnsRowset and, iid = IID_IColumnsRowset // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_22() { BOOL fResult = TRUE; DBPROPSET * pPropSet = NULL; ULONG cPropSet = 0; HRESULT hr = E_FAIL; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } if(!IsRowsetPropertySupported(DBPROP_IColumnsRowset)) { odtLog << L"IColumnsRowset is not supported.\n"; return TEST_SKIPPED; } TESTC_(SetProperty(DBPROP_IColumnsRowset, DBPROPSET_ROWSET, &cPropSet, &pPropSet, DBTYPE_BOOL, VARIANT_TRUE), S_OK); // test method TESTC_(m_pCHelper->GetRowsetHelper(NULL, RV_ALL, NULL, IID_IColumnsRowset, cPropSet, pPropSet), S_OK); if (!VerifyPropStatus(cPropSet, pPropSet, DBPROP_IColumnsRowset, DBPROPSET_ROWSET, DBPROPSTATUS_OK)) goto CLEANUP; fResult = TRUE; CLEANUP: FreeProperties(&cPropSet, &pPropSet); return fResult; } // }} // {{ TCW_VAR_PROTOTYPE(23) //*----------------------------------------------------------------------- // @mfunc S_OK: riid = IID_IRowsetInfo, call IRowset::GetSpecification // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_23() { HRESULT hr = E_FAIL; IUnknown * pIUnknown = NULL; IRowsetInfo * pIRowsetInfo = NULL; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } // Test method TESTC_(m_pCHelper->GetRowsetHelper(NULL, RV_ALL, NULL, IID_IRowsetInfo, 0, NULL, (IUnknown **)&pIRowsetInfo, GUID_NULL, FALSE), S_OK); TESTC(pIRowsetInfo != NULL); // GetSpecification should succeed hr = pIRowsetInfo->GetSpecification(IID_IDBSchemaRowset,&pIUnknown); if (hr == S_FALSE) { // Kagera - Temp table has no way of getting back to kagera's objects so it // returns S_FALSE // While this is allowed it's certainly unusual, print warning odtLog << L"WARNING - GetSpecification returned S_FALSE.\n"; odtLog << L"This is allowed but may signify a failure for this provider.\n"; // If we claim we didn't return an object make sure COMPARE(pIUnknown, NULL); } else { // We should have succeeded and returned a valid object pointer if (CHECK(hr, S_OK) && COMPARE(pIUnknown != NULL, TRUE)) { IOpenRowset * pIOpenRowset = NULL; // Schema rowsets are always opened via IDBSchemaRowset, therefore GetSpecification // should return a session interface. if (COMPARE(VerifyInterface(pIUnknown, IID_IOpenRowset, SESSION_INTERFACE, (IUnknown**)&pIOpenRowset),TRUE)) { SAFE_RELEASE(pIOpenRowset); } } } CLEANUP: SAFE_RELEASE(pIRowsetInfo); SAFE_RELEASE(pIUnknown); return TEST_PASS; } // }} // {{ TCW_VAR_PROTOTYPE(24) //*----------------------------------------------------------------------- // @mfunc S_OK: riid = IID_IUnknown, get IRowset from IUnknown // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_24() { IUnknown * pIUnknown = NULL; IRowset * pIRowset = NULL; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } // Test method TESTC_(m_pCHelper->GetRowsetHelper(NULL, RV_ALL, NULL, IID_IUnknown, 0, NULL, &pIUnknown, GUID_NULL, FALSE), S_OK); TESTC(pIUnknown != NULL); TESTC(VerifyInterface(pIUnknown, IID_IRowset, ROWSET_INTERFACE, (IUnknown**)&pIRowset)) // RestartPosition should succeed TEST2C_(pIRowset->RestartPosition(NULL), S_OK, DB_S_COMMANDREEXECUTED); CLEANUP: SAFE_RELEASE(pIRowset); SAFE_RELEASE(pIUnknown); return TRUE; } // }} // {{ TCW_VAR_PROTOTYPE(25) //*----------------------------------------------------------------------- // @mfunc S_OK: open rowset from schema, try to open rowset on command // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_25() { ULONG ulIndex=0; IRowset * pICommandRowset=NULL; ICommandText * pICommandText=NULL; WCHAR * pSQLText=NULL; IDBCreateCommand * pIDBCreateCommand=NULL; IRowset * pIRowset = NULL; BOOL fResult = FALSE; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } if(m_pIDBCreateCommand) { TESTC_(m_pIDBCreateCommand->CreateCommand(NULL,IID_ICommandText,(IUnknown**)&pICommandText),S_OK); } else { // Check to see if commands are supported TESTC_PROVIDER(VerifyInterface(m_pIOpenRowset, IID_IDBCreateCommand, SESSION_INTERFACE, (IUnknown**)&pIDBCreateCommand)) TESTC_(pIDBCreateCommand->CreateCommand(NULL,IID_ICommandText,(IUnknown**)&pICommandText),S_OK); } TESTC_(m_pTable->CreateSQLStmt(SELECT_ALLFROMTBL,m_pTable->GetTableName(),&pSQLText,NULL,NULL),S_OK); TESTC_(pICommandText->SetCommandText(DBGUID_DBSQL,pSQLText),S_OK); // Test method TESTC_(m_pCHelper->GetRowsetHelper(NULL, RV_ALL, NULL, IID_IRowset, 0, NULL, (IUnknown **)&pIRowset, GUID_NULL, FALSE), S_OK); TESTC(pIRowset != NULL); TESTC_(pICommandText->Execute(NULL,IID_IRowset,NULL,NULL,(IUnknown **)&pICommandRowset),S_OK); fResult = TRUE; CLEANUP: SAFE_RELEASE(pICommandText); SAFE_RELEASE(pIDBCreateCommand); SAFE_RELEASE(pICommandRowset); SAFE_RELEASE(pIRowset); // Free the memory SAFE_FREE(pSQLText); return fResult; } // }} // {{ TCW_VAR_PROTOTYPE(26) //*----------------------------------------------------------------------- // @mfunc S_OK: IRowsetScroll // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_26() { BOOL fResult = TRUE; IRowsetScroll * pIRowsetScroll = NULL; DBCOUNTITEM cRowsObtained = 0; HROW * phRow = NULL; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } if(!IsRowsetPropertySupported(DBPROP_IRowsetScroll)) { odtLog << L"IRowsetScroll is not supported.\n"; return TEST_SKIPPED; } // test method TESTC_(m_pCHelper->GetRowsetHelper(NULL, RV_ALL, NULL, IID_IRowsetScroll, 0, NULL, (IUnknown **)&pIRowsetScroll, GUID_NULL, FALSE), S_OK); TESTC(pIRowsetScroll != NULL); TESTC_(pIRowsetScroll->GetRowsAtRatio(NULL, NULL, 1, 2, 1, &cRowsObtained, &phRow), S_OK); TESTC(cRowsObtained); TESTC(phRow != NULL); fResult = TRUE; CLEANUP: if (phRow && pIRowsetScroll) CHECK(pIRowsetScroll->ReleaseRows(cRowsObtained, phRow, NULL, NULL, NULL), S_OK); SAFE_FREE(phRow); SAFE_RELEASE(pIRowsetScroll); return fResult; } // }} // {{ TCW_VAR_PROTOTYPE(27) //-------------------------------------------------------------------- // @mfunc E_INVALIDARG: Schema not supported // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_27() { HRESULT hrExp = S_OK; if (m_pCHelper->IsSupported()) { odtLog << L"Schema is supported.\n"; return TEST_SKIPPED; } CHECK(m_pCHelper->GetRowsetHelper(NULL, RV_NULL), E_INVALIDARG); return TEST_PASS; } // }} // {{ TCW_VAR_PROTOTYPE(28) //*----------------------------------------------------------------------- // @mfunc S_OK: Empty result set, pass first restriction that matches second restriction // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_28() { BOOL fResult = FALSE; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } // Must support both restrictions if (!m_pCHelper->IsSupportedRestriction(RV_ONE) || !m_pCHelper->IsSupportedRestriction(RV_TWO)) { odtLog << L"First or second restriction not suported.\n"; return TEST_SKIPPED; } // The VT must match between first and second restriction if (V_VT(m_pCHelper->GetRestrictPtr(RV_ONE)) != V_VT(m_pCHelper->GetRestrictPtr(RV_TWO))) { odtLog << L"First and second restriction are different types.\n"; return TEST_SKIPPED; } m_pCHelper->SetRestrictionArray(RT_CUSTOM); m_pCHelper->ClearRestrictions(); // Set first restriction to a valid value m_pCHelper->SetValidRestriction(RV_ONE); // Set second restriction to first restriction's value TESTC(m_pCHelper->SetRestriction(RV_TWO, m_pCHelper->GetRestrictPtr(RV_ONE))); // Tell helper to expect 0 rows m_pCHelper->SetRowCount(EXACT_VALUE, 0); // Get the rowset TESTC_(m_pCHelper->GetRowsetHelper(), S_OK); fResult = TRUE; CLEANUP: m_pCHelper->SetRowCount(MIN_VALUE, 1); m_pCHelper->SetRestrictionArray(RT_SUPPORTED); return fResult; } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_VAR_PROTOTYPE(29) //*----------------------------------------------------------------------- // @mfunc S_OK: Empty result set, pass non-matching value for each restriction // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_29() { BOOL fResult = FALSE; ULONG iRestrict; VARIANT * pVariant = NULL; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } // Use custom restrictions m_pCHelper->SetRestrictionArray(RT_CUSTOM); // Clear all m_pCHelper->ClearRestrictions(); // for all possible restrictions for (iRestrict = 1; iRestrict <= m_pCHelper->RestrictionCount(); iRestrict++) { // If this restriction isn't supported then don't test it if (!m_pCHelper->IsSupportedRestriction(iRestrict)) continue; // Set restriction to a valid value m_pCHelper->SetValidRestriction(iRestrict); pVariant = m_pCHelper->GetRestrictPtr(iRestrict); TESTC(pVariant != NULL); // It's impossible to come up with a nonmatching // value for boolean restrictions without first going // the entire rowset, so we'll skip boolean (VARIANT_BOOL) // restrictions. if (V_VT(pVariant) == VT_BOOL) continue; // Now reset to a bogus nonmatching value. We assume all available // bits set on will not match any restriction. if (V_VT(pVariant) == VT_BSTR) V_BSTR(pVariant)[0] = L'z'; // memset(V_BSTR(pVariant), 0x55, // wcslen(V_BSTR(pVariant))*sizeof(WCHAR)); else // For all other types just set all bits on. At this time there // are no BYREF restrictions. memset(&(pVariant->bVal), 0xF, sizeof(VARIANT)-sizeof(VARTYPE)-sizeof(USHORT)*3); // Over-ride the row count expected, we MUST get 0 rows m_pCHelper->SetRowCount(EXACT_VALUE, 0); // Get the rowset TESTC_(m_pCHelper->GetRowsetHelper(), S_OK); // Clear the bogus restriction m_pCHelper->ClearRestrictions(); } fResult = TRUE; CLEANUP: m_pCHelper->SetRowCount(MIN_VALUE, 1); m_pCHelper->SetRestrictionArray(RT_SUPPORTED); return fResult; } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_VAR_PROTOTYPE(30) //*----------------------------------------------------------------------- // @mfunc First restriction // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_30() { return m_pCHelper->TestRestriction(RV_ONE); } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_VAR_PROTOTYPE(31) //*----------------------------------------------------------------------- // @mfunc Second restriction // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_31() { return m_pCHelper->TestRestriction(RV_TWO); } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_VAR_PROTOTYPE(32) //*----------------------------------------------------------------------- // @mfunc Third restriction // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_32() { return m_pCHelper->TestRestriction(RV_THREE); } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_VAR_PROTOTYPE(33) //*----------------------------------------------------------------------- // @mfunc Fourth restriction // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_33() { return m_pCHelper->TestRestriction(RV_FOUR); } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_VAR_PROTOTYPE(34) //*----------------------------------------------------------------------- // @mfunc Fifth restriction // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_34() { return m_pCHelper->TestRestriction(RV_FIVE); } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_VAR_PROTOTYPE(35) //*----------------------------------------------------------------------- // @mfunc Sixth restriction // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_35() { return m_pCHelper->TestRestriction(RV_SIX); } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_VAR_PROTOTYPE(36) //*----------------------------------------------------------------------- // @mfunc Seventh restriction // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_36() { return m_pCHelper->TestRestriction(RV_SEVEN); } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_VAR_PROTOTYPE(37) //*----------------------------------------------------------------------- // @mfunc S_OK: all rowset properties as required // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_37() { // TODO: Consolidate vars 37, 38, and 39. BOOL fResult = FALSE; ULONG cPropInfos = 0; DBPROPINFO * pPropInfos = NULL; DBPROPSET * pPropSet = NULL; ULONG cPropSet = 0; LPVOID lpvPropVal; HRESULT hr = E_FAIL; DBPROPSTATUS dwPropStatusExpected; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } cPropInfos = m_rgRowsetDBPROPINFOSET[0].cPropertyInfos; pPropInfos = m_rgRowsetDBPROPINFOSET[0].rgPropertyInfos; // Spin through each rowset prop for(ULONG iProp=0; iProp < cPropInfos; iProp++) { DBPROPID dwPropertyID = pPropInfos[iProp].dwPropertyID; VARTYPE vt = pPropInfos[iProp].vtType; odtLog << pPropInfos[iProp].pwszDescription << L"\n"; // If this is a BOOLEAN property set on if (vt == VT_BOOL) lpvPropVal = (LPVOID)VARIANT_TRUE; else { // Value has to be specifically set for each property switch(dwPropertyID) { case DBPROP_ACCESSORDER: lpvPropVal = (LPVOID)(DBPROPVAL_AO_RANDOM); break; case DBPROP_UPDATABILITY: lpvPropVal = (LPVOID)(DBPROPVAL_UP_CHANGE|DBPROPVAL_UP_INSERT|DBPROPVAL_UP_DELETE); break; default: odtLog << L"\tProperty not yet tested.\n"; continue; } } TESTC_(SetProperty(dwPropertyID, DBPROPSET_ROWSET, &cPropSet, &pPropSet, vt, &lpvPropVal), S_OK); TEST2C_(hr = m_pCHelper->GetRowsetHelper(NULL, RV_ALL, NULL, IID_IRowset, cPropSet, pPropSet), S_OK, DB_E_ERRORSOCCURRED); if (S_OK == hr) dwPropStatusExpected = DBPROPSTATUS_OK; else if (!(pPropInfos[iProp].dwFlags & DBPROPFLAGS_WRITE)) { dwPropStatusExpected = DBPROPSTATUS_NOTSETTABLE; } else { // It has been determined that the proper status here is DBPROPSTATUS_CONFLICTING // if the provider does not support a given update property on a schema rowset. // We will cheat a little on the spec here since schema rowsets don't generally // support all the props other rowsets do and we will allow DBPROPSTATUS_NOTSETTABLE // even though GetPropertyInfo returns supported and settable. if (pPropSet[0].rgProperties[0].dwStatus == DBPROPSTATUS_NOTSETTABLE) dwPropStatusExpected = DBPROPSTATUS_NOTSETTABLE; else dwPropStatusExpected = DBPROPSTATUS_CONFLICTING; // If this is an update prop or the prop can't be supported on a schema rowset the // provider may return DBPROPSTATUS_NOTSUPPORTED. Since we don't have any way // to know what props the provider actually does support against a schema rowset // we have to allow this. if (pPropSet[0].rgProperties[0].dwStatus == DBPROPSTATUS_NOTSUPPORTED) dwPropStatusExpected = DBPROPSTATUS_NOTSUPPORTED; // If this is DBPROP_UPDATABILITY itself, we need to allow // DBPROPSTATUS_BADVALUE if the user attempts to set non-zero if (pPropSet[0].rgProperties[0].dwPropertyID == DBPROP_UPDATABILITY && V_I4(&pPropSet[0].rgProperties[0].vValue) != 0 && pPropSet[0].rgProperties[0].dwStatus == DBPROPSTATUS_BADVALUE) dwPropStatusExpected = DBPROPSTATUS_BADVALUE; } // VerifyPropStatus posts its own errors, don't check return. VerifyPropStatus(cPropSet, pPropSet, dwPropertyID, DBPROPSET_ROWSET, dwPropStatusExpected); // Free the property info for next iteration FreeProperties(&cPropSet, &pPropSet); } fResult = TRUE; CLEANUP: FreeProperties(&cPropSet, &pPropSet); return fResult; } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_VAR_PROTOTYPE(38) //*----------------------------------------------------------------------- // @mfunc S_OK: all rowset properties as optional // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_38() { BOOL fResult = FALSE; ULONG cPropInfos = 0; DBPROPINFO * pPropInfos = NULL; DBPROPSET * pPropSet = NULL; ULONG cPropSet = 0; LPVOID lpvPropVal; HRESULT hr = E_FAIL; DBPROPSTATUS dwPropStatusExpected; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } cPropInfos = m_rgRowsetDBPROPINFOSET[0].cPropertyInfos; pPropInfos = m_rgRowsetDBPROPINFOSET[0].rgPropertyInfos; // Spin through each rowset prop for(ULONG iProp=0; iProp < cPropInfos; iProp++) { DBPROPID dwPropertyID = pPropInfos[iProp].dwPropertyID; VARTYPE vt = pPropInfos[iProp].vtType; odtLog << pPropInfos[iProp].pwszDescription << L"\n"; // If this is a BOOLEAN property set on if (vt == VT_BOOL) lpvPropVal = (LPVOID)VARIANT_TRUE; else { // Value has to be specifically set for each property switch(dwPropertyID) { case DBPROP_ACCESSORDER: lpvPropVal = (LPVOID)(DBPROPVAL_AO_RANDOM); break; case DBPROP_UPDATABILITY: lpvPropVal = (LPVOID)(DBPROPVAL_UP_CHANGE|DBPROPVAL_UP_INSERT|DBPROPVAL_UP_DELETE); break; default: odtLog << L"\tProperty not yet tested.\n"; continue; } } TESTC_(SetProperty(dwPropertyID, DBPROPSET_ROWSET, &cPropSet, &pPropSet, vt, &lpvPropVal, DBPROPOPTIONS_OPTIONAL), S_OK); hr = m_pCHelper->GetRowsetHelper(NULL, RV_ALL, NULL, IID_IRowset, cPropSet, pPropSet); // Allow S_OK or DB_S_ERRORSOCCURRED. Don't use TESTC_ macro because we really don't // want to bail from our loop. if (hr != S_OK) CHECK(hr, DB_S_ERRORSOCCURRED); if (S_OK == hr) dwPropStatusExpected = DBPROPSTATUS_OK; else { dwPropStatusExpected = DBPROPSTATUS_NOTSET; // Since the property may not be settable for schema rowset we need to allow // DBPROPSTATUS_NOTSETTABLE here also. if (pPropSet[0].rgProperties[0].dwStatus == DBPROPSTATUS_NOTSETTABLE) dwPropStatusExpected = DBPROPSTATUS_NOTSETTABLE; // Since the property may not be supported for schema rowset we need to allow // DBPROPSTATUS_NOTSUPPORTED here also. Unlike regular rowsets we can't depend // on GetPropertyInfo to tell us whether it's supported. if (pPropSet[0].rgProperties[0].dwStatus == DBPROPSTATUS_NOTSUPPORTED) dwPropStatusExpected = DBPROPSTATUS_NOTSUPPORTED; // Since the property may require other properties to be set (example: sqlncli can not set DBPROP_IDBAsynchStatus until DBPROP_ROWSET_ASYNCH is set), // some providers may return DBPROPSTATUS_CONFLICTING if (pPropSet[0].rgProperties[0].dwStatus == DBPROPSTATUS_CONFLICTING) dwPropStatusExpected = DBPROPSTATUS_CONFLICTING; // And, finally, since we don't support updatability for schema rowsets, // some providers may return DBPROPSTATUS_BADVALUE when requesting update support if (pPropSet[0].rgProperties[0].dwStatus == DBPROPSTATUS_BADVALUE) dwPropStatusExpected = DBPROPSTATUS_BADVALUE; } // VerifyPropStatus posts its own errors, don't check return. VerifyPropStatus(cPropSet, pPropSet, dwPropertyID, DBPROPSET_ROWSET, dwPropStatusExpected); // Free the property info for next iteration FreeProperties(&cPropSet, &pPropSet); } fResult = TRUE; CLEANUP: FreeProperties(&cPropSet, &pPropSet); return fResult; } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_VAR_PROTOTYPE(39) //*----------------------------------------------------------------------- // @mfunc S_OK: all rowset properties, 2 at time, 1 optional, 1 required // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_39() { BOOL fResult = FALSE; ULONG cPropInfos = 0; DBPROPINFO * pPropInfos = NULL; DBPROPSET * pPropSet = NULL; ULONG cPropSet = 0; LPVOID lpvPropVal; LPVOID lpvPropValOpt; HRESULT hr = E_FAIL; BOOL fStatusOK; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } odtLog << L"This testing is too time consuming and has been removed.\n"; return TEST_SKIPPED; cPropInfos = m_rgRowsetDBPROPINFOSET[0].cPropertyInfos; pPropInfos = m_rgRowsetDBPROPINFOSET[0].rgPropertyInfos; // Spin through each rowset prop for(ULONG iProp=0; iProp < cPropInfos; iProp++) { for (ULONG jProp = 0; jProp < cPropInfos; jProp++) { // Don't set same prop both optional and required if (iProp == jProp) continue; DBPROPID dwPropertyID = pPropInfos[iProp].dwPropertyID; VARTYPE vt = pPropInfos[iProp].vtType; DBPROPID dwPropIDOpt = pPropInfos[jProp].dwPropertyID; VARTYPE vtOpt = pPropInfos[jProp].vtType; // If this is a BOOLEAN property set on if (vt == VT_BOOL) lpvPropVal = (LPVOID)VARIANT_TRUE; else { // Value has to be specifically set for each property switch(dwPropertyID) { case DBPROP_ACCESSORDER: lpvPropVal = (LPVOID)(DBPROPVAL_AO_RANDOM); break; case DBPROP_UPDATABILITY: lpvPropVal = (LPVOID)(DBPROPVAL_UP_CHANGE|DBPROPVAL_UP_INSERT|DBPROPVAL_UP_DELETE); break; default: continue; } } TESTC_(SetProperty(dwPropertyID, DBPROPSET_ROWSET, &cPropSet, &pPropSet, vt, &lpvPropVal), S_OK); // If this is a BOOLEAN property set on if (vtOpt == VT_BOOL) lpvPropValOpt = (LPVOID)VARIANT_TRUE; else { // Value has to be specifically set for each property switch(dwPropIDOpt) { case DBPROP_ACCESSORDER: lpvPropValOpt = (LPVOID)(DBPROPVAL_AO_RANDOM); break; case DBPROP_UPDATABILITY: lpvPropValOpt = (LPVOID)(DBPROPVAL_UP_CHANGE|DBPROPVAL_UP_INSERT|DBPROPVAL_UP_DELETE); break; default: FreeProperties(&cPropSet, &pPropSet); continue; } } TESTC_(SetProperty(dwPropIDOpt, DBPROPSET_ROWSET, &cPropSet, &pPropSet, vtOpt, &lpvPropValOpt, DBPROPOPTIONS_OPTIONAL), S_OK); TEST3C_(hr = m_pCHelper->GetRowsetHelper(NULL, RV_ALL, NULL, IID_IRowset, cPropSet, pPropSet), S_OK, DB_S_ERRORSOCCURRED, DB_E_ERRORSOCCURRED); fStatusOK = TRUE; if (S_OK == hr) { // Both properties were set, verify status fStatusOK &= VerifyPropStatus(cPropSet, pPropSet, dwPropertyID, DBPROPSET_ROWSET, DBPROPSTATUS_OK); fStatusOK &= VerifyPropStatus(cPropSet, pPropSet, dwPropIDOpt, DBPROPSET_ROWSET, DBPROPSTATUS_OK); } else if (DB_S_ERRORSOCCURRED == hr) { // First prop must have been set fStatusOK &= VerifyPropStatus(cPropSet, pPropSet, dwPropertyID, DBPROPSET_ROWSET, DBPROPSTATUS_OK); // Due to ambiguities in the spec the provider may return DBPROPSTATUS_NOTSETTABLE // or DBPROPSTATUS_NOTSUPPORTED here, but we prefer DBPROPSTATUS_NOTSET. if (pPropSet[0].rgProperties[1].dwStatus != DBPROPSTATUS_NOTSUPPORTED && pPropSet[0].rgProperties[1].dwStatus != DBPROPSTATUS_NOTSETTABLE) fStatusOK &= VerifyPropStatus(cPropSet, pPropSet, dwPropIDOpt, DBPROPSET_ROWSET, DBPROPSTATUS_NOTSET); } else { DBPROPSTATUS dwStatusExpected = DBPROPSTATUS_CONFLICTING; // First prop must be NOTSETTABLE or CONFLICTING since it was REQUIRED if (pPropSet[0].rgProperties[0].dwStatus == DBPROPSTATUS_NOTSETTABLE) dwStatusExpected = DBPROPSTATUS_NOTSETTABLE; // We will allow this if (pPropSet[0].rgProperties[0].dwStatus == DBPROPSTATUS_NOTSUPPORTED) dwStatusExpected = DBPROPSTATUS_NOTSUPPORTED; // We will allow this fStatusOK &= VerifyPropStatus(cPropSet, pPropSet, dwPropertyID, DBPROPSET_ROWSET, dwStatusExpected); // Other may have errored also, but may have succeeded if (pPropSet[0].rgProperties[1].dwStatus != DBPROPSTATUS_NOTSUPPORTED && pPropSet[0].rgProperties[1].dwStatus != DBPROPSTATUS_NOTSETTABLE) fStatusOK &= VerifyPropStatus(cPropSet, pPropSet, dwPropIDOpt, DBPROPSET_ROWSET, DBPROPSTATUS_OK); } if (!fStatusOK) odtLog << L"For property combination: " << pPropInfos[iProp].pwszDescription << L" and " << pPropInfos[jProp].pwszDescription << L"\n\n"; // Free the property info for next iteration FreeProperties(&cPropSet, &pPropSet); } } fResult = TRUE; CLEANUP: FreeProperties(&cPropSet, &pPropSet); return fResult; } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_VAR_PROTOTYPE(40) //*----------------------------------------------------------------------- // @mfunc DB_E_ERRORSOCCURRED: non-rowset property sets, all properties in that set // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_40() { // TODO: Consolidate vars 37, 38, and 39. BOOL fResult = FALSE; ULONG cPropInfos = 0; DBPROPINFO * pPropInfos = NULL; DBPROPSET * pPropSet = NULL; ULONG cPropSet = 0; LPVOID lpvPropVal; HRESULT hr = E_FAIL; DBPROPSTATUS dwPropStatusExpected; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } cPropInfos = m_rgDBPROPINFOSET[0].cPropertyInfos; pPropInfos = m_rgDBPROPINFOSET[0].rgPropertyInfos; for(ULONG iInfoSet=0; iInfoSet < m_cDBPROPINFOSET; iInfoSet++) { BOOL fRowsetPropSet = FALSE; // We only want the non-rowset props for (ULONG iRowsetInfoSet = 0; iRowsetInfoSet < m_cRowsetDBPROPINFOSET; iRowsetInfoSet++) { if (m_rgDBPROPINFOSET[iInfoSet].guidPropertySet == m_rgRowsetDBPROPINFOSET[iRowsetInfoSet].guidPropertySet) { fRowsetPropSet = TRUE; break; } } if (fRowsetPropSet) continue; // Spin through each non-rowset prop for(ULONG iProp=0; iProp < cPropInfos; iProp++) { DBPROPID dwPropertyID = pPropInfos[iProp].dwPropertyID; VARTYPE vt = pPropInfos[iProp].vtType; // odtLog << pPropInfos[iProp].pwszDescription << L"\n"; lpvPropVal = (LPVOID)VARIANT_TRUE; TESTC_(SetProperty(dwPropertyID, m_rgDBPROPINFOSET[iInfoSet].guidPropertySet, &cPropSet, &pPropSet, vt, &lpvPropVal), S_OK); TESTC_(hr = m_pCHelper->GetRowsetHelper(NULL, RV_ALL, NULL, IID_IRowset, cPropSet, pPropSet), DB_E_ERRORSOCCURRED); dwPropStatusExpected = DBPROPSTATUS_NOTSUPPORTED; VerifyPropStatus(cPropSet, pPropSet, dwPropertyID, m_rgDBPROPINFOSET[iInfoSet].guidPropertySet, dwPropStatusExpected); // Free the property info for next iteration FreeProperties(&cPropSet, &pPropSet); } } fResult = TRUE; CLEANUP: FreeProperties(&cPropSet, &pPropSet); return fResult; } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_VAR_PROTOTYPE(41) //*----------------------------------------------------------------------- // @mfunc Security: Maximum sized string restriction // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_41() { BOOL fResult = FALSE; ULONG iRestrict; VARIANT * pVariant = NULL; ULONG cchRestrictionMax = 0; BSTR bstrMaxRestriction = NULL; LPWSTR pwszMaxRestriction = NULL; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } // Use custom restrictions m_pCHelper->SetRestrictionArray(RT_CUSTOM); // Clear all m_pCHelper->ClearRestrictions(); // for all possible restrictions for (iRestrict = 1; iRestrict <= m_pCHelper->RestrictionCount(); iRestrict++) { // If this restriction isn't supported then don't test it if (!m_pCHelper->IsSupportedRestriction(iRestrict)) continue; // Get the max length for this restriction cchRestrictionMax = m_pCHelper->GetRestrictionMaxLength(iRestrict); // If the length is CCHMAXLENGTH_UNKNOWN, then the restriction does not have a max length OR // the max length is unknown if (cchRestrictionMax == CCHMAXLENGTH_UNKNOWN) continue; // Set restriction to a valid value m_pCHelper->SetValidRestriction(iRestrict); pVariant = m_pCHelper->GetRestrictPtr(iRestrict); TESTC(pVariant != NULL); // We don't care about non-BSTR restrictions if (V_VT(pVariant) != VT_BSTR) continue; // Now reset to a maximum value. Note this value likely does not // match any rows, so there should be an empty rowset. // Create a restriction value of the appropriate size bstrMaxRestriction = SysAllocStringLen(NULL, cchRestrictionMax+1); TESTC(bstrMaxRestriction != NULL); memset(bstrMaxRestriction, 1, cchRestrictionMax*sizeof(WCHAR)); bstrMaxRestriction[cchRestrictionMax] = L'\0'; VariantClear(pVariant); V_VT(pVariant) = VT_BSTR; V_BSTR(pVariant) = bstrMaxRestriction; bstrMaxRestriction = NULL; // Because the Variant now owns the BSTR. // Over-ride the row count expected, we MUST get 0 rows m_pCHelper->SetRowCount(EXACT_VALUE, 0); // Get the rowset TESTC_(m_pCHelper->GetRowsetHelper(), S_OK); // Clear the bogus restriction m_pCHelper->ClearRestrictions(); } fResult = TRUE; CLEANUP: // VariantClear(pVariant); Don't need to clear the variant as it's owned by the helper class m_pCHelper->SetRowCount(MIN_VALUE, 1); m_pCHelper->SetRestrictionArray(RT_SUPPORTED); return fResult; } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_VAR_PROTOTYPE(42) //*----------------------------------------------------------------------- // @mfunc Security: Max size plus one string restriction // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_42() { BOOL fResult = FALSE; ULONG iRestrict; VARIANT * pVariant = NULL; ULONG cchRestrictionMax = 0; BSTR bstrMaxRestriction = NULL; LPWSTR pwszMaxRestriction = NULL; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } // Use custom restrictions m_pCHelper->SetRestrictionArray(RT_CUSTOM); // Clear all m_pCHelper->ClearRestrictions(); // for all possible restrictions for (iRestrict = 1; iRestrict <= m_pCHelper->RestrictionCount(); iRestrict++) { // If this restriction isn't supported then don't test it if (!m_pCHelper->IsSupportedRestriction(iRestrict)) continue; // Get the max length for this restriction cchRestrictionMax = m_pCHelper->GetRestrictionMaxLength(iRestrict); // If the length is CCHMAXLENGTH_UNKNOWN, then the restriction does not have a max length OR // the max length is unknown if (cchRestrictionMax == CCHMAXLENGTH_UNKNOWN) continue; // Set restriction to a valid value m_pCHelper->SetValidRestriction(iRestrict); pVariant = m_pCHelper->GetRestrictPtr(iRestrict); TESTC(pVariant != NULL); // We don't care about non-BSTR restrictions if (V_VT(pVariant) != VT_BSTR) continue; // Now reset to a maximum plus 1 value. Note this value likely does not // match any rows, so there should be an empty rowset. cchRestrictionMax++; // Create a restriction value of the appropriate size. Use max size // plus null terminator. bstrMaxRestriction = SysAllocStringLen(NULL, cchRestrictionMax+1); TESTC(bstrMaxRestriction != NULL); memset(bstrMaxRestriction, 1, cchRestrictionMax*sizeof(WCHAR)); bstrMaxRestriction[cchRestrictionMax] = L'\0'; VariantClear(pVariant); V_VT(pVariant) = VT_BSTR; V_BSTR(pVariant) = bstrMaxRestriction; bstrMaxRestriction = NULL; // Because the Variant now owns the BSTR. // Over-ride the row count expected, we MUST get 0 rows m_pCHelper->SetRowCount(EXACT_VALUE, 0); // Get the rowset. Expect empty rowset (S_OK) or provider specific error (E_FAIL) TEST2C_(m_pCHelper->GetRowsetHelper(), S_OK, E_FAIL); // Clear the bogus restriction m_pCHelper->ClearRestrictions(); } fResult = TRUE; CLEANUP: // VariantClear(pVariant); Don't need to clear the variant as it's owned by the helper class m_pCHelper->SetRowCount(MIN_VALUE, 1); m_pCHelper->SetRestrictionArray(RT_SUPPORTED); return fResult; } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_VAR_PROTOTYPE(43) //*----------------------------------------------------------------------- // @mfunc Security: Extremely large string restriction // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_43() { BOOL fResult = FALSE; ULONG iRestrict; VARIANT * pVariant = NULL; ULONG cchRestrictionMax = 0; BSTR bstrMaxRestriction = NULL; LPWSTR pwszMaxRestriction = NULL; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } // Use custom restrictions m_pCHelper->SetRestrictionArray(RT_CUSTOM); // Clear all m_pCHelper->ClearRestrictions(); // for all possible restrictions for (iRestrict = 1; iRestrict <= m_pCHelper->RestrictionCount(); iRestrict++) { // If this restriction isn't supported then don't test it if (!m_pCHelper->IsSupportedRestriction(iRestrict)) continue; // Get the max length for this restriction cchRestrictionMax = m_pCHelper->GetRestrictionMaxLength(iRestrict); // If the length is CCHMAXLENGTH_UNKNOWN, then the restriction does not have a max length OR // the max length is unknown if (cchRestrictionMax == CCHMAXLENGTH_UNKNOWN) continue; // Set restriction to a valid value m_pCHelper->SetValidRestriction(iRestrict); pVariant = m_pCHelper->GetRestrictPtr(iRestrict); TESTC(pVariant != NULL); // We don't care about non-BSTR restrictions if (V_VT(pVariant) != VT_BSTR) continue; // Now reset to an extremely large value. We assume that an extremely // large value will be 1000 times that of the max value. Note this value likely does not // match any rows, so there should be an empty rowset. cchRestrictionMax *= 1000; // Create a restriction value of the appropriate size. Use max size // plus null terminator. bstrMaxRestriction = SysAllocStringLen(NULL, cchRestrictionMax+1); TESTC(bstrMaxRestriction != NULL); memset(bstrMaxRestriction, 1, cchRestrictionMax*sizeof(WCHAR)); bstrMaxRestriction[cchRestrictionMax] = L'\0'; VariantClear(pVariant); V_VT(pVariant) = VT_BSTR; V_BSTR(pVariant) = bstrMaxRestriction; bstrMaxRestriction = NULL; // Because the Variant now owns the BSTR. // Over-ride the row count expected, we MUST get 0 rows m_pCHelper->SetRowCount(EXACT_VALUE, 0); // Get the rowset. Expect empty rowset (S_OK) or provider specific error (E_FAIL) TEST2C_(m_pCHelper->GetRowsetHelper(), S_OK, E_FAIL); // Clear the bogus restriction m_pCHelper->ClearRestrictions(); } fResult = TRUE; CLEANUP: // VariantClear(pVariant); Don't need to clear the variant as it's owned by the helper class m_pCHelper->SetRowCount(MIN_VALUE, 1); m_pCHelper->SetRestrictionArray(RT_SUPPORTED); return fResult; } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_VAR_PROTOTYPE(44) //*----------------------------------------------------------------------- // @mfunc Security: Use %s in string restriction // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_44() { BOOL fResult = FALSE; ULONG iRestrict; VARIANT * pVariant = NULL; ULONG cchRestrictionMax = 0; BSTR bstrMaxRestriction = NULL; LPWSTR pwszMaxRestriction = NULL; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } // Use custom restrictions m_pCHelper->SetRestrictionArray(RT_CUSTOM); // Clear all m_pCHelper->ClearRestrictions(); // for all possible restrictions for (iRestrict = 1; iRestrict <= m_pCHelper->RestrictionCount(); iRestrict++) { // If this restriction isn't supported then don't test it if (!m_pCHelper->IsSupportedRestriction(iRestrict)) continue; // Get the max length for this restriction cchRestrictionMax = m_pCHelper->GetRestrictionMaxLength(iRestrict); // If the length is CCHMAXLENGTH_UNKNOWN, then the restriction does not have a max length OR // the max length is unknown if (cchRestrictionMax == CCHMAXLENGTH_UNKNOWN) continue; // Set restriction to a valid value m_pCHelper->SetValidRestriction(iRestrict); pVariant = m_pCHelper->GetRestrictPtr(iRestrict); TESTC(pVariant != NULL); // We don't care about non-BSTR restrictions if (V_VT(pVariant) != VT_BSTR) continue; // Create a restriction value of the appropriate size bstrMaxRestriction = SysAllocStringLen(NULL, cchRestrictionMax+1); TESTC(bstrMaxRestriction != NULL); memset(bstrMaxRestriction, 1, cchRestrictionMax*sizeof(WCHAR)); bstrMaxRestriction[cchRestrictionMax] = L'\0'; // Put a %s in the string restriction wcsncpy(bstrMaxRestriction, L"%s", wcslen(L"%s")); VariantClear(pVariant); V_VT(pVariant) = VT_BSTR; V_BSTR(pVariant) = bstrMaxRestriction; bstrMaxRestriction = NULL; // Because the Variant now owns the BSTR. // Over-ride the row count expected, we MUST get 0 rows m_pCHelper->SetRowCount(EXACT_VALUE, 0); // Get the rowset TESTC_(m_pCHelper->GetRowsetHelper(), S_OK); // Clear the bogus restriction m_pCHelper->ClearRestrictions(); } fResult = TRUE; CLEANUP: // VariantClear(pVariant); Don't need to clear the variant as it's owned by the helper class m_pCHelper->SetRowCount(MIN_VALUE, 1); m_pCHelper->SetRestrictionArray(RT_SUPPORTED); return fResult; } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_VAR_PROTOTYPE(45) //*----------------------------------------------------------------------- // @mfunc Security: Use recursive variant in restriction // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_45() { BOOL fResult = FALSE; ULONG iRestrict; VARIANT * pVariant = NULL; ULONG cchRestrictionMax = 0; BSTR bstrMaxRestriction = NULL; LPWSTR pwszMaxRestriction = NULL; VARIANT vVar; VARIANT * pvVar = &vVar; VariantInit(pvVar); if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } // Use custom restrictions m_pCHelper->SetRestrictionArray(RT_CUSTOM); // Clear all m_pCHelper->ClearRestrictions(); // for all possible restrictions for (iRestrict = 1; iRestrict <= m_pCHelper->RestrictionCount(); iRestrict++) { // If this restriction isn't supported then don't test it if (!m_pCHelper->IsSupportedRestriction(iRestrict)) continue; // Get the max length for this restriction cchRestrictionMax = m_pCHelper->GetRestrictionMaxLength(iRestrict); // If the length is CCHMAXLENGTH_UNKNOWN, then the restriction does not have a max length OR // the max length is unknown if (cchRestrictionMax == CCHMAXLENGTH_UNKNOWN) continue; // Set restriction to a valid value m_pCHelper->SetValidRestriction(iRestrict); pVariant = m_pCHelper->GetRestrictPtr(iRestrict); TESTC(pVariant != NULL); // Create a recursive variant V_VT(pVariant) = VT_VARIANT; V_VT(pvVar) = VT_VARIANT; V_VARIANTREF(pVariant) = pvVar; V_VARIANTREF(pvVar) = pVariant; // Over-ride the row count expected, we MUST get 0 rows m_pCHelper->SetRowCount(EXACT_VALUE, 0); // Get the rowset TESTC_(m_pCHelper->GetRowsetHelper(), E_INVALIDARG); // Clear the bogus restriction m_pCHelper->ClearRestrictions(); } fResult = TRUE; CLEANUP: // VariantClear(pVariant); Don't need to clear the variant as it's owned by the helper class m_pCHelper->SetRowCount(MIN_VALUE, 1); m_pCHelper->SetRestrictionArray(RT_SUPPORTED); return fResult;} // }} TCW_VAR_PROTOTYPE_END // {{ TCW_VAR_PROTOTYPE(46) //*----------------------------------------------------------------------- // @mfunc Security: Use unclosed quote in restriction // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_46() { BOOL fResult = FALSE; ULONG iRestrict; VARIANT * pVariant = NULL; ULONG cchRestrictionMax = 0; BSTR bstrMaxRestriction = NULL; LPWSTR pwszMaxRestriction = NULL; HRESULT hr = E_NOINTERFACE; if (!m_pCHelper->IsSupported()) { odtLog << L"Schema not supported.\n"; return TEST_SKIPPED; } // Use custom restrictions m_pCHelper->SetRestrictionArray(RT_CUSTOM); // Clear all m_pCHelper->ClearRestrictions(); // for all possible restrictions for (iRestrict = 1; iRestrict <= m_pCHelper->RestrictionCount(); iRestrict++) { // If this restriction isn't supported then don't test it if (!m_pCHelper->IsSupportedRestriction(iRestrict)) continue; // Get the max length for this restriction cchRestrictionMax = m_pCHelper->GetRestrictionMaxLength(iRestrict); // If the length is CCHMAXLENGTH_UNKNOWN, then the restriction does not have a max length OR // the max length is unknown if (cchRestrictionMax == CCHMAXLENGTH_UNKNOWN) continue; // Set restriction to a valid value m_pCHelper->SetValidRestriction(iRestrict); pVariant = m_pCHelper->GetRestrictPtr(iRestrict); TESTC(pVariant != NULL); // We don't care about non-BSTR restrictions if (V_VT(pVariant) != VT_BSTR) continue; // Create a restriction value of the appropriate size bstrMaxRestriction = SysAllocStringLen(NULL, cchRestrictionMax+1); TESTC(bstrMaxRestriction != NULL); memset(bstrMaxRestriction, 1, cchRestrictionMax*sizeof(WCHAR)); bstrMaxRestriction[cchRestrictionMax] = L'\0'; // Put an unclosed quote in the string restriction wcsncpy(bstrMaxRestriction, L"'", wcslen(L"'")); VariantClear(pVariant); V_VT(pVariant) = VT_BSTR; V_BSTR(pVariant) = bstrMaxRestriction; bstrMaxRestriction = NULL; // Because the Variant now owns the BSTR. // Over-ride the row count expected, we MUST get 0 rows m_pCHelper->SetRowCount(EXACT_VALUE, 0); // Get the rowset. May be empty rowset or a provider specific error hr = m_pCHelper->GetRowsetHelper(); TEST2C_(hr, S_OK, E_FAIL); // Clear the bogus restriction m_pCHelper->ClearRestrictions(); } fResult = TRUE; CLEANUP: // VariantClear(pVariant); Don't need to clear the variant as it's owned by the helper class m_pCHelper->SetRowCount(MIN_VALUE, 1); m_pCHelper->SetRestrictionArray(RT_SUPPORTED); return fResult; } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_VAR_PROTOTYPE(47) //*----------------------------------------------------------------------- // @mfunc Synonyms: Use table synonym in table restriction // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_47() { // No synonym support yet return TEST_SKIPPED; } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_VAR_PROTOTYPE(48) //*----------------------------------------------------------------------- // @mfunc Synonyms: Use SYNONYM in table type restriction // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_48() { // No synonym support yet return TEST_SKIPPED; } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_VAR_PROTOTYPE(49) //*----------------------------------------------------------------------- // @mfunc Synonyms: Use synonym for table name restriction and SYNONYM in table type restriction. // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_49() { // No synonym support yet return TEST_SKIPPED; } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_VAR_PROTOTYPE(50) //*----------------------------------------------------------------------- // @mfunc Security: SQLBU #363546: Use max size string restriction of closing square brackets // This testing is needed because we internally escape the closing ] and if we don't properly // keep track it will overflow buffers. // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_50() { odtLog << L"This variation only supported against SQLNCLI.\n"; return TEST_SKIPPED; } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_VAR_PROTOTYPE(51) //*----------------------------------------------------------------------- // @mfunc Security: SQLBU #363546: Use extremely large string restriction of closing square brackets // This testing is needed because we internally escape the closing ] and if we don't properly // keep track it will overflow buffers. // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_51() { odtLog << L"This variation only supported against SQLNCLI.\n"; return TEST_SKIPPED; } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_VAR_PROTOTYPE(52) //*----------------------------------------------------------------------- // @mfunc SQLBU #395368: Use a sortid that does not have a SQL collation // // @rdesc TEST_PASS or TEST_FAIL // int CCommon::Variation_52() { return TEST_SKIPPED; } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_TERMINATE_METHOD //-------------------------------------------------------------------- // @mfunc TestCase Termination Routine // // @rdesc TRUE or FALSE // BOOL CCommon::Terminate() { // {{ TCW_TERM_BASECLASS_CHECK2 SAFE_DELETE(m_pCHelper); return(CSchemaTest::Terminate()); } // }} // }} // }} // {{ TCW_TC_PROTOTYPE(CGetSchema) //*----------------------------------------------------------------------- //| Test Case: CGetSchema - test IDBSchemaRowset::GetSchemas //| Created: 09/23/96 //*----------------------------------------------------------------------- //-------------------------------------------------------------------- // @mfunc TestCase Initialization Routine // // @rdesc TRUE or FALSE // BOOL CGetSchema::Init() { // DON'T need restrictions in order to test schema m_fDontCaptureRestrictions = TRUE; // {{ TCW_INIT_BASECLASS_CHECK if(CSchemaTest::Init()) // }} { return TRUE; } return FALSE; } // {{ TCW_VAR_PROTOTYPE(1) //*----------------------------------------------------------------------- // @mfunc E_INVALIDARG: pcSchemas = NULL // // @rdesc TEST_PASS or TEST_FAIL // int CGetSchema::Variation_1() { INIT GUID * rgSchemas=NULL; ULONG cSchemas=0; ULONG * rgRestrictionSupport=NULL; // test method if(CHECK(m_HR = m_pIDBSchemaRowset->GetSchemas(NULL,&rgSchemas,&rgRestrictionSupport),E_INVALIDARG)) m_fResult = TEST_PASS; if((!COMPARE(rgRestrictionSupport,NULL)) || (!COMPARE(rgSchemas,NULL))) m_fResult = TEST_FAIL; FREE return m_fResult; } // }} // {{ TCW_VAR_PROTOTYPE(2) //*----------------------------------------------------------------------- // @mfunc S_OK: *prgSchemas = NULL, pcSchemas = 0 // // @rdesc TEST_PASS or TEST_FAIL // int CGetSchema::Variation_2() { INIT GUID * rgSchemas=NULL; ULONG cSchemas=0; ULONG * rgRestrictionSupport=NULL; // test method if(CHECK(m_HR = m_pIDBSchemaRowset->GetSchemas(&cSchemas,&rgSchemas,&rgRestrictionSupport),S_OK)) m_fResult = TEST_PASS; // Free the memory PROVIDER_FREE(rgSchemas); PROVIDER_FREE(rgRestrictionSupport); // free the array FREE return m_fResult; } // }} // {{ TCW_VAR_PROTOTYPE(3) //*----------------------------------------------------------------------- // @mfunc S_OK: prgRestrictionSupported = NULL // // @rdesc TEST_PASS or TEST_FAIL // int CGetSchema::Variation_3() { INIT GUID * rgSchemas=NULL; ULONG cSchemas=0; ULONG * rgRestrictionSupport=NULL; m_fResult = TEST_FAIL; // test method if (m_ulOLEDBVer >= VER_25) { TESTC_(m_HR = m_pIDBSchemaRowset->GetSchemas(&cSchemas,&rgSchemas,NULL),S_OK); // If we got S_OK then the following must be true TESTC(cSchemas > 0); TESTC(rgSchemas != NULL); } else { // Older providers return E_INVALIDARG TESTC_(m_HR = m_pIDBSchemaRowset->GetSchemas(&cSchemas,&rgSchemas,NULL),E_INVALIDARG); TESTC(cSchemas == 0); TESTC(rgSchemas == NULL); } m_fResult = TEST_PASS; CLEANUP: SAFE_FREE(rgSchemas); // free the array FREE return m_fResult; } // }} // {{ TCW_VAR_PROTOTYPE(4) //*----------------------------------------------------------------------- // @mfunc E_INVALIDARG: prgSchemas = NULL // // @rdesc TEST_PASS or TEST_FAIL // int CGetSchema::Variation_4() { INIT GUID * rgSchemas=NULL; ULONG cSchemas=0; ULONG * rgRestrictionSupport=NULL; // test method if(CHECK(m_HR = m_pIDBSchemaRowset->GetSchemas(&cSchemas,NULL,&rgRestrictionSupport),E_INVALIDARG)) m_fResult = TEST_PASS; if((!COMPARE(cSchemas,0)) || (!COMPARE(rgRestrictionSupport,NULL))) m_fResult = TEST_FAIL; FREE return m_fResult; } // }} // {{ TCW_VAR_PROTOTYPE(5) //*----------------------------------------------------------------------- // @mfunc S_OK: open schema rowset, try to open rowset from command object // // @rdesc TEST_PASS or TEST_FAIL // int CGetSchema::Variation_5() { INIT GUID * rgSchemas=NULL; ULONG cSchemas=0; ULONG * rgRestrictionSupport=NULL; ULONG ulIndex=0; IUnknown * pICommandRowset=NULL; ICommandText * pICommandText=NULL; WCHAR * pSQLText=NULL; IDBCreateCommand * pIDBCreateCommand=NULL; // test method if(CHECK(m_HR = m_pIDBSchemaRowset->GetSchemas(&cSchemas,&rgSchemas,&rgRestrictionSupport),S_OK)) m_fResult = TEST_PASS; if(m_pIDBCreateCommand) { if(!CHECK(m_pIDBCreateCommand->CreateCommand(NULL,IID_ICommandText,(IUnknown**)&pICommandText),S_OK)) return TEST_FAIL; } else { // Check to see if commands are supported if(!VerifyInterface(m_pIOpenRowset, IID_IDBCreateCommand, SESSION_INTERFACE, (IUnknown**)&pIDBCreateCommand)) goto CLEANUP; if(!CHECK(pIDBCreateCommand->CreateCommand(NULL,IID_ICommandText,(IUnknown**)&pICommandText),S_OK)) { m_cErrors++; goto CLEANUP; } } if(!CHECK(m_pTable->CreateSQLStmt(SELECT_ALLFROMTBL,m_pTable->GetTableName(),&pSQLText,NULL,NULL),S_OK)) { m_cErrors++; goto CLEANUP; } if(!CHECK(pICommandText->SetCommandText(DBGUID_DBSQL,pSQLText),S_OK)) { m_cErrors++; goto CLEANUP; } if(!CHECK(pICommandText->Execute(NULL,IID_IUnknown,NULL,NULL,&pICommandRowset),S_OK)) m_cErrors++; if(pICommandRowset) { pICommandRowset->Release(); pICommandRowset=NULL; } CLEANUP: // Free the memory PROVIDER_FREE(rgSchemas); PROVIDER_FREE(rgRestrictionSupport); PROVIDER_FREE(pSQLText); // free the array FREE if(pICommandText) pICommandText->Release(); if(pIDBCreateCommand) pIDBCreateCommand->Release(); if(m_cErrors) return TEST_FAIL; else return TEST_PASS; } // }} // {{ TCW_VAR_PROTOTYPE(6) //*----------------------------------------------------------------------- // @mfunc S_OK: don't initialize variables before sending // // @rdesc TEST_PASS or TEST_FAIL // int CGetSchema::Variation_6() { INIT GUID * rgSchemas; ULONG cSchemas; ULONG * rgRestrictionSupport; // test method if(CHECK(m_HR = m_pIDBSchemaRowset->GetSchemas(&cSchemas,&rgSchemas,&rgRestrictionSupport),S_OK)) m_fResult = TEST_PASS; for(ULONG index=0;indexget_ICommandPTR(); if (!m_pIDBCreateCommand || m_pCTable->get_ICommandPTR() || (m_pIDBCreateCommand && CHECK(m_pIDBCreateCommand->CreateCommand(NULL,IID_ICommand, (IUnknown**)&pICmd),S_OK))) return TRUE; } } // Check to see if ITransaction is supported if(!m_pITransactionLocal) return TEST_SKIPPED; // Clear the bad pointer value if(m_pITransactionLocal == INVALID(ITransactionLocal*)) m_pITransactionLocal = NULL; return FALSE; } //*----------------------------------------------------------------------- // @mfunc TestTxn // Tests commit/abort with respect to IAccessor on commands // // @rdesc TEST_PASS or TEST_FAIL // int CZombie::TestTxnGetRowset ( ETXN eTxn, BOOL fRetaining, GUID schema ) { BOOL fSuccess = FALSE; ULONG index=0; IDBSchemaRowset * pIDBSchemaRowset=NULL; IRowset * pIRowset=NULL; if (!StartTransaction(SELECT_ALLFROMTBL, (IUnknown **)&pIDBSchemaRowset, 0, NULL, NULL, ISOLATIONLEVEL_READUNCOMMITTED)) goto CLEANUP; if (eTxn == ETXN_COMMIT) { //Commit the transaction, with retention as specified if(!GetCommit(fRetaining)) goto CLEANUP; } else { //Abort the transaction, with retention as specified if(!GetAbort(fRetaining)) goto CLEANUP; } //Make sure everything still works after commit or abort fSuccess = CHECK(pIDBSchemaRowset->GetRowset( NULL, schema, 0, NULL, IID_IRowset, 0, NULL, PPI &pIRowset),S_OK); CLEANUP: if(pIDBSchemaRowset) pIDBSchemaRowset->Release(); if(pIRowset) pIRowset->Release(); //Return code of Commit/Abort will vary depending on whether //or not we have an open txn, so adjust accordingly if (fRetaining) CleanUpTransaction(S_OK); else CleanUpTransaction(XACT_E_NOTRANSACTION); if (fSuccess) return TEST_PASS; else return TEST_FAIL; } int CZombie::TestTxnGetSchemas ( ETXN eTxn, BOOL fRetaining ) { BOOL fSuccess = FALSE; ULONG index=0; IDBSchemaRowset * pIDBSchemaRowset=NULL; ULONG cTxnSchemas=0; GUID * rgTxnSchemas=NULL; ULONG * rgTxnRestrictions=NULL; if (!StartTransaction(SELECT_ALLFROMTBL, (IUnknown **)&pIDBSchemaRowset, 0, NULL, NULL, ISOLATIONLEVEL_READUNCOMMITTED)) goto CLEANUP; if (eTxn == ETXN_COMMIT) { //Commit the transaction, with retention as specified if(!GetCommit(fRetaining)) goto CLEANUP; } else { //Abort the transaction, with retention as specified if(!GetAbort(fRetaining)) goto CLEANUP; } //Make sure everything still works after commit or abort fSuccess = CHECK(pIDBSchemaRowset->GetSchemas( &cTxnSchemas,&rgTxnSchemas,&rgTxnRestrictions),S_OK); CLEANUP: // Free the memory PROVIDER_FREE(rgTxnSchemas); PROVIDER_FREE(rgTxnRestrictions); if(pIDBSchemaRowset) pIDBSchemaRowset->Release(); //Return code of Commit/Abort will vary depending on whether //or not we have an open txn, so adjust accordingly if (fRetaining) CleanUpTransaction(S_OK); else CleanUpTransaction(XACT_E_NOTRANSACTION); if (fSuccess) return TEST_PASS; else return TEST_FAIL; } // {{ TCW_VAR_PROTOTYPE(1) //*----------------------------------------------------------------------- // @mfunc GetRowset: Commit with fRetaining set to TRUE // // @rdesc TEST_PASS or TEST_FAIL // int CZombie::Variation_1() { for(ULONG index=0;indexm_ProviderClsid, m_pError); if (!m_pExtError) return FALSE; // {{ TCW_INIT_BASECLASS_CHECK if(CSchemaTest::Init()) // }} { return TRUE; } return FALSE; } CHelper * ExtendedErrors::GetSchemaHelper(GUID guidSchema) { if(IsEqualGUID(DBSCHEMA_ASSERTIONS,guidSchema)) return new CAssertionsHelper(); else if(IsEqualGUID(DBSCHEMA_CATALOGS,guidSchema)) return new CCatalogsHelper(); else if(IsEqualGUID(DBSCHEMA_CHARACTER_SETS,guidSchema)) return new CCharacterSetsHelper(); else if(IsEqualGUID(DBSCHEMA_CHECK_CONSTRAINTS,guidSchema)) return new CCheckConstraintsHelper(); else if(IsEqualGUID(DBSCHEMA_CHECK_CONSTRAINTS_BY_TABLE,guidSchema)) return new CCheckConstraintsByTableHelper(); else if(IsEqualGUID(DBSCHEMA_COLLATIONS,guidSchema)) return new CCollationsHelper(); else if(IsEqualGUID(DBSCHEMA_COLUMN_DOMAIN_USAGE,guidSchema)) return new CColumnDomainUsageHelper(); else if(IsEqualGUID(DBSCHEMA_COLUMN_PRIVILEGES,guidSchema)) return new CColumnPrivilegesHelper(); else if(IsEqualGUID(DBSCHEMA_COLUMNS,guidSchema)) return new CColumnsHelper(); else if(IsEqualGUID(DBSCHEMA_CONSTRAINT_COLUMN_USAGE,guidSchema)) return new CConstraintColumnUsageHelper(); else if(IsEqualGUID(DBSCHEMA_CONSTRAINT_TABLE_USAGE,guidSchema)) return new CConstraintTableUsageHelper(); else if(IsEqualGUID(DBSCHEMA_FOREIGN_KEYS,guidSchema)) return new CForeignKeysHelper(); else if(IsEqualGUID(DBSCHEMA_INDEXES,guidSchema)) return new CIndexesHelper(); else if(IsEqualGUID(DBSCHEMA_KEY_COLUMN_USAGE,guidSchema)) return new CKeyColumnUsageHelper(); else if(IsEqualGUID(DBSCHEMA_PRIMARY_KEYS,guidSchema)) return new CPrimaryKeysHelper(); else if(IsEqualGUID(DBSCHEMA_PROCEDURE_COLUMNS,guidSchema)) return new CProcedureColumnsHelper(); else if(IsEqualGUID(DBSCHEMA_PROCEDURE_PARAMETERS, guidSchema)) return new CProcedureParametersHelper(); else if(IsEqualGUID(DBSCHEMA_PROCEDURES,guidSchema)) return new CProceduresHelper(); else if(IsEqualGUID(DBSCHEMA_PROVIDER_TYPES,guidSchema)) return new CProviderTypesHelper(); else if(IsEqualGUID(DBSCHEMA_REFERENTIAL_CONSTRAINTS,guidSchema)) return new CReferentialConstraintsHelper(); else if(IsEqualGUID(DBSCHEMA_SCHEMATA,guidSchema)) return new CSchemataHelper(); else if(IsEqualGUID(DBSCHEMA_SQL_LANGUAGES,guidSchema)) return NULL; else if(IsEqualGUID(DBSCHEMA_STATISTICS,guidSchema)) return new CStatisticsHelper(); else if(IsEqualGUID(DBSCHEMA_TABLES,guidSchema)) return new CTablesHelper(); else if(IsEqualGUID(DBSCHEMA_TABLES_INFO,guidSchema)) return new CTablesInfoHelper(); else if(IsEqualGUID(DBSCHEMA_TABLE_CONSTRAINTS,guidSchema)) return new CTableConstraintsHelper(); else if(IsEqualGUID(DBSCHEMA_TABLE_PRIVILEGES,guidSchema)) return new CTablePrivilegesHelper(); else if(IsEqualGUID(DBSCHEMA_TABLE_STATISTICS,guidSchema)) return new CTableStatisticsHelper(); else if(IsEqualGUID(DBSCHEMA_TRANSLATIONS,guidSchema)) return NULL; else if(IsEqualGUID(DBSCHEMA_TRUSTEE,guidSchema)) return new CTrusteeHelper(); else if(IsEqualGUID(DBSCHEMA_USAGE_PRIVILEGES,guidSchema)) return NULL; else if(IsEqualGUID(DBSCHEMA_VIEW_COLUMN_USAGE,guidSchema)) return NULL; else if(IsEqualGUID(DBSCHEMA_VIEW_TABLE_USAGE,guidSchema)) return NULL; else if(IsEqualGUID(DBSCHEMA_VIEWS,guidSchema)) return new CViewsHelper(); else return NULL; } // {{ TCW_VAR_PROTOTYPE(1) //*----------------------------------------------------------------------- // @mfunc Valid GetSchemas Call with previous error object existing // // @rdesc TEST_PASS or TEST_FAIL // int ExtendedErrors::Variation_1() { INIT GUID * rgSchemas=NULL; ULONG cSchemas=0; ULONG * rgRestrictionSupport=NULL; //For each method of the interface, first create an error object on //the current thread, try get a success from the IDBSchemaRowset method. //We then check extended errors to verify the right extended error behavior. m_fResult = FALSE; //create an error object m_pExtError->CauseError(); // test method if(CHECK(m_HR = m_pIDBSchemaRowset->GetSchemas(&cSchemas,&rgSchemas,&rgRestrictionSupport),S_OK)) //Do extended check following GetSchemas m_fResult = XCHECK(m_pIDBSchemaRowset, IID_IDBSchemaRowset, m_HR); // Free the memory PROVIDER_FREE(rgSchemas); PROVIDER_FREE(rgRestrictionSupport); FREE if(m_fResult) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(2) //*----------------------------------------------------------------------- // @mfunc Valid GetRowset call with previous error object existing // // @rdesc TEST_PASS or TEST_FAIL // int ExtendedErrors::Variation_2() { BOOL fResult= TRUE; CHelper* pCHelper = NULL; //For each method of the interface, first create an error object on //the current thread, try get a success from the IDBSchemaRowset method. //We then check extended errors to verify the right extended error behavior. // for each valid schema, test method for(ULONG ulIndex=0;ulIndexCauseError(); if(fResult &= CHECK(m_HR=m_pIDBSchemaRowset->GetRowset( m_punkOuter, m_guid, 0, NULL, m_iid, 0, 0, (IUnknown **) &m_pIRowset), S_OK)) { //Do extended check following GetRowset fResult &= XCHECK(m_pIDBSchemaRowset, IID_IDBSchemaRowset, m_HR); // Get the helper object for this schema rowset pCHelper = GetSchemaHelper(m_guid); TESTC(pCHelper != NULL); pCHelper->Init(this); fResult &= pCHelper->CheckResults(m_HR, m_iid, m_pIRowset); SAFE_DELETE(pCHelper); } } FREE } CLEANUP: SAFE_DELETE(pCHelper); if(fResult) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(3) //*----------------------------------------------------------------------- // @mfunc Valid GetSchemas call with previous error object existing // // @rdesc TEST_PASS or TEST_FAIL // int ExtendedErrors::Variation_3() { INIT GUID * rgSchemas=NULL; ULONG cSchemas=0; ULONG * rgRestrictionSupport=NULL; //For each method of the interface, first create an error object on //the current thread, try get a failure from the IDBSchemaRowset method. //We then check extended errors to verify the right extended error behavior. m_fResult = FALSE; //create an error object m_pExtError->CauseError(); // test method if(CHECK(m_HR = m_pIDBSchemaRowset->GetSchemas(NULL,&rgSchemas,&rgRestrictionSupport),E_INVALIDARG)) //Do extended check following GetSchemas m_fResult = XCHECK(m_pIDBSchemaRowset, IID_IDBSchemaRowset, m_HR); if((!COMPARE(rgRestrictionSupport,NULL)) || (!COMPARE(rgSchemas,NULL))) m_fResult &= FALSE; FREE if(m_fResult) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(4) //*----------------------------------------------------------------------- // @mfunc Invalid GetRowset call with previous error object existing // // @rdesc TEST_PASS or TEST_FAIL // int ExtendedErrors::Variation_4() { //first create an error object on the current thread, try get a failure from //the IDBSchemaRowset method. We then check extended errors to verify the //right extended error behavior. INIT m_fResult = FALSE; m_iid = IID_IRowset; m_guid = DBPROPSET_ROWSET; // no restrictions m_fCountRestrictionsNULL = TRUE; m_fRangeRestrictionsNULL = TRUE; // no properties m_fCountPropSetNULL = TRUE; m_fRangePropSetNULL = TRUE; //create an error object m_pExtError->CauseError(); //invalid m_guid if(CHECK(m_HR=m_pIDBSchemaRowset->GetRowset( m_punkOuter, m_guid, 0, NULL, m_iid, 0, 0, (IUnknown **) &m_pIRowset), E_INVALIDARG)) //Do extended check following GetRowset m_fResult = XCHECK(m_pIDBSchemaRowset, IID_IDBSchemaRowset, m_HR); FREE if(m_fResult) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(5) //*----------------------------------------------------------------------- // @mfunc Invalid GetSchemas call with previous error object existing // // @rdesc TEST_PASS or TEST_FAIL // int ExtendedErrors::Variation_5() { INIT GUID * rgSchemas=NULL; ULONG cSchemas=0; ULONG * rgRestrictionSupport=NULL; //For each method of the interface, with no error object on //the current thread, try get a failure from the IDBSchemaRowset method. //We then check extended errors to verify the right extended error behavior. m_fResult = FALSE; // test method if(CHECK(m_HR = m_pIDBSchemaRowset->GetSchemas(&cSchemas,NULL,&rgRestrictionSupport),E_INVALIDARG)) //Do extended check following GetSchemas m_fResult = XCHECK(m_pIDBSchemaRowset, IID_IDBSchemaRowset, m_HR); if((!COMPARE(cSchemas,0)) || (!COMPARE(rgRestrictionSupport,NULL))) m_fResult &= FALSE; FREE if(m_fResult) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(6) //*----------------------------------------------------------------------- // @mfunc Invalid GetRowset call with previous error object existing // // @rdesc TEST_PASS or TEST_FAIL // int ExtendedErrors::Variation_6() { ULONG cErrors=0; //For each method of the interface, with no error object on //the current thread, try get a failure from the IDBSchemaRowset method. //We then check extended errors to verify the right extended error behavior. for(ULONG ulIndex = 0; ulIndex < m_cSchemasSupported; ulIndex++) { INIT m_iid=IID_IDBProperties; m_restrict = ZERO; // don't pass restrictions m_fCountRestrictionsNULL = TRUE; m_fRangeRestrictionsNULL = TRUE; // don't pass restrictions m_fCountRestrictionsNULL = TRUE; m_fRangeRestrictionsNULL = TRUE; // if this is a schema I want then get information for schema if(GetSchemaInfo(SUPPORTED,ulIndex)) { PRVTRACE(L"Before call\n"); //invalid m_iid CHECK(m_HR=m_pIDBSchemaRowset->GetRowset( m_punkOuter, m_guid, 0, 0, m_iid, 0, 0, (IUnknown **) &m_pIRowset), E_NOINTERFACE); //Do extended check following GetRowset PRVTRACE(L"After call\n"); m_fResult = XCHECK(m_pIDBSchemaRowset, IID_IDBSchemaRowset, m_HR); if(!m_fResult) cErrors++; } // free rowset FREE } if(cErrors) return TEST_FAIL; else return TEST_PASS; } // }} // {{ TCW_VAR_PROTOTYPE(7) //*----------------------------------------------------------------------- // @mfunc Open schema rowset DBSCHEMA_ASSERTIONS -- E_INVALIDARG // // @rdesc TEST_PASS or TEST_FAIL // int ExtendedErrors::Variation_7() { INIT m_fResult = FALSE; m_iid = IID_IRowset; //create an error object m_pExtError->CauseError(); //invalid m_guid if(CHECK(m_HR=m_pIDBSchemaRowset->GetRowset( NULL, DBSCHEMA_ASSERTIONS, 0, NULL, m_iid, 0, 0, (IUnknown **) &m_pIRowset), E_INVALIDARG)) //Do extended check following GetRowset m_fResult = XCHECK(m_pIDBSchemaRowset, IID_IDBSchemaRowset, m_HR); FREE if(m_fResult) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_TERMINATE_METHOD //-------------------------------------------------------------------- // @mfunc TestCase Termination Routine // // @rdesc TRUE or FALSE // BOOL ExtendedErrors::Terminate() { //free error object if (m_pExtError) delete m_pExtError; m_pExtError = NULL; // {{ TCW_TERM_BASECLASS_CHECK2 return(CSchemaTest::Terminate()); } // }} // }} // }} // {{ TCW_TC_PROTOTYPE(CBugRegressions) //*----------------------------------------------------------------------- //| Test Case: CBugRegressions - Test case for bug regressions //| Created: 7/2/99 //*----------------------------------------------------------------------- //*----------------------------------------------------------------------- // @mfunc TestCase Initialization Routine // // @rdesc TRUE or FALSE // BOOL CBugRegressions::Init() { // {{ TCW_INIT_BASECLASS_CHECK if(CSchemaTest::Init()) // }} { // TO DO: Add your own code here return TRUE; } return FALSE; } // {{ TCW_VAR_PROTOTYPE(1) //*----------------------------------------------------------------------- // @mfunc GetRowset on schema TABLES after executing RETURN statement // // @rdesc TEST_PASS or TEST_FAIL // int CBugRegressions::Variation_1() { // To repro this bug we must execute a statement that just contains "RETURN". // We can just hard-code this since it's specific to this bug. LPWSTR pwszReturn = L"RETURN"; IRowset * pIRowset = NULL; BOOL fResult = TEST_FAIL; // Must have commands if(!(m_pTable->get_ICommandPTR())) return TEST_SKIPPED; // Execute the RETURN statement. This may not be supported, so don't check return // code. m_pTable->BuildCommand(pwszReturn, // SQL STMT IID_IRowset, EXECUTE_ALWAYS, 0, NULL, NULL, NULL, (IUnknown **)&pIRowset); // Shouldn't return a rowset TESTC(pIRowset == NULL); // Now execute a valid statement TESTC_(m_pTable->ExecuteCommand(SELECT_VALIDATIONORDER, IID_IRowset, NULL, NULL, NULL, NULL, EXECUTE_IFNOERROR, 0, NULL, NULL, (IUnknown**)&pIRowset), S_OK); TESTC(pIRowset != NULL); // Now get schema tables with table name restriction TESTC(TestSchemaRestrictions(DBSCHEMA_TABLES, THIRD, EXACT_VALUE, 0)); fResult = TEST_PASS; CLEANUP: SAFE_RELEASE(pIRowset); return fResult; } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_TERMINATE_METHOD //*----------------------------------------------------------------------- // @mfunc TestCase Termination Routine // // @rdesc TEST_PASS or TEST_FAIL // BOOL CBugRegressions::Terminate() { // TO DO: Add your own code here // {{ TCW_TERM_BASECLASS_CHECK2 return(CSchemaTest::Terminate()); } // }} // }} TCW_TERMINATE_METHOD_END // }} TCW_TC_PROTOTYPE_END // {{ TCW_TC_PROTOTYPE(CTableStatistics) //*----------------------------------------------------------------------- //| Test Case: CTableStatistics - Test DBSCHEMA_TABLE_STATISTICS //| Created: 11/8/1999 //*----------------------------------------------------------------------- //*----------------------------------------------------------------------- // @mfunc TestCase Initialization Routine // // @rdesc TRUE or FALSE // BOOL CTableStatistics::Init() { // {{ TCW_INIT_BASECLASS_CHECK if(CSchemaTest::Init()) // }} { return TRUE; } return FALSE; } // {{ TCW_VAR_PROTOTYPE(1) //*----------------------------------------------------------------------- // @mfunc Validate DBPROP_OPENROWSETSUPPORT, DBPROPVAL_ORS_HISTOGRAM // // @rdesc TEST_PASS or TEST_FAIL // int CTableStatistics::Variation_1() { BOOL fTableStats = FALSE; BOOL fOpenRowset = FALSE; HRESULT hrExp = S_OK; ULONG_PTR ulTableStatistics = 0; ULONG_PTR ulOpenRowsetSupport = 0; BOOL fResult = TEST_FAIL; fTableStats = GetProperty(g_propTableStatistics, DBPROPSET_DATASOURCEINFO, m_pIDBInitialize, &ulTableStatistics); // If we support the schema we should be able to get DBPROP_TABLESTATISTICS // otherwise we could get an error. if (!IsSchemaSupported(DBSCHEMA_TABLE_STATISTICS)) { // GetProperty may fail if prop isn't supported. if(fTableStats) { // If the prop is supported it must return no // histogram support TESTC(ulTableStatistics == 0); } } else { TESTC(fTableStats); // Make sure no other bits are set TESTC((ulTableStatistics & ~(DBPROPVAL_TS_CARDINALITY | DBPROPVAL_TS_HISTOGRAM)) == 0); } // We should be able to get DBPROP_OPENROWSETSUPPORT fOpenRowset = GetProperty(DBPROP_OPENROWSETSUPPORT, DBPROPSET_DATASOURCEINFO, m_pIDBInitialize, &ulOpenRowsetSupport); // If the provider supports TABLESTATISTICS prop and DBPROPVAL_TS_HISTOGRAM we will // require the provider to support DBPROP_OPENROWSETSUPPORT and // DBPROPVAL_ORS_HISTOGRAM per spec if (fTableStats && (ulTableStatistics & DBPROPVAL_TS_HISTOGRAM)) TESTC(fOpenRowset && (ulOpenRowsetSupport & DBPROPVAL_ORS_HISTOGRAM)); // If the provider supports OPENROWSETSUPPORT prop and DBPROP_ORS_HISTOGRAM // we will require DBPROP_TABLESTATISTICS and DBPROPVAL_TS_HISTOGRAM. if (fOpenRowset && (ulOpenRowsetSupport & DBPROPVAL_ORS_HISTOGRAM)) TESTC(fTableStats && (ulTableStatistics & DBPROPVAL_TS_HISTOGRAM)); // And if the provider does support both props the histogram bit should agree. if (fOpenRowset && fTableStats) { TESTC(!(ulTableStatistics & DBPROPVAL_TS_HISTOGRAM) == !(ulOpenRowsetSupport & DBPROPVAL_ORS_HISTOGRAM)); } fResult = TEST_PASS; CLEANUP: return fResult; } // }} TCW_VAR_PROTOTYPE_END // {{ TCW_TERMINATE_METHOD //*----------------------------------------------------------------------- // @mfunc TestCase Termination Routine // // @rdesc TEST_PASS or TEST_FAIL // BOOL CTableStatistics::Terminate() { // {{ TCW_TERM_BASECLASS_CHECK2 return(CSchemaTest::Terminate()); } // }} // }} TCW_TERMINATE_METHOD_END // }} TCW_TC_PROTOTYPE_END