From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/recordset.c | 108 +++++++++++++++++++++++++++++++-------- 1 file changed, 88 insertions(+), 20 deletions(-)
diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index cfd27ae1f73..3b32db18d2f 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -84,9 +84,17 @@ struct recordset IRowsetExactScroll *rowset_es; IRowsetChange *rowset_change; IAccessor *accessor; - EditModeEnum editmode; + EditModeEnum editmode; HROW current_row; - LONG cache_size; + struct + { + LONG max_size; + LONG alloc; + LONG size; + LONG fetched; + LONG pos; + HROW *rows; + } cache; ADO_LONGPTR max_records; VARIANT filter; BOOL use_bookmarks; @@ -106,6 +114,26 @@ static inline struct field *impl_from_Properties( Properties *iface ) return CONTAINING_RECORD( iface, struct field, Properties_iface ); }
+static void cache_release( struct recordset *recordset ) +{ + if (!recordset->cache.fetched) return; + IRowset_ReleaseRows( recordset->row_set, recordset->cache.fetched, + recordset->cache.rows, NULL, NULL, NULL ); + recordset->cache.fetched = 0; + recordset->cache.pos = 0; + recordset->current_row = DB_NULL_HROW; +} + +static void cache_add( struct recordset *recordset, HROW row ) +{ + assert( !recordset->cache.fetched ); + assert( !recordset->cache.pos ); + + recordset->cache.rows[0] = row; + recordset->cache.fetched = 1; + recordset->current_row = row; +} + static ULONG WINAPI field_AddRef( Field *iface ) { struct field *field = impl_from_Field( iface ); @@ -1294,11 +1322,8 @@ static void close_recordset( struct recordset *recordset ) if (recordset->haccessors) IRowset_QueryInterface(recordset->row_set, &IID_IAccessor, (void**)&accessor);
- if ( recordset->current_row ) - { - IRowset_ReleaseRows( recordset->row_set, 1, &recordset->current_row, NULL, NULL, NULL ); - recordset->current_row = 0; - } + cache_release( recordset ); + recordset->current_row = DB_NULL_HROW; if ( recordset->hacc_empty ) { IAccessor_ReleaseAccessor( recordset->accessor, recordset->hacc_empty, NULL ); @@ -1359,6 +1384,7 @@ static ULONG WINAPI recordset_Release( _Recordset *iface ) TRACE( "destroying %p\n", recordset ); close_recordset( recordset ); free( recordset->fields.field ); + free( recordset->cache.rows ); free( recordset ); } return refs; @@ -1582,16 +1608,62 @@ static HRESULT WINAPI recordset_get_CacheSize( _Recordset *iface, LONG *size ) struct recordset *recordset = impl_from_Recordset( iface ); TRACE( "%p, %p\n", iface, size );
- *size = recordset->cache_size; + *size = recordset->cache.size; return S_OK; }
static HRESULT WINAPI recordset_put_CacheSize( _Recordset *iface, LONG size ) { struct recordset *recordset = impl_from_Recordset( iface ); + TRACE( "%p, %ld\n", iface, size );
- recordset->cache_size = size; + if (size < 1) return MAKE_ADO_HRESULT( adErrInvalidArgument ); + + if (!recordset->cache.max_size && recordset->row_set) + { + DBPROPSET *propset = NULL; + IRowsetInfo *info; + HRESULT hr; + + recordset->cache.max_size = LONG_MAX; + + hr = IRowset_QueryInterface( recordset->row_set, &IID_IRowsetInfo, (void **)&info ); + if (SUCCEEDED( hr )) + { + DBPROPIDSET propidset; + DBPROPID id[1]; + ULONG count; + + propidset.rgPropertyIDs = id; + propidset.cPropertyIDs = ARRAY_SIZE(id); + propidset.guidPropertySet = DBPROPSET_ROWSET; + id[0] = DBPROP_MAXOPENROWS; + hr = IRowsetInfo_GetProperties( info, 1, &propidset, &count, &propset ); + IRowsetInfo_Release( info ); + if (FAILED( hr )) propset = NULL; + } + if (propset) + { + if (V_VT(&propset->rgProperties[0].vValue) == VT_I4) + recordset->cache.max_size = V_I4(&propset->rgProperties[0].vValue); + CoTaskMemFree( propset->rgProperties ); + CoTaskMemFree( propset ); + } + } + + if (recordset->cache.max_size && recordset->cache.max_size < size) + return MAKE_ADO_HRESULT( adErrInvalidArgument ); + + if (size > recordset->cache.alloc) + { + HROW *rows = realloc( recordset->cache.rows, sizeof(*rows) * size ); + if (!rows) return E_OUTOFMEMORY; + recordset->cache.alloc = size; + recordset->cache.rows = rows; + } + + recordset->cache.size = size; return S_OK; }
@@ -1735,6 +1807,7 @@ static HRESULT WINAPI recordset_AddNew( _Recordset *iface, VARIANT field_list, V struct recordset *recordset = impl_from_Recordset( iface ); DBREFCOUNT refcount; HRESULT hr; + HROW row;
TRACE( "%p, %s, %s\n", recordset, debugstr_variant(&field_list), debugstr_variant(&values) ); if (V_VT(&field_list) != VT_ERROR) @@ -1772,20 +1845,13 @@ static HRESULT WINAPI recordset_AddNew( _Recordset *iface, VARIANT field_list, V hr = IAccessor_AddRefAccessor( recordset->accessor, recordset->hacc_empty, &refcount ); if (FAILED(hr)) return MAKE_ADO_HRESULT( adErrNoCurrentRecord ); - if (recordset->current_row) - { - hr = IRowset_ReleaseRows( recordset->row_set, 1, &recordset->current_row, NULL, NULL, NULL ); - if (FAILED(hr)) - { - IAccessor_ReleaseAccessor( recordset->accessor, recordset->hacc_empty, &refcount ); - return hr; - } - } + cache_release( recordset ); hr = IRowsetChange_InsertRow( recordset->rowset_change, 0, - recordset->hacc_empty, NULL, &recordset->current_row ); + recordset->hacc_empty, NULL, &row ); IAccessor_ReleaseAccessor( recordset->accessor, recordset->hacc_empty, &refcount ); if (FAILED(hr)) return MAKE_ADO_HRESULT( adErrNoCurrentRecord ); + cache_add( recordset, row );
if (!resize_recordset( recordset, recordset->count + 1 )) return E_OUTOFMEMORY; recordset->index = recordset->count - 1; @@ -3076,7 +3142,9 @@ HRESULT Recordset_create( void **obj ) recordset->cursor_type = adOpenForwardOnly; recordset->row_set = NULL; recordset->editmode = adEditNone; - recordset->cache_size = 1; + recordset->cache.alloc = 1; + recordset->cache.size = 1; + recordset->cache.rows = malloc( sizeof(*recordset->cache.rows) ); recordset->max_records = 0; VariantInit( &recordset->filter ); recordset->columntypes = NULL;
From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/rowset.c | 45 ++++++++++++++++++++++++++++++++++++++++--- include/oledberr.h | 1 + 2 files changed, 43 insertions(+), 3 deletions(-)
diff --git a/dlls/msado15/rowset.c b/dlls/msado15/rowset.c index 79be537d9b9..a4019ef6612 100644 --- a/dlls/msado15/rowset.c +++ b/dlls/msado15/rowset.c @@ -38,6 +38,8 @@ struct rowset DBCOLUMNINFO *columns; OLECHAR *columns_buf;
+ BOOL backward_fetch; + int index; int row_cnt; };
@@ -158,13 +160,50 @@ static HRESULT WINAPI rowset_GetData(IRowsetExactScroll *iface, HROW row, HACCES return E_NOTIMPL; }
-static HRESULT WINAPI rowset_GetNextRows(IRowsetExactScroll *iface, HCHAPTER reserved, +static HRESULT WINAPI rowset_GetNextRows(IRowsetExactScroll *iface, HCHAPTER chapter, DBROWOFFSET offset, DBROWCOUNT count, DBCOUNTITEM *obtained, HROW **rows) { struct rowset *rowset = impl_from_IRowsetExactScroll( iface ); + int i, row_count;
- FIXME("%p, %Id, %Id, %Id, %p, %p\n", rowset, reserved, offset, count, obtained, rows); - return E_NOTIMPL; + TRACE("%p, %Id, %Id, %Id, %p, %p\n", rowset, chapter, offset, count, obtained, rows); + + if (!obtained || !rows) return E_INVALIDARG; + *obtained = 0; + + if (chapter != DB_NULL_HCHAPTER) + { + FIXME("chapter = %Id\n", chapter); + return E_NOTIMPL; + } + + if (rowset->backward_fetch) offset = -offset; + if (rowset->index + offset < 0 || rowset->index + offset > rowset->row_cnt) + return DB_E_BADSTARTPOSITION; + + if (count > 0) row_count = min(rowset->row_cnt - rowset->index - offset, count); + else row_count = min(rowset->index + offset, -count); + + /* don't apply offset if no rows were fetched */ + if (!row_count) return count ? DB_S_ENDOFROWSET : S_OK; + + if (!*rows) + { + *rows = CoTaskMemAlloc(sizeof(**rows) * row_count); + if (!*rows) return E_OUTOFMEMORY; + } + + rowset->index += offset; + for (i = 0; i < row_count; i++) + { + if (count < 0) rowset->index--; + (*rows)[i] = rowset->index + 1; + if (count > 0) rowset->index++; + } + + *obtained = row_count; + rowset->backward_fetch = (count < 0); + return row_count == count || row_count == -count ? S_OK : DB_S_ENDOFROWSET; }
static HRESULT WINAPI rowset_ReleaseRows(IRowsetExactScroll *iface, DBCOUNTITEM count, const HROW rows[], diff --git a/include/oledberr.h b/include/oledberr.h index b3445d50c10..4fd2ad42dcd 100644 --- a/include/oledberr.h +++ b/include/oledberr.h @@ -49,6 +49,7 @@ #define DB_E_NOTFOUND 0x80040e19
#define DB_E_UNSUPPORTEDCONVERSION 0x80040e1d +#define DB_E_BADSTARTPOSITION 0x80040e1e
#define DB_E_ERRORSOCCURRED 0x80040e21
From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/recordset.c | 31 ++------------------------- dlls/msado15/tests/msado15.c | 41 ++++++++++++++++++++---------------- 2 files changed, 25 insertions(+), 47 deletions(-)
diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index 3b32db18d2f..7f115ee2c72 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -97,7 +97,6 @@ struct recordset } cache; ADO_LONGPTR max_records; VARIANT filter; - BOOL use_bookmarks;
DBTYPE *columntypes; HACCESSOR hacc_empty; /* haccessor for adding empty rows */ @@ -1065,8 +1064,8 @@ static HRESULT init_fields( struct fields *fields ) colinfo[i].dwFlags, colinfo[i].ulColumnSize, colinfo[i].wType, colinfo[i].bPrecision, colinfo[i].bScale);
- /* skip bookmark column */ - if (!i && rec->use_bookmarks) continue; + if (!i && colinfo[i].columnid.eKind == DBKIND_GUID_PROPID && + IsEqualGUID(&colinfo[i].columnid.uGuid.guid, &DBCOL_SPECIALCOL)) continue;
hr = append_field(fields, &colinfo[i]); if (FAILED(hr)) @@ -1343,7 +1342,6 @@ static void close_recordset( struct recordset *recordset ) recordset->accessor = NULL;
VariantClear( &recordset->filter ); - recordset->use_bookmarks = FALSE;
col_count = get_column_count( recordset );
@@ -3040,8 +3038,6 @@ static HRESULT WINAPI rsconstruction_get_Rowset(ADORecordsetConstruction *iface, static HRESULT WINAPI rsconstruction_put_Rowset(ADORecordsetConstruction *iface, IUnknown *unk) { struct recordset *recordset = impl_from_ADORecordsetConstruction( iface ); - DBPROPSET *propset = NULL; - IRowsetInfo *info; IRowset *rowset; HRESULT hr;
@@ -3055,29 +3051,6 @@ static HRESULT WINAPI rsconstruction_put_Rowset(ADORecordsetConstruction *iface, if ( recordset->row_set ) IRowset_Release( recordset->row_set ); recordset->row_set = rowset;
- hr = IRowset_QueryInterface( rowset, &IID_IRowsetInfo, (void**)&info ); - if ( SUCCEEDED(hr) && info) - { - DBPROPIDSET propidset; - DBPROPID id[1]; - ULONG count; - - propidset.rgPropertyIDs = id; - propidset.cPropertyIDs = ARRAY_SIZE(id); - propidset.guidPropertySet = DBPROPSET_ROWSET; - id[0] = DBPROP_BOOKMARKS; - hr = IRowsetInfo_GetProperties( info, 1, &propidset, &count, &propset ); - IRowsetInfo_Release( info ); - if ( FAILED(hr) ) propset = NULL; - } - if ( propset ) - { - if (V_VT(&propset->rgProperties[0].vValue) == VT_BOOL && V_BOOL(&propset->rgProperties[0].vValue)) - recordset->use_bookmarks = TRUE; - CoTaskMemFree( propset->rgProperties ); - CoTaskMemFree( propset ); - } - recordset->state = adStateOpen; return S_OK; } diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index 959ffcfe832..9ed016e8c1a 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -18,6 +18,7 @@
#include <stdio.h> #define COBJMACROS +#define DBINITCONSTANTS #include <initguid.h> #include <oledb.h> #include <oledberr.h> @@ -27,8 +28,6 @@ #include "msdasql.h" #include "odbcinst.h"
-DEFINE_GUID(DBPROPSET_ROWSET, 0xc8b522be, 0x5cf3, 0x11ce, 0xad, 0xe5, 0x00, 0xaa, 0x00, 0x44, 0x77, 0x3d); - #define MAKE_ADO_HRESULT( err ) MAKE_HRESULT( SEVERITY_ERROR, FACILITY_CONTROL, err )
static BOOL db_created; @@ -630,25 +629,31 @@ static HRESULT WINAPI column_info_GetColumnInfo(IColumnsInfo *This, DBORDINAL *c
CHECK_EXPECT(column_info_GetColumnInfo);
- *columns = 1; + *columns = 2; *stringsbuffer = CoTaskMemAlloc(sizeof(L"Column1")); lstrcpyW(*stringsbuffer, L"Column1");
- dbcolumn = CoTaskMemAlloc(sizeof(DBCOLUMNINFO)); - - dbcolumn->pwszName = *stringsbuffer; - dbcolumn->pTypeInfo = NULL; - dbcolumn->iOrdinal = 1; - dbcolumn->dwFlags = DBCOLUMNFLAGS_MAYBENULL; - dbcolumn->ulColumnSize = 5; - dbcolumn->wType = DBTYPE_I4; - dbcolumn->bPrecision = 1; - dbcolumn->bScale = 1; - dbcolumn->columnid.eKind = DBKIND_NAME; - dbcolumn->columnid.uName.pwszName = *stringsbuffer; + dbcolumn = CoTaskMemAlloc(sizeof(*dbcolumn) * 2); + memset(dbcolumn, 0, sizeof(*dbcolumn) * 2); + + dbcolumn[0].dwFlags = 0; + dbcolumn[0].ulColumnSize = sizeof(unsigned int); + dbcolumn[0].wType = DBTYPE_UI4; + dbcolumn[0].columnid.eKind = DBKIND_GUID_PROPID; + dbcolumn[0].columnid.uGuid.guid = DBCOL_SPECIALCOL; + + dbcolumn[1].pwszName = *stringsbuffer; + dbcolumn[1].pTypeInfo = NULL; + dbcolumn[1].iOrdinal = 1; + dbcolumn[1].dwFlags = DBCOLUMNFLAGS_MAYBENULL; + dbcolumn[1].ulColumnSize = 5; + dbcolumn[1].wType = DBTYPE_I4; + dbcolumn[1].bPrecision = 1; + dbcolumn[1].bScale = 1; + dbcolumn[1].columnid.eKind = DBKIND_NAME; + dbcolumn[1].columnid.uName.pwszName = *stringsbuffer;
*colinfo = dbcolumn; - return S_OK; }
@@ -1064,10 +1069,10 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) SET_EXPECT( column_info_GetColumnInfo ); hr = ADORecordsetConstruction_put_Rowset( construct, rowset ); CHECK_CALLED( rowset_QI_IRowset ); - CHECK_CALLED( rowset_QI_IRowsetInfo ); + todo_wine CHECK_CALLED( rowset_QI_IRowsetInfo ); todo_wine CHECK_CALLED( rowset_QI_IRowsetExactScroll ); todo_wine CHECK_CALLED( rowset_QI_IDBAsynchStatus ); - CHECK_CALLED( rowset_info_GetProperties ); + todo_wine CHECK_CALLED( rowset_info_GetProperties ); if (exact_scroll) todo_wine CHECK_CALLED( rowset_QI_IColumnsInfo ); else CHECK_NOT_CALLED( rowset_QI_IColumnsInfo ); if (exact_scroll) todo_wine CHECK_CALLED( column_info_GetColumnInfo );
From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/tests/msado15.c | 198 ++++++++++++++++++++++++++++++----- include/dbs.idl | 4 + 2 files changed, 177 insertions(+), 25 deletions(-)
diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index 9ed016e8c1a..f531f12065a 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -73,9 +73,12 @@ DEFINE_EXPECT(rowset_QI_IColumnsInfo); DEFINE_EXPECT(rowset_QI_IRowsetChange); DEFINE_EXPECT(rowset_QI_IDBAsynchStatus); DEFINE_EXPECT(rowset_QI_IAccessor); +DEFINE_EXPECT(rowset_QI_IRowsetUpdate); +DEFINE_EXPECT(rowset_QI_IRowsetFind); DEFINE_EXPECT(rowset_info_GetProperties); DEFINE_EXPECT(column_info_GetColumnInfo); DEFINE_EXPECT(rowset_GetNextRows); +DEFINE_EXPECT(rowset_AddRefRows); DEFINE_EXPECT(rowset_ReleaseRows); DEFINE_EXPECT(rowset_GetRowsAt); DEFINE_EXPECT(rowset_GetExactPosition); @@ -564,20 +567,145 @@ static ULONG WINAPI rowset_info_Release(IRowsetInfo *iface) return IRowsetExactScroll_Release(&rowset->IRowsetExactScroll_iface); }
-static HRESULT WINAPI rowset_info_GetProperties(IRowsetInfo *iface, const ULONG count, - const DBPROPIDSET propertyidsets[], ULONG *out_count, DBPROPSET **propertysets1) +static HRESULT WINAPI rowset_info_GetProperties(IRowsetInfo *iface, const ULONG propidsets_count, + const DBPROPIDSET propidsets[], ULONG *count, DBPROPSET **propsets) { + BOOL prop_fail = FALSE, err = FALSE; + int i, j; + CHECK_EXPECT(rowset_info_GetProperties); - todo_wine ok( count == 2, "got %ld\n", count );
- ok( IsEqualIID(&DBPROPSET_ROWSET, &propertyidsets[0].guidPropertySet), "got %s\n", wine_dbgstr_guid(&propertyidsets[0].guidPropertySet)); - todo_wine ok( propertyidsets[0].cPropertyIDs == 17, "got %ld\n", propertyidsets[0].cPropertyIDs ); - if (count < 2) return E_NOTIMPL; + ok( propidsets_count, "propidsets_count = %ld\n", propidsets_count ); + ok( propidsets != NULL, "propertyidsets = NULL\n" ); + ok( count != NULL, "count = NULL\n" ); + ok( propsets != NULL, "propsets = NULL\n"); + + *count = 0; + *propsets = CoTaskMemAlloc(sizeof(**propsets) * propidsets_count); + for (i = 0; i < propidsets_count; i++) + { + size_t size = sizeof(*(*propsets)[i].rgProperties) * propidsets[i].cPropertyIDs; + DBPROPSTATUS *status; + VARIANT *v;
- ok( IsEqualIID(&DBPROPSET_PROVIDERROWSET, &propertyidsets[1].guidPropertySet), "got %s\n", wine_dbgstr_guid(&propertyidsets[1].guidPropertySet)); - ok( propertyidsets[1].cPropertyIDs == 1, "got %ld\n", propertyidsets[1].cPropertyIDs ); + (*propsets)[i].rgProperties = CoTaskMemAlloc( size ); + memset( (*propsets)[i].rgProperties, 0, size ); + (*propsets)[i].cProperties = propidsets[i].cPropertyIDs; + (*propsets)[i].guidPropertySet = propidsets[i].guidPropertySet;
- return E_NOTIMPL; + for (j = 0; j < propidsets[i].cPropertyIDs; j++) + { + (*propsets)[i].rgProperties[j].dwPropertyID = propidsets[i].rgPropertyIDs[j]; + status = &(*propsets)[i].rgProperties[j].dwStatus; + v = &(*propsets)[i].rgProperties[j].vValue; + + if (IsEqualGUID( &propidsets[i].guidPropertySet, &DBPROPSET_ROWSET )) + { + switch(propidsets[i].rgPropertyIDs[j]) + { + case DBPROP_OTHERUPDATEDELETE: + V_VT(v) = VT_BOOL; + V_BOOL(v) = VARIANT_FALSE; + break; + case DBPROP_OTHERINSERT: + V_VT(v) = VT_BOOL; + V_BOOL(v) = VARIANT_FALSE; + break; + case DBPROP_CANHOLDROWS: + V_VT(v) = VT_BOOL; + V_BOOL(v) = VARIANT_TRUE; + break; + case DBPROP_CANSCROLLBACKWARDS: + V_VT(v) = VT_BOOL; + V_BOOL(v) = VARIANT_TRUE; + break; + case DBPROP_UPDATABILITY: + V_VT(v) = VT_I4; + V_I4(v) = DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_DELETE | DBPROPVAL_UP_INSERT; + break; + case DBPROP_IRowsetLocate: + V_VT(v) = VT_BOOL; + V_BOOL(v) = VARIANT_TRUE; + break; + case DBPROP_IRowsetScroll: + V_VT(v) = VT_BOOL; + V_BOOL(v) = VARIANT_TRUE; + break; + case DBPROP_IRowsetUpdate: + V_VT(v) = VT_BOOL; + V_BOOL(v) = VARIANT_FALSE; + break; + case DBPROP_IRowsetResynch: + V_VT(v) = VT_BOOL; + V_BOOL(v) = VARIANT_FALSE; + break; + case DBPROP_IConnectionPointContainer: + V_VT(v) = VT_BOOL; + V_BOOL(v) = VARIANT_FALSE; + break; + case DBPROP_BOOKMARKSKIPPED: + V_VT(v) = VT_BOOL; + V_BOOL(v) = VARIANT_TRUE; + break; + case DBPROP_IRowsetFind: + V_VT(v) = VT_BOOL; + V_BOOL(v) = VARIANT_FALSE; + break; + case DBPROP_IRowsetRefresh: + V_VT(v) = VT_BOOL; + V_BOOL(v) = VARIANT_FALSE; + break; + case DBPROP_LOCKMODE: + *status = DBPROPSTATUS_NOTSUPPORTED; + prop_fail = TRUE; + break; + case DBPROP_IRowsetIndex: + V_VT(v) = VT_BOOL; + V_BOOL(v) = VARIANT_FALSE; + break; + case DBPROP_IRowsetCurrentIndex: + *status = DBPROPSTATUS_NOTSUPPORTED; + prop_fail = TRUE; + break; + case DBPROP_REMOVEDELETED: + V_VT(v) = VT_BOOL; + V_BOOL(v) = VARIANT_TRUE; + break; + default: + err = TRUE; + break; + } + } + else if (IsEqualGUID( &propidsets[i].guidPropertySet, &DBPROPSET_PROVIDERROWSET )) + { + switch(propidsets[i].rgPropertyIDs[j]) + { + case KAGPROP_CONCURRENCY: + V_VT(v) = VT_I4; + V_I4(v) = KAGPROPVAL_CONCUR_VALUES; + break; + default: + err = TRUE; + break; + } + } + else + { + err = TRUE; + } + + if (err) + { + ok( 0, "unhandled propery %s %lx\n", + wine_dbgstr_guid(&propidsets[i].guidPropertySet), + propidsets[i].rgPropertyIDs[j]); + return E_FAIL; + } + } + } + + *count = propidsets_count; + return prop_fail ? DB_S_ERRORSOCCURRED : S_OK; }
static HRESULT WINAPI rowset_info_GetReferencedRowset(IRowsetInfo *iface, DBORDINAL ordinal, @@ -832,7 +960,7 @@ static HRESULT WINAPI rowset_QueryInterface(IRowsetExactScroll *iface, REFIID ri } else if (IsEqualIID(riid, &IID_IRowsetChange)) { - CHECK_EXPECT(rowset_QI_IRowsetChange); + todo_wine CHECK_EXPECT(rowset_QI_IRowsetChange); *obj = &rowset->IRowsetChange_iface; } else if (IsEqualIID(riid, &IID_IDBAsynchStatus)) @@ -845,6 +973,16 @@ static HRESULT WINAPI rowset_QueryInterface(IRowsetExactScroll *iface, REFIID ri CHECK_EXPECT(rowset_QI_IAccessor); *obj = &rowset->IAccessor_iface; } + else if (IsEqualIID(riid, &IID_IRowsetUpdate)) + { + CHECK_EXPECT(rowset_QI_IRowsetUpdate); + return E_NOINTERFACE; + } + else if (IsEqualIID(riid, &IID_IRowsetFind)) + { + CHECK_EXPECT(rowset_QI_IRowsetFind); + return E_NOINTERFACE; + } else if (IsEqualIID(riid, &UKN_INTERFACE)) { trace("Unknown interface\n"); @@ -876,8 +1014,8 @@ static ULONG WINAPI rowset_Release(IRowsetExactScroll *iface) static HRESULT WINAPI rowset_AddRefRows(IRowsetExactScroll *iface, DBCOUNTITEM cRows, const HROW rghRows[], DBREFCOUNT rgRefCounts[], DBROWSTATUS rgRowStatus[]) { - ok(0, "Unexpected call\n"); - return E_NOTIMPL; + CHECK_EXPECT(rowset_AddRefRows); + return S_OK; }
static HRESULT WINAPI rowset_GetData(IRowsetExactScroll *iface, HROW hRow, HACCESSOR hAccessor, void *pData) @@ -912,7 +1050,7 @@ static HRESULT WINAPI rowset_GetNextRows(IRowsetExactScroll *iface, HCHAPTER hRe static HRESULT WINAPI rowset_ReleaseRows(IRowsetExactScroll *iface, DBCOUNTITEM cRows, const HROW rghRows[], DBROWOPTIONS rgRowOptions[], DBREFCOUNT rgRefCounts[], DBROWSTATUS rgRowStatus[]) { - CHECK_EXPECT(rowset_ReleaseRows); + CHECK_EXPECT2(rowset_ReleaseRows); return S_OK; }
@@ -1062,21 +1200,31 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll)
SET_EXPECT( rowset_QI_IRowset ); SET_EXPECT( rowset_QI_IRowsetInfo ); + SET_EXPECT( rowset_info_GetProperties ); + SET_EXPECT( rowset_QI_IRowsetChange ); + SET_EXPECT( rowset_QI_IRowsetUpdate ); + SET_EXPECT( rowset_QI_IRowsetFind ); SET_EXPECT( rowset_QI_IRowsetExactScroll ); + if (exact_scroll) + { + SET_EXPECT( rowset_QI_IColumnsInfo ); + SET_EXPECT( column_info_GetColumnInfo ); + } SET_EXPECT( rowset_QI_IDBAsynchStatus ); - SET_EXPECT( rowset_QI_IColumnsInfo ); - SET_EXPECT( rowset_info_GetProperties ); - SET_EXPECT( column_info_GetColumnInfo ); hr = ADORecordsetConstruction_put_Rowset( construct, rowset ); CHECK_CALLED( rowset_QI_IRowset ); todo_wine CHECK_CALLED( rowset_QI_IRowsetInfo ); + todo_wine CHECK_CALLED( rowset_info_GetProperties ); + todo_wine CHECK_CALLED( rowset_QI_IRowsetChange ); + todo_wine CHECK_CALLED( rowset_QI_IRowsetUpdate ); + todo_wine CHECK_CALLED( rowset_QI_IRowsetFind ); todo_wine CHECK_CALLED( rowset_QI_IRowsetExactScroll ); + if (exact_scroll) + { + todo_wine CHECK_CALLED( rowset_QI_IColumnsInfo ); + todo_wine CHECK_CALLED( column_info_GetColumnInfo ); + } todo_wine CHECK_CALLED( rowset_QI_IDBAsynchStatus ); - todo_wine CHECK_CALLED( rowset_info_GetProperties ); - if (exact_scroll) todo_wine CHECK_CALLED( rowset_QI_IColumnsInfo ); - else CHECK_NOT_CALLED( rowset_QI_IColumnsInfo ); - if (exact_scroll) todo_wine CHECK_CALLED( column_info_GetColumnInfo ); - else CHECK_NOT_CALLED( column_info_GetColumnInfo ); ok( hr == S_OK, "got %08lx\n", hr );
hr = _Recordset_get_State( recordset, &state ); @@ -1136,13 +1284,15 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) ok( hr == S_OK, "got %08lx\n", hr ); todo_wine ok( !is_eof( recordset ), "at eof\n" );
+ SET_EXPECT( rowset_AddRefRows ); + SET_EXPECT( rowset_ReleaseRows ); if (!exact_scroll) SET_EXPECT( rowset_GetNextRows ); else SET_EXPECT( rowset_GetRowsAt ); - SET_EXPECT( rowset_ReleaseRows ); hr = _Recordset_MoveNext( recordset ); + todo_wine CHECK_CALLED( rowset_AddRefRows ); + todo_wine CHECK_CALLED( rowset_ReleaseRows ); if (!exact_scroll) todo_wine CHECK_CALLED( rowset_GetNextRows ); else todo_wine CHECK_CALLED( rowset_GetRowsAt ); - todo_wine CHECK_CALLED( rowset_ReleaseRows ); todo_wine ok( hr == S_OK, "got %08lx\n", hr ); ok( is_eof( recordset ), "unexpected records\n" );
@@ -1155,7 +1305,6 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll)
V_VT( &missing ) = VT_ERROR; V_ERROR( &missing ) = DISP_E_PARAMNOTFOUND; - SET_EXPECT(rowset_QI_IRowsetChange); SET_EXPECT(rowset_QI_IAccessor); SET_EXPECT(accessor_CreateAccessor); SET_EXPECT(accessor_AddRefAccessor); @@ -1163,7 +1312,6 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) SET_EXPECT(accessor_ReleaseAccessor); hr = _Recordset_AddNew( recordset, missing, missing ); ok( hr == S_OK, "got %08lx\n", hr ); - CHECK_CALLED(rowset_QI_IRowsetChange); CHECK_CALLED(rowset_QI_IAccessor); CHECK_CALLED(accessor_CreateAccessor); CHECK_CALLED(accessor_AddRefAccessor); diff --git a/include/dbs.idl b/include/dbs.idl index 881d256e1c6..0f132fbc629 100644 --- a/include/dbs.idl +++ b/include/dbs.idl @@ -645,6 +645,10 @@ cpp_quote("#define DBPROPVAL_RT_FREETHREAD __MSABI_LONG(0x00000001)") cpp_quote("#define DBPROPVAL_RT_APTMTTHREAD __MSABI_LONG(0x00000002)") cpp_quote("#define DBPROPVAL_RT_SINGLETHREAD __MSABI_LONG(0x00000004)")
+cpp_quote("#define DBPROPVAL_UP_CHANGE __MSABI_LONG(0x00000001)") +cpp_quote("#define DBPROPVAL_UP_DELETE __MSABI_LONG(0x00000002)") +cpp_quote("#define DBPROPVAL_UP_INSERT __MSABI_LONG(0x00000004)") + cpp_quote("#define DBPROPVAL_LM_NONE __MSABI_LONG(0x00000001)") cpp_quote("#define DBPROPVAL_LM_READ __MSABI_LONG(0x00000002)") cpp_quote("#define DBPROPVAL_LM_INTENT __MSABI_LONG(0x00000004)")
From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/tests/msado15.c | 115 +++++++++++++++++++++++++++++------ 1 file changed, 98 insertions(+), 17 deletions(-)
diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index f531f12065a..2901f468b3e 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -82,6 +82,7 @@ DEFINE_EXPECT(rowset_AddRefRows); DEFINE_EXPECT(rowset_ReleaseRows); DEFINE_EXPECT(rowset_GetRowsAt); DEFINE_EXPECT(rowset_GetExactPosition); +DEFINE_EXPECT(rowset_GetData); DEFINE_EXPECT(rowset_change_InsertRow); DEFINE_EXPECT(accessor_AddRefAccessor); DEFINE_EXPECT(accessor_CreateAccessor); @@ -524,6 +525,12 @@ struct test_rowset BOOL exact_scroll; };
+struct haccessor +{ + LONG ref; + DBBINDING binding; +}; + static inline struct test_rowset *impl_from_IRowsetExactScroll( IRowsetExactScroll *iface ) { return CONTAINING_RECORD( iface, struct test_rowset, IRowsetExactScroll_iface ); @@ -764,7 +771,7 @@ static HRESULT WINAPI column_info_GetColumnInfo(IColumnsInfo *This, DBORDINAL *c dbcolumn = CoTaskMemAlloc(sizeof(*dbcolumn) * 2); memset(dbcolumn, 0, sizeof(*dbcolumn) * 2);
- dbcolumn[0].dwFlags = 0; + dbcolumn[0].dwFlags = DBCOLUMNFLAGS_ISBOOKMARK | DBCOLUMNFLAGS_ISFIXEDLENGTH; dbcolumn[0].ulColumnSize = sizeof(unsigned int); dbcolumn[0].wType = DBTYPE_UI4; dbcolumn[0].columnid.eKind = DBKIND_GUID_PROPID; @@ -889,14 +896,25 @@ static HRESULT WINAPI accessor_CreateAccessor(IAccessor *iface, DBACCESSORFLAGS DBCOUNTITEM cBindings, const DBBINDING rgBindings[], DBLENGTH cbRowSize, HACCESSOR *phAccessor, DBBINDSTATUS rgStatus[]) { + struct haccessor *haccessor; + CHECK_EXPECT(accessor_CreateAccessor); ok(dwAccessorFlags == DBACCESSOR_ROWDATA, "dwAccessorFlags = %lx\n", dwAccessorFlags); - ok(cBindings == 0, "cBindings = %Iu\n", cBindings); + ok(!cBindings || cBindings == 1, "cBindings = %Iu\n", cBindings); ok(cbRowSize == 0, "cbRowSize = %Iu\n", cbRowSize); ok(phAccessor != NULL, "pHAccessor = NULL\n"); ok(!rgStatus, "rgStatus != NULL\n");
- *phAccessor = 1; + if (!cBindings) + { + *phAccessor = 1; + return S_OK; + } + + haccessor = malloc(sizeof(*haccessor)); + haccessor->ref = 1; + haccessor->binding = rgBindings[0]; + *phAccessor = (HACCESSOR)haccessor; return S_OK; }
@@ -910,10 +928,19 @@ static HRESULT WINAPI accessor_GetBindings(IAccessor *iface, HACCESSOR hAccessor static HRESULT WINAPI accessor_ReleaseAccessor(IAccessor *iface, HACCESSOR hAccessor, DBREFCOUNT *pcRefCount) { + struct haccessor *haccessor = (struct haccessor *)hAccessor; + CHECK_EXPECT2(accessor_ReleaseAccessor); - ok(hAccessor == 1, "hAccessor = %Id\n", hAccessor);
- if (pcRefCount) *pcRefCount = 1; + if (hAccessor == 1) + { + if (pcRefCount) *pcRefCount = 1; + return S_OK; + } + + haccessor->ref--; + if (pcRefCount) *pcRefCount = haccessor->ref; + if (!haccessor->ref) free(haccessor); return S_OK; }
@@ -1020,8 +1047,27 @@ static HRESULT WINAPI rowset_AddRefRows(IRowsetExactScroll *iface, DBCOUNTITEM c
static HRESULT WINAPI rowset_GetData(IRowsetExactScroll *iface, HROW hRow, HACCESSOR hAccessor, void *pData) { - ok(0, "Unexpected call\n"); - return E_NOTIMPL; + struct haccessor *haccessor = (struct haccessor *)hAccessor; + DBSTATUS status; + DBLENGTH len; + int val; + + CHECK_EXPECT2(rowset_GetData); + + ok(!haccessor->binding.iOrdinal, "iOrdinal = %Id\n", haccessor->binding.iOrdinal); + ok(haccessor->binding.dwPart == (DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS), + "dwPart = %ld\n", haccessor->binding.dwPart); + ok(haccessor->binding.cbMaxLen == sizeof(int), "cbMaxLen = %Id\n", haccessor->binding.cbMaxLen); + ok(haccessor->binding.wType == DBTYPE_I4, "wType = %d\n", haccessor->binding.wType); + + val = hRow; + len = sizeof(int); + status = DBSTATUS_S_OK; + + memcpy((BYTE *)pData + haccessor->binding.obValue, &val, sizeof(val)); + memcpy((BYTE *)pData + haccessor->binding.obLength, &len, sizeof(len)); + memcpy((BYTE *)pData + haccessor->binding.obStatus, &status, sizeof(status)); + return S_OK; }
static HRESULT WINAPI rowset_GetNextRows(IRowsetExactScroll *iface, HCHAPTER hReserved, DBROWOFFSET lRowsOffset, @@ -1071,28 +1117,46 @@ static HRESULT WINAPI rowset_GetRowsAt(IRowsetExactScroll *iface, HWATCHREGION h HCHAPTER hReserved2, DBBKMARK cbBookmark, const BYTE *pBookmark, DBROWOFFSET lRowsOffset, DBROWCOUNT cRows, DBCOUNTITEM *pcRowsObtained, HROW **prghRows) { - static int idx; + int row;
CHECK_EXPECT2(rowset_GetRowsAt); ok(!hReserved1, "hReserved1 = %Ix\n", hReserved1); ok(!hReserved2, "hReserved2 = %Ix\n", hReserved2); - ok(cbBookmark == 1, "cbBookmark = %Id\n", cbBookmark); - ok(lRowsOffset >= 0 && lRowsOffset <= 2, "lRowsOffset = %Id\n", lRowsOffset); ok(cRows == 1, "cRows = %Id\n", cRows); ok(pcRowsObtained != NULL, "pcRowsObtained == NULL\n"); ok(prghRows != NULL, "prghRows == NULL\n"); ok(*prghRows != NULL, "*prghRows == NULL\n");
- if (pBookmark[0] == DBBMK_LAST && idx == 2) + if (cbBookmark == 1 && pBookmark[0] == DBBMK_FIRST) + { + ok(!lRowsOffset, "lRowsOffset = %Id\n", lRowsOffset); + + *pcRowsObtained = 1; + (*prghRows)[0] = 1; + return S_OK; + } + if (cbBookmark == 1) + { + ok(pBookmark[0] == DBBMK_LAST, "pBookmark[0] = %x\n", pBookmark[0]); + ok(lRowsOffset == 2, "lRowsOffset = %Id\n", lRowsOffset); + + *pcRowsObtained = 0; + return DB_E_BADSTARTPOSITION; + } + + ok(cbBookmark == sizeof(int), "cbBookmark = %Id\n", cbBookmark); + ok(lRowsOffset == 1, "lRowsOffset = %Id\n", lRowsOffset); + + row = *(int *)pBookmark + lRowsOffset; + ok(row > 1 && row <= 3, "row = %d\n", row); + if (row == 3) { *pcRowsObtained = 0; return DB_S_ENDOFROWSET; } - if (pBookmark[0] == DBBMK_FIRST) ok(!idx, "idx = %d\n", idx);
*pcRowsObtained = 1; - (*prghRows)[0] = idx + lRowsOffset; - idx += cRows; + (*prghRows)[0] = row; return S_OK; }
@@ -1209,6 +1273,8 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) { SET_EXPECT( rowset_QI_IColumnsInfo ); SET_EXPECT( column_info_GetColumnInfo ); + SET_EXPECT( rowset_QI_IAccessor ); + SET_EXPECT( accessor_CreateAccessor ); } SET_EXPECT( rowset_QI_IDBAsynchStatus ); hr = ADORecordsetConstruction_put_Rowset( construct, rowset ); @@ -1223,6 +1289,8 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) { todo_wine CHECK_CALLED( rowset_QI_IColumnsInfo ); todo_wine CHECK_CALLED( column_info_GetColumnInfo ); + todo_wine CHECK_CALLED( rowset_QI_IAccessor ); + todo_wine CHECK_CALLED( accessor_CreateAccessor ); } todo_wine CHECK_CALLED( rowset_QI_IDBAsynchStatus ); ok( hr == S_OK, "got %08lx\n", hr ); @@ -1275,11 +1343,21 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) ok( size == (exact_scroll ? 3 : -1), "size = %Id\n", size );
if (!exact_scroll) SET_EXPECT( rowset_GetNextRows ); - else SET_EXPECT( rowset_GetRowsAt ); + else + { + SET_EXPECT( rowset_GetRowsAt ); + SET_EXPECT( rowset_GetData ); + SET_EXPECT( rowset_AddRefRows ); + } SET_EXPECT( rowset_ReleaseRows ); hr = _Recordset_MoveNext( recordset ); if (!exact_scroll) todo_wine CHECK_CALLED( rowset_GetNextRows ); - else todo_wine CHECK_CALLED( rowset_GetRowsAt ); + else + { + todo_wine CHECK_CALLED( rowset_GetRowsAt ); + todo_wine CHECK_CALLED( rowset_GetData ); + todo_wine CHECK_CALLED( rowset_AddRefRows ); + } todo_wine CHECK_CALLED( rowset_ReleaseRows ); ok( hr == S_OK, "got %08lx\n", hr ); todo_wine ok( !is_eof( recordset ), "at eof\n" ); @@ -1310,13 +1388,16 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) SET_EXPECT(accessor_AddRefAccessor); SET_EXPECT(rowset_change_InsertRow); SET_EXPECT(accessor_ReleaseAccessor); + if (exact_scroll) SET_EXPECT(rowset_GetData); hr = _Recordset_AddNew( recordset, missing, missing ); ok( hr == S_OK, "got %08lx\n", hr ); - CHECK_CALLED(rowset_QI_IAccessor); + if (!exact_scroll) CHECK_CALLED(rowset_QI_IAccessor); + else todo_wine CHECK_NOT_CALLED(rowset_QI_IAccessor); CHECK_CALLED(accessor_CreateAccessor); CHECK_CALLED(accessor_AddRefAccessor); CHECK_CALLED(rowset_change_InsertRow); CHECK_CALLED(accessor_ReleaseAccessor); + if (exact_scroll) CHECK_EXPECT(rowset_GetData);
Fields_Release(fields); ADORecordsetConstruction_Release(construct);