[PATCH 0/6] MR9891: msado15: Add IRowset wrapper and _Recordset::Seek implementation.
From: Piotr Caban <piotr@codeweavers.com> --- dlls/msado15/tests/msado15.c | 79 ++++++++++++++++++++++++++++-------- 1 file changed, 61 insertions(+), 18 deletions(-) diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index 03424b9e929..be4e9fd0e2d 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -584,6 +584,7 @@ struct test_rowset BOOL filter_chapter; BOOL exact_scroll; + BOOL locate; int idx; }; @@ -849,7 +850,7 @@ static HRESULT WINAPI column_info_GetColumnInfo(IColumnsInfo *This, DBORDINAL *c { DBCOLUMNINFO *dbcolumn; - CHECK_EXPECT(column_info_GetColumnInfo); + CHECK_EXPECT2(column_info_GetColumnInfo); *columns = 2; *stringsbuffer = CoTaskMemAlloc(sizeof(L"Column1")); @@ -1418,8 +1419,12 @@ static HRESULT WINAPI rowset_QueryInterface(IRowsetExactScroll *iface, REFIID ri { *obj = &rowset->IRowsetExactScroll_iface; } - else if (IsEqualIID(riid, &IID_IRowsetLocate) || - IsEqualIID(riid, &IID_IRowsetScroll) || + else if (IsEqualIID(riid, &IID_IRowsetLocate)) + { + if (!rowset->locate && !rowset->exact_scroll) return E_NOINTERFACE; + *obj = &rowset->IRowsetExactScroll_iface; + } + else if (IsEqualIID(riid, &IID_IRowsetScroll) || IsEqualIID(riid, &IID_IRowsetExactScroll)) { if (!rowset->exact_scroll) return E_NOINTERFACE; @@ -1760,6 +1765,7 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) testrowset.refs = 1; testrowset.IViewChapter_iface.lpVtbl = &view_chapter; testrowset.IViewFilter_iface.lpVtbl = &view_filter; + testrowset.locate = FALSE; testrowset.exact_scroll = exact_scroll; testrowset.idx = 0; testrowset.filter_chapter = FALSE; @@ -3382,11 +3388,11 @@ static ULONG WINAPI open_rowset_Release(IOpenRowset *iface) return 1; } +static struct test_rowset open_rowset_test; static HRESULT WINAPI open_rowset_OpenRowset(IOpenRowset *iface, IUnknown *unk_outer, DBID *table_id, DBID *index_id, REFIID riid, ULONG propsets_count, DBPROPSET propsets[], IUnknown **rowset) { - static struct test_rowset testrowset; DBPROP *prop; int i; @@ -3534,19 +3540,21 @@ static HRESULT WINAPI open_rowset_OpenRowset(IOpenRowset *iface, IUnknown *unk_o winetest_pop_context(); } - testrowset.IRowsetExactScroll_iface.lpVtbl = &rowset_vtbl; - testrowset.IRowsetInfo_iface.lpVtbl = &rowset_info; - testrowset.IColumnsInfo_iface.lpVtbl = &column_info; - testrowset.IRowsetUpdate_iface.lpVtbl = &rowset_update; - testrowset.IAccessor_iface.lpVtbl = &accessor; - testrowset.IRowsetView_iface.lpVtbl = &rowset_view; - testrowset.IChapteredRowset_iface.lpVtbl = &chaptered_rowset; - testrowset.IRowsetCurrentIndex_iface.lpVtbl = &rowset_current_index; - testrowset.refs = 1; - testrowset.IViewChapter_iface.lpVtbl = &view_chapter; - testrowset.IViewFilter_iface.lpVtbl = &view_filter; - - *rowset = (IUnknown *)&testrowset.IRowsetExactScroll_iface; + memset(&open_rowset_test, 0, sizeof(open_rowset_test)); + open_rowset_test.IRowsetExactScroll_iface.lpVtbl = &rowset_vtbl; + open_rowset_test.IRowsetInfo_iface.lpVtbl = &rowset_info; + open_rowset_test.IColumnsInfo_iface.lpVtbl = &column_info; + open_rowset_test.IRowsetUpdate_iface.lpVtbl = &rowset_update; + open_rowset_test.IAccessor_iface.lpVtbl = &accessor; + open_rowset_test.IRowsetView_iface.lpVtbl = &rowset_view; + open_rowset_test.IChapteredRowset_iface.lpVtbl = &chaptered_rowset; + open_rowset_test.IRowsetCurrentIndex_iface.lpVtbl = &rowset_current_index; + open_rowset_test.refs = 1; + open_rowset_test.IViewChapter_iface.lpVtbl = &view_chapter; + open_rowset_test.IViewFilter_iface.lpVtbl = &view_filter; + open_rowset_test.locate = TRUE; + + *rowset = (IUnknown *)&open_rowset_test.IRowsetExactScroll_iface; return S_OK; } @@ -3562,9 +3570,14 @@ static IOpenRowset open_rowset = { &open_rowset_vtbl }; static void test_ADOConnectionConstruction(void) { ADOConnectionConstruction15 *conn_constr; + ADORecordsetConstruction *rec_constr; + IRowsetExactScroll *rowset_es; _Recordset *recordset; + IUnknown *unk, *unk2; VARIANT v, missing; _Connection *conn; + IColumnsInfo *ci; + IRowset *rowset; LONG state; HRESULT hr; @@ -3609,15 +3622,45 @@ static void test_ADOConnectionConstruction(void) SET_EXPECT(open_rowset_QI_IDBCreateCommand); SET_EXPECT(open_rowset_OpenRowset); SET_EXPECT(rowset_info_GetProperties); + SET_EXPECT(column_info_GetColumnInfo); + SET_EXPECT(accessor_CreateAccessor); hr = _Recordset_Open(recordset, v, missing, adOpenKeyset, adLockOptimistic, adCmdUnspecified); ok(hr == S_OK, "got %08lx\n", hr); todo_wine CHECK_CALLED(open_rowset_QI_IDBCreateCommand); CHECK_CALLED(open_rowset_OpenRowset); CHECK_CALLED(rowset_info_GetProperties); + CHECK_CALLED(column_info_GetColumnInfo); + CHECK_CALLED(accessor_CreateAccessor); VariantClear(&v); + hr = _Recordset_QueryInterface(recordset, &IID_ADORecordsetConstruction, (void **)&rec_constr); + ok(hr == S_OK, "got %08lx\n", hr); + hr = ADORecordsetConstruction_get_Rowset(rec_constr, &unk); + ok(hr == S_OK, "got %08lx\n", hr); + ADORecordsetConstruction_Release(rec_constr); + hr = IUnknown_QueryInterface(unk, &IID_IRowset, (void **)&rowset); + ok(hr == S_OK, "got %08lx\n", hr); + + todo_wine ok(rowset != (IRowset *)&open_rowset_test.IRowsetExactScroll_iface, "rowset not wrapped\n"); + hr = IRowset_QueryInterface(rowset, &IID_IRowsetExactScroll, (void **)&rowset_es); + todo_wine ok(hr == S_OK, "got %08lx\n", hr); + if (rowset_es) IRowsetExactScroll_Release(rowset_es); + + hr = IRowset_QueryInterface(rowset, &IID_IColumnsInfo, (void **)&ci); + ok(hr == S_OK, "got %08lx\n", hr); + ok(ci == &open_rowset_test.IColumnsInfo_iface, "modified ColumnsInfo interface exposed\n"); + hr = IColumnsInfo_QueryInterface(ci, &IID_IUnknown, (void **)&unk2); + ok(hr == S_OK, "got %08lx\n", hr); + IColumnsInfo_Release(ci); + todo_wine ok(unk != unk2, "IUnknown interfaces match\n"); + IUnknown_Release(unk2); + IUnknown_Release(unk); + IRowset_Release(rowset); + + SET_EXPECT(accessor_ReleaseAccessor); ok(!_Recordset_Release(recordset), "_Recordset not released\n"); - _Connection_Release(conn); + CHECK_CALLED(accessor_ReleaseAccessor); + ok(!_Connection_Release(conn), "_Connection not released\n"); } START_TEST(msado15) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9891
From: Piotr Caban <piotr@codeweavers.com> --- dlls/msado15/Makefile.in | 1 + dlls/msado15/msado15_private.h | 1 + dlls/msado15/recordset.c | 10 +- dlls/msado15/rowsetex.c | 302 +++++++++++++++++++++++++++++++++ dlls/msado15/tests/msado15.c | 8 +- 5 files changed, 315 insertions(+), 7 deletions(-) create mode 100644 dlls/msado15/rowsetex.c diff --git a/dlls/msado15/Makefile.in b/dlls/msado15/Makefile.in index 1209708e980..fb7ce05d234 100644 --- a/dlls/msado15/Makefile.in +++ b/dlls/msado15/Makefile.in @@ -9,4 +9,5 @@ SOURCES = \ msado15_tlb.idl \ recordset.c \ rowset.c \ + rowsetex.c \ stream.c diff --git a/dlls/msado15/msado15_private.h b/dlls/msado15/msado15_private.h index a15c185adc0..6d4d169671a 100644 --- a/dlls/msado15/msado15_private.h +++ b/dlls/msado15/msado15_private.h @@ -27,6 +27,7 @@ HRESULT Recordset_create( void ** ); HRESULT Stream_create( void ** ); HRESULT create_mem_rowset( int, const DBCOLUMNINFO *, IUnknown ** ); +HRESULT create_rowsetex( IUnknown *, IUnknown ** ); typedef enum tid_t { ADORecordsetConstruction_tid, diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index c760cbabbd2..6f05c1f56d6 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -2684,8 +2684,7 @@ static HRESULT WINAPI recordset_Open( _Recordset *iface, VARIANT source, VARIANT { struct recordset *recordset = impl_from_Recordset( iface ); ADOConnectionConstruction15 *construct; - IUnknown *session; - IUnknown *rowset; + IUnknown *session, *rowset, *rowsetex; HRESULT hr; TRACE( "%p, %s, %s, %d, %d, %ld\n", recordset, debugstr_variant(&source), debugstr_variant(&active_connection), @@ -2777,8 +2776,13 @@ static HRESULT WINAPI recordset_Open( _Recordset *iface, VARIANT source, VARIANT if (FAILED(hr) || !rowset) return hr; - hr = ADORecordsetConstruction_put_Rowset(&recordset->ADORecordsetConstruction_iface, rowset); + hr = create_rowsetex(rowset, &rowsetex); IUnknown_Release(rowset); + if (FAILED(hr)) + return hr; + + hr = ADORecordsetConstruction_put_Rowset(&recordset->ADORecordsetConstruction_iface, rowsetex); + IUnknown_Release(rowsetex); return hr; } diff --git a/dlls/msado15/rowsetex.c b/dlls/msado15/rowsetex.c new file mode 100644 index 00000000000..6cd1c81b7c1 --- /dev/null +++ b/dlls/msado15/rowsetex.c @@ -0,0 +1,302 @@ +/* + * Copyright 2025 Piotr Caban for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS +#include "oledb.h" +#include "msado15_backcompat.h" + +#include "wine/debug.h" + +#include "msado15_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msado15); + +#define NO_INTERFACE ((void*)-1) + +struct rowsetex +{ + IRowsetExactScroll IRowsetExactScroll_iface; + LONG refs; + + IRowset *rowset; + IRowsetLocate *rowset_loc; + IRowsetExactScroll *rowset_es; +}; + +static inline struct rowsetex *impl_from_IRowsetExactScroll(IRowsetExactScroll *iface) +{ + return CONTAINING_RECORD(iface, struct rowsetex, IRowsetExactScroll_iface); +} + +static HRESULT WINAPI rowsetex_QueryInterface(IRowsetExactScroll *iface, REFIID riid, void **obj) +{ + struct rowsetex *rowset = impl_from_IRowsetExactScroll(iface); + + TRACE("%p, %s, %p\n", rowset, debugstr_guid(riid), obj); + + *obj = NULL; + if (IsEqualGUID(&IID_IUnknown, riid) || + IsEqualGUID(&IID_IRowset, riid)) + { + *obj = &rowset->IRowsetExactScroll_iface; + } + else if (IsEqualGUID(&IID_IRowsetLocate, riid) || + IsEqualGUID(&IID_IRowsetScroll, riid) || + IsEqualGUID(&IID_IRowsetExactScroll, riid)) + { + if (!rowset->rowset_loc) return E_NOINTERFACE; + *obj = &rowset->IRowsetExactScroll_iface; + } + + if(*obj) + { + IUnknown_AddRef((IUnknown*)*obj); + return S_OK; + } + + FIXME("(%p)->(%s %p)\n", iface, debugstr_guid(riid), obj); + return IRowset_QueryInterface(rowset->rowset, riid, obj); +} + +static ULONG WINAPI rowsetex_AddRef(IRowsetExactScroll *iface) +{ + struct rowsetex *rowset = impl_from_IRowsetExactScroll(iface); + LONG refs = InterlockedIncrement(&rowset->refs); + + TRACE("%p new refcount %ld\n", rowset, refs); + + return refs; +} + +static ULONG WINAPI rowsetex_Release(IRowsetExactScroll *iface) +{ + struct rowsetex *rowset = impl_from_IRowsetExactScroll(iface); + LONG refs = InterlockedDecrement(&rowset->refs); + + TRACE("%p new refcount %ld\n", rowset, refs); + + if (!refs) + { + TRACE("destroying %p\n", rowset); + if (rowset->rowset) IRowset_Release(rowset->rowset); + if (rowset->rowset_loc) IRowsetLocate_Release(rowset->rowset_loc); + if (rowset->rowset_es && rowset->rowset_es != NO_INTERFACE) + IRowsetExactScroll_Release(rowset->rowset_es); + free(rowset); + } + return refs; +} + +static HRESULT WINAPI rowsetex_AddRefRows(IRowsetExactScroll *iface, DBCOUNTITEM count, + const HROW rows[], DBREFCOUNT ref_counts[], DBROWSTATUS status[]) +{ + struct rowsetex *rowset = impl_from_IRowsetExactScroll(iface); + + TRACE("%p, %Id, %p, %p, %p\n", rowset, count, rows, ref_counts, status); + return IRowset_AddRefRows(rowset->rowset, count, rows, ref_counts, status); +} + +static HRESULT WINAPI rowsetex_GetData(IRowsetExactScroll *iface, HROW row, HACCESSOR hacc, void *data) +{ + struct rowsetex *rowset = impl_from_IRowsetExactScroll(iface); + + TRACE("%p, %Id, %Id, %p\n", rowset, row, hacc, data); + return IRowset_GetData(rowset->rowset, row, hacc, data); +} + +static HRESULT WINAPI rowsetex_GetNextRows(IRowsetExactScroll *iface, HCHAPTER chapter, + DBROWOFFSET offset, DBROWCOUNT count, DBCOUNTITEM *obtained, HROW **rows) +{ + struct rowsetex *rowset = impl_from_IRowsetExactScroll(iface); + + TRACE("%p, %Id, %Id, %Id, %p, %p\n", rowset, chapter, offset, count, obtained, rows); + return IRowset_GetNextRows(rowset->rowset, chapter, offset, count, obtained, rows); +} + +static HRESULT WINAPI rowsetex_ReleaseRows(IRowsetExactScroll *iface, DBCOUNTITEM count, const HROW rows[], + DBROWOPTIONS options[], DBREFCOUNT ref_counts[], DBROWSTATUS status[]) +{ + struct rowsetex *rowset = impl_from_IRowsetExactScroll(iface); + + TRACE("%p, %Id, %p, %p, %p, %p\n", rowset, count, rows, options, ref_counts, status); + return IRowset_ReleaseRows(rowset->rowset, count, rows, options, ref_counts, status); +} + +static HRESULT WINAPI rowsetex_RestartPosition(IRowsetExactScroll *iface, HCHAPTER chapter) +{ + struct rowsetex *rowset = impl_from_IRowsetExactScroll(iface); + + TRACE("%p, %Id\n", rowset, chapter); + return IRowset_RestartPosition(rowset->rowset, chapter); +} + +static HRESULT WINAPI rowsetex_Compare(IRowsetExactScroll *iface, HCHAPTER chapter, DBBKMARK bookmark1_size, + const BYTE *bookmark1, DBBKMARK bookmark2_size, const BYTE *bookmark2, DBCOMPARE *compare) +{ + struct rowsetex *rowset = impl_from_IRowsetExactScroll(iface); + + TRACE("%p, %Id, %Iu, %p, %Iu, %p, %p\n", rowset, chapter, bookmark1_size, + bookmark1, bookmark2_size, bookmark2, compare); + return IRowsetLocate_Compare(rowset->rowset_loc, chapter, bookmark1_size, + bookmark1, bookmark2_size, bookmark2, compare); +} + +static HRESULT WINAPI rowsetex_GetRowsAt(IRowsetExactScroll *iface, HWATCHREGION watchregion, + HCHAPTER chapter, DBBKMARK bookmark_size, const BYTE *bookmark, DBROWOFFSET offset, + DBROWCOUNT count, DBCOUNTITEM *obtained, HROW **rows) +{ + struct rowsetex *rowset = impl_from_IRowsetExactScroll(iface); + + TRACE("%p, %Id, %Id, %Iu, %p, %Id, %Id, %p, %p\n", rowset, watchregion, chapter, + bookmark_size, bookmark, offset, count, obtained, rows); + return IRowsetLocate_GetRowsAt(rowset->rowset_loc, watchregion, chapter, + bookmark_size, bookmark, offset, count, obtained, rows); +} + +static HRESULT WINAPI rowsetex_GetRowsByBookmark(IRowsetExactScroll *iface, HCHAPTER chapter, + DBCOUNTITEM rows_cnt, const DBBKMARK bookmark_size[], const BYTE *bookmark[], + HROW row[], DBROWSTATUS status[]) +{ + struct rowsetex *rowset = impl_from_IRowsetExactScroll(iface); + + TRACE("%p, %Id, %Id, %p, %p, %p, %p\n", rowset, chapter, rows_cnt, + bookmark_size, bookmark, row, status); + return IRowsetLocate_GetRowsByBookmark(rowset->rowset_loc, chapter, rows_cnt, + bookmark_size, bookmark, row, status); +} + +static HRESULT WINAPI rowsetex_Hash(IRowsetExactScroll *iface, HCHAPTER chapter, + DBBKMARK bookmark_cnt, const DBBKMARK bookmark_size[], const BYTE *bookmark[], + DBHASHVALUE hash[], DBROWSTATUS status[]) +{ + struct rowsetex *rowset = impl_from_IRowsetExactScroll(iface); + + TRACE("%p, %Id, %Iu, %p, %p, %p, %p\n", rowset, chapter, bookmark_cnt, + bookmark_size, bookmark, hash, status); + return IRowsetLocate_GetRowsByBookmark(rowset->rowset_loc, chapter, bookmark_cnt, + bookmark_size, bookmark, hash, status); +} + +static BOOL init_rowset_es(struct rowsetex *rowset) +{ + if (!rowset->rowset_es) + { + HRESULT hr = IRowset_QueryInterface(rowset->rowset, + &IID_IRowsetExactScroll, (void**)&rowset->rowset_es); + if (FAILED(hr)) + rowset->rowset_es = NO_INTERFACE; + } + return rowset->rowset_es != NO_INTERFACE; +} + +static HRESULT WINAPI rowsetex_GetApproximatePosition(IRowsetExactScroll *iface, HCHAPTER chapter, + DBBKMARK bookmark_size, const BYTE *bookmark, DBCOUNTITEM *position, DBCOUNTITEM *rows) +{ + struct rowsetex *rowset = impl_from_IRowsetExactScroll(iface); + + TRACE("%p, %Id, %Iu, %p, %p, %p\n", rowset, chapter, bookmark_size, bookmark, position, rows); + + if (init_rowset_es(rowset)) + { + return IRowsetExactScroll_GetApproximatePosition(rowset->rowset_es, + chapter, bookmark_size, bookmark, position, rows); + } + + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI rowsetex_GetRowsAtRatio(IRowsetExactScroll *iface, HWATCHREGION watch_region, HCHAPTER chapter, + DBCOUNTITEM numerator, DBCOUNTITEM denominator, DBROWCOUNT row_cnt, DBCOUNTITEM *obtained, HROW **rows) +{ + struct rowsetex *rowset = impl_from_IRowsetExactScroll(iface); + + TRACE("%p, %Id, %Id, %Iu, %Iu, %Id, %p, %p\n", rowset, watch_region, chapter, + numerator, denominator, row_cnt, obtained, rows); + + if (init_rowset_es(rowset)) + { + return IRowsetExactScroll_GetRowsAtRatio(rowset->rowset_es, watch_region, + chapter, numerator, denominator, row_cnt, obtained, rows); + } + + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI rowsetex_GetExactPosition(IRowsetExactScroll *iface, HCHAPTER chapter, + DBBKMARK bookmark_size, const BYTE *bookmark, DBCOUNTITEM *position, DBCOUNTITEM *rows) +{ + struct rowsetex *rowset = impl_from_IRowsetExactScroll(iface); + + TRACE("%p, %Id, %Iu, %p, %p, %p\n", rowset, chapter, bookmark_size, bookmark, position, rows); + + if (init_rowset_es(rowset)) + { + return IRowsetExactScroll_GetExactPosition(rowset->rowset_es, + chapter, bookmark_size, bookmark, position, rows); + } + + FIXME("\n"); + return E_NOTIMPL; +} + +static const struct IRowsetExactScrollVtbl rowsetex_vtbl = +{ + rowsetex_QueryInterface, + rowsetex_AddRef, + rowsetex_Release, + rowsetex_AddRefRows, + rowsetex_GetData, + rowsetex_GetNextRows, + rowsetex_ReleaseRows, + rowsetex_RestartPosition, + rowsetex_Compare, + rowsetex_GetRowsAt, + rowsetex_GetRowsByBookmark, + rowsetex_Hash, + rowsetex_GetApproximatePosition, + rowsetex_GetRowsAtRatio, + rowsetex_GetExactPosition +}; + +HRESULT create_rowsetex(IUnknown *rowset, IUnknown **ret) +{ + struct rowsetex *rowsetex; + HRESULT hr; + + rowsetex = calloc(1, sizeof(*rowsetex)); + if (!rowsetex) return E_OUTOFMEMORY; + + rowsetex->IRowsetExactScroll_iface.lpVtbl = &rowsetex_vtbl; + rowsetex->refs = 1; + + hr = IUnknown_QueryInterface(rowset, &IID_IRowset, (void **)&rowsetex->rowset); + if (FAILED(hr)) + { + IRowsetExactScroll_Release(&rowsetex->IRowsetExactScroll_iface); + return MAKE_ADO_HRESULT(adErrFeatureNotAvailable); + } + + hr = IUnknown_QueryInterface(rowset, &IID_IRowsetLocate, (void **)&rowsetex->rowset_loc); + if (FAILED(hr)) + rowsetex->rowset_loc = NULL; + + *ret = (IUnknown *)&rowsetex->IRowsetExactScroll_iface; + return S_OK; +} diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index be4e9fd0e2d..ffd650d90f5 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -3641,10 +3641,10 @@ static void test_ADOConnectionConstruction(void) hr = IUnknown_QueryInterface(unk, &IID_IRowset, (void **)&rowset); ok(hr == S_OK, "got %08lx\n", hr); - todo_wine ok(rowset != (IRowset *)&open_rowset_test.IRowsetExactScroll_iface, "rowset not wrapped\n"); + ok(rowset != (IRowset *)&open_rowset_test.IRowsetExactScroll_iface, "rowset not wrapped\n"); hr = IRowset_QueryInterface(rowset, &IID_IRowsetExactScroll, (void **)&rowset_es); - todo_wine ok(hr == S_OK, "got %08lx\n", hr); - if (rowset_es) IRowsetExactScroll_Release(rowset_es); + ok(hr == S_OK, "got %08lx\n", hr); + IRowsetExactScroll_Release(rowset_es); hr = IRowset_QueryInterface(rowset, &IID_IColumnsInfo, (void **)&ci); ok(hr == S_OK, "got %08lx\n", hr); @@ -3652,7 +3652,7 @@ static void test_ADOConnectionConstruction(void) hr = IColumnsInfo_QueryInterface(ci, &IID_IUnknown, (void **)&unk2); ok(hr == S_OK, "got %08lx\n", hr); IColumnsInfo_Release(ci); - todo_wine ok(unk != unk2, "IUnknown interfaces match\n"); + ok(unk != unk2, "IUnknown interfaces match\n"); IUnknown_Release(unk2); IUnknown_Release(unk); IRowset_Release(rowset); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9891
From: Piotr Caban <piotr@codeweavers.com> --- dlls/msado15/rowsetex.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/msado15/rowsetex.c b/dlls/msado15/rowsetex.c index 6cd1c81b7c1..02b3ce5332e 100644 --- a/dlls/msado15/rowsetex.c +++ b/dlls/msado15/rowsetex.c @@ -62,6 +62,12 @@ static HRESULT WINAPI rowsetex_QueryInterface(IRowsetExactScroll *iface, REFIID if (!rowset->rowset_loc) return E_NOINTERFACE; *obj = &rowset->IRowsetExactScroll_iface; } + else if (IsEqualGUID(&IID_IColumnsInfo, riid) || + IsEqualGUID(&IID_IRowsetIndex, riid) || + IsEqualGUID(&IID_IRowsetCurrentIndex, riid)) + { + return IRowset_QueryInterface(rowset->rowset, riid, obj); + } if(*obj) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9891
From: Piotr Caban <piotr@codeweavers.com> --- dlls/msado15/rowsetex.c | 134 +++++++++++++++++++++++++++++++++-- dlls/msado15/tests/msado15.c | 34 ++++++++- 2 files changed, 162 insertions(+), 6 deletions(-) diff --git a/dlls/msado15/rowsetex.c b/dlls/msado15/rowsetex.c index 02b3ce5332e..969d93ba614 100644 --- a/dlls/msado15/rowsetex.c +++ b/dlls/msado15/rowsetex.c @@ -18,6 +18,7 @@ #define COBJMACROS #include "oledb.h" +#include "oledberr.h" #include "msado15_backcompat.h" #include "wine/debug.h" @@ -36,6 +37,10 @@ struct rowsetex IRowset *rowset; IRowsetLocate *rowset_loc; IRowsetExactScroll *rowset_es; + IAccessor *accessor; + + DBTYPE bookmark_type; + HACCESSOR bookmark_hacc; }; static inline struct rowsetex *impl_from_IRowsetExactScroll(IRowsetExactScroll *iface) @@ -103,6 +108,9 @@ static ULONG WINAPI rowsetex_Release(IRowsetExactScroll *iface) if (rowset->rowset_loc) IRowsetLocate_Release(rowset->rowset_loc); if (rowset->rowset_es && rowset->rowset_es != NO_INTERFACE) IRowsetExactScroll_Release(rowset->rowset_es); + if (rowset->bookmark_hacc) + IAccessor_ReleaseAccessor(rowset->accessor, rowset->bookmark_hacc, NULL); + if (rowset->accessor) IAccessor_Release(rowset->accessor); free(rowset); } return refs; @@ -248,7 +256,24 @@ static HRESULT WINAPI rowsetex_GetRowsAtRatio(IRowsetExactScroll *iface, HWATCHR static HRESULT WINAPI rowsetex_GetExactPosition(IRowsetExactScroll *iface, HCHAPTER chapter, DBBKMARK bookmark_size, const BYTE *bookmark, DBCOUNTITEM *position, DBCOUNTITEM *rows) { + struct bookmark_data + { + union + { + int i4; + LONGLONG i8; + BYTE *ptr; + } val; + DBLENGTH len; + DBSTATUS status; + } bookmark_data; + struct rowsetex *rowset = impl_from_IRowsetExactScroll(iface); + DBCOUNTITEM got_rows, n = 0; + HROW hrow[64], *prow = hrow; + BYTE tmp, *bm = &tmp; + DBBKMARK size; + HRESULT hr; TRACE("%p, %Id, %Iu, %p, %p, %p\n", rowset, chapter, bookmark_size, bookmark, position, rows); @@ -258,8 +283,67 @@ static HRESULT WINAPI rowsetex_GetExactPosition(IRowsetExactScroll *iface, HCHAP chapter, bookmark_size, bookmark, position, rows); } - FIXME("\n"); - return E_NOTIMPL; + if (bookmark_size || bookmark || position) return E_INVALIDARG; + if (!rows) return S_OK; + + size = 1; + bm[0] = DBBMK_FIRST; + n = 0; + while (1) + { + hr = IRowsetLocate_GetRowsAt(rowset->rowset_loc, 0, chapter, size, bm, + n ? 1 : 0, ARRAY_SIZE(hrow), &got_rows, &prow); + if (n && rowset->bookmark_type == (DBTYPE_BYREF | DBTYPE_BYTES)) + CoTaskMemFree( bookmark_data.val.ptr ); + if (FAILED(hr)) return hr; + n += got_rows; + + if (hr != DB_S_ENDOFROWSET && got_rows) + { + if (!rowset->bookmark_hacc) + { + DBBINDING binding; + + memset(&binding, 0, sizeof(binding)); + binding.obValue = offsetof(struct bookmark_data, val); + binding.obLength = offsetof(struct bookmark_data, len); + binding.obStatus = offsetof(struct bookmark_data, status); + binding.dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS; + binding.cbMaxLen = rowset->bookmark_type == DBTYPE_I4 ? sizeof(int) : sizeof(void *); + binding.wType = rowset->bookmark_type; + + hr = IAccessor_CreateAccessor(rowset->accessor, DBACCESSOR_ROWDATA, + 1, &binding, 0, &rowset->bookmark_hacc, NULL); + if (FAILED(hr)) return hr; + } + + hr = IRowset_GetData(rowset->rowset, hrow[got_rows - 1], rowset->bookmark_hacc, &bookmark_data); + if (FAILED(hr)) return hr; + + if (rowset->bookmark_type == DBTYPE_I4) + { + size = sizeof(int); + bm = (BYTE *)&bookmark_data.val.i4; + } + else if (rowset->bookmark_type == DBTYPE_I8) + { + size = sizeof(long long); + bm = (BYTE *)&bookmark_data.val.i8; + } + else + { + size = bookmark_data.len; + bm = bookmark_data.val.ptr; + } + } + IRowset_ReleaseRows(rowset->rowset, got_rows, hrow, NULL, NULL, NULL); + if (hr == DB_S_ENDOFROWSET) + { + *rows = n; + return S_OK; + } + if (!got_rows) return E_FAIL; + } } static const struct IRowsetExactScrollVtbl rowsetex_vtbl = @@ -300,8 +384,50 @@ HRESULT create_rowsetex(IUnknown *rowset, IUnknown **ret) } hr = IUnknown_QueryInterface(rowset, &IID_IRowsetLocate, (void **)&rowsetex->rowset_loc); - if (FAILED(hr)) - rowsetex->rowset_loc = NULL; + if (SUCCEEDED(hr)) + { + DBCOLUMNINFO *colinfo = NULL; + OLECHAR *strbuf = NULL; + DBORDINAL i, columns; + IColumnsInfo *info; + + hr = IUnknown_QueryInterface(rowset, &IID_IAccessor, (void **)&rowsetex->accessor); + if (FAILED(hr)) + { + IRowsetExactScroll_Release(&rowsetex->IRowsetExactScroll_iface); + return MAKE_ADO_HRESULT(adErrFeatureNotAvailable); + } + + hr = IUnknown_QueryInterface(rowset, &IID_IColumnsInfo, (void **)&info); + if (FAILED(hr)) + { + IRowsetExactScroll_Release(&rowsetex->IRowsetExactScroll_iface); + return MAKE_ADO_HRESULT(adErrFeatureNotAvailable); + } + + hr = IColumnsInfo_GetColumnInfo(info, &columns, &colinfo, &strbuf); + IColumnsInfo_Release(info); + if (FAILED(hr)) + { + IRowsetExactScroll_Release(&rowsetex->IRowsetExactScroll_iface); + return MAKE_ADO_HRESULT(adErrFeatureNotAvailable); + } + + for (i = 0; i < columns; i++) + { + if (colinfo[i].dwFlags & DBCOLUMNFLAGS_ISBOOKMARK) + { + if (colinfo[i].ulColumnSize == sizeof(int)) + rowsetex->bookmark_type = DBTYPE_I4; + else if (colinfo[i].ulColumnSize == sizeof(INT_PTR)) + rowsetex->bookmark_type = DBTYPE_I8; + else + rowsetex->bookmark_type = DBTYPE_BYREF | DBTYPE_BYTES; + } + } + CoTaskMemFree(strbuf); + CoTaskMemFree(colinfo); + } *ret = (IUnknown *)&rowsetex->IRowsetExactScroll_iface; return S_OK; diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index ffd650d90f5..0574559d3c5 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -1616,7 +1616,7 @@ static HRESULT WINAPI rowset_GetRowsAt(IRowsetExactScroll *iface, HWATCHREGION h ok(!hReserved1, "hReserved1 = %Ix\n", hReserved1); ok((!chapter && !rowset->filter_chapter) || (chapter == 1 && rowset->filter_chapter), "chapter = %Ix (filter %x)\n", chapter, rowset->filter_chapter); - ok(cRows == -1 || cRows == 1, "cRows = %Id\n", cRows); + ok(cRows == -1 || cRows == 1 || cRows == 64, "cRows = %Id\n", cRows); ok(pcRowsObtained != NULL, "pcRowsObtained == NULL\n"); ok(prghRows != NULL, "prghRows == NULL\n"); ok(*prghRows != NULL, "*prghRows == NULL\n"); @@ -3573,11 +3573,13 @@ static void test_ADOConnectionConstruction(void) ADORecordsetConstruction *rec_constr; IRowsetExactScroll *rowset_es; _Recordset *recordset; + DBCOUNTITEM rows, pos; IUnknown *unk, *unk2; VARIANT v, missing; _Connection *conn; IColumnsInfo *ci; IRowset *rowset; + BYTE bookmark; LONG state; HRESULT hr; @@ -3644,7 +3646,6 @@ static void test_ADOConnectionConstruction(void) ok(rowset != (IRowset *)&open_rowset_test.IRowsetExactScroll_iface, "rowset not wrapped\n"); hr = IRowset_QueryInterface(rowset, &IID_IRowsetExactScroll, (void **)&rowset_es); ok(hr == S_OK, "got %08lx\n", hr); - IRowsetExactScroll_Release(rowset_es); hr = IRowset_QueryInterface(rowset, &IID_IColumnsInfo, (void **)&ci); ok(hr == S_OK, "got %08lx\n", hr); @@ -3657,6 +3658,35 @@ static void test_ADOConnectionConstruction(void) IUnknown_Release(unk); IRowset_Release(rowset); + SET_EXPECT(rowset_GetRowsAt); + SET_EXPECT(accessor_CreateAccessor); + SET_EXPECT(rowset_GetData); + SET_EXPECT(rowset_ReleaseRows); + hr = IRowsetExactScroll_GetExactPosition(rowset_es, 0, 0, 0, 0, &rows); + ok(hr == S_OK, "got %08lx\n", hr); + ok(rows == 2, "rows = %Id\n", rows); + CHECK_CALLED(rowset_GetRowsAt); + CHECK_CALLED(accessor_CreateAccessor); + CHECK_CALLED(rowset_GetData); + CHECK_CALLED(rowset_ReleaseRows); + + rows = 0; + SET_EXPECT(rowset_GetRowsAt); + SET_EXPECT(accessor_CreateAccessor); + SET_EXPECT(rowset_GetData); + SET_EXPECT(rowset_ReleaseRows); + hr = IRowsetExactScroll_GetExactPosition(rowset_es, 0, 0, 0, 0, &rows); + ok(hr == S_OK, "got %08lx\n", hr); + ok(rows == 2, "rows = %Id\n", rows); + todo_wine CHECK_NOT_CALLED(rowset_GetRowsAt); + todo_wine CHECK_NOT_CALLED(rowset_GetData); + todo_wine CHECK_NOT_CALLED(rowset_ReleaseRows); + + bookmark = DBBMK_FIRST; + hr = IRowsetExactScroll_GetExactPosition(rowset_es, 0, sizeof(bookmark), &bookmark, &pos, &rows); + ok(hr == E_INVALIDARG, "got %08lx\n", hr); + IRowsetExactScroll_Release(rowset_es); + SET_EXPECT(accessor_ReleaseAccessor); ok(!_Recordset_Release(recordset), "_Recordset not released\n"); CHECK_CALLED(accessor_ReleaseAccessor); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9891
From: Piotr Caban <piotr@codeweavers.com> --- dlls/msado15/recordset.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index 6f05c1f56d6..964bdd1ea6f 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -278,6 +278,7 @@ static HRESULT cache_get( struct recordset *recordset, BOOL forward ) if (recordset->bookmark_hacc) { const BYTE *data; + LONGLONG i8_buf; BYTE byte_buf; DBBKMARK len; int int_buf; @@ -306,6 +307,12 @@ static HRESULT cache_get( struct recordset *recordset, BOOL forward ) len = sizeof(int_buf); } } + else if (V_VT(&recordset->bookmark) == VT_I8) + { + data = (BYTE *)&i8_buf; + i8_buf = V_I8(&recordset->bookmark); + len = sizeof(i8_buf); + } else { hr = SafeArrayLock(V_ARRAY(&recordset->bookmark)); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9891
From: Piotr Caban <piotr@codeweavers.com> --- dlls/msado15/recordset.c | 151 +++++++++++++++++++++++++++++++++-- dlls/msado15/tests/msado15.c | 47 ++++++++++- 2 files changed, 189 insertions(+), 9 deletions(-) diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index 964bdd1ea6f..64884c9fb53 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -116,6 +116,7 @@ struct recordset IRowsetChange *rowset_change; IRowsetUpdate *rowset_update; IAccessor *accessor; + IRowsetIndex *rowset_idx; IRowsetCurrentIndex *rowset_cur_idx; EditModeEnum editmode; HROW current_row; @@ -139,6 +140,8 @@ struct recordset DBTYPE bookmark_type; VARIANT bookmark; + HACCESSOR index_hacc; + ULONG prop_count; DBPROPSET *prop; }; @@ -313,6 +316,11 @@ static HRESULT cache_get( struct recordset *recordset, BOOL forward ) i8_buf = V_I8(&recordset->bookmark); len = sizeof(i8_buf); } + else if (V_VT(&recordset->bookmark) == VT_EMPTY) + { + data = NULL; + len = 0; + } else { hr = SafeArrayLock(V_ARRAY(&recordset->bookmark)); @@ -321,8 +329,15 @@ static HRESULT cache_get( struct recordset *recordset, BOOL forward ) len = V_ARRAY(&recordset->bookmark)->rgsabound[0].cElements; } - hr = IRowsetLocate_GetRowsAt(recordset->rowset_locate, 0, 0, len, data, - off, fetch, &count, &recordset->cache.rows); + if (!data) + { + hr = IRowset_GetNextRows(recordset->row_set, 0, off, fetch, &count, &recordset->cache.rows); + } + else + { + hr = IRowsetLocate_GetRowsAt(recordset->rowset_locate, 0, 0, len, data, + off, fetch, &count, &recordset->cache.rows); + } if (V_VT(&recordset->bookmark) & VT_ARRAY) SafeArrayUnlock(V_ARRAY(&recordset->bookmark)); @@ -1698,6 +1713,9 @@ static void close_recordset( struct recordset *recordset ) if ( recordset->rowset_update && recordset->rowset_update != NO_INTERFACE ) IRowsetUpdate_Release( recordset->rowset_update ); recordset->rowset_update = NULL; + if ( recordset->rowset_idx && recordset->rowset_idx != NO_INTERFACE ) + IRowsetIndex_Release( recordset->rowset_idx ); + recordset->rowset_idx = NULL; if ( recordset->rowset_cur_idx && recordset->rowset_cur_idx != NO_INTERFACE ) IRowsetCurrentIndex_Release( recordset->rowset_cur_idx ); recordset->rowset_cur_idx = NULL; @@ -1720,6 +1738,12 @@ static void close_recordset( struct recordset *recordset ) } recordset->fields.count = -1; + if (recordset->index_hacc) + { + IAccessor_ReleaseAccessor(recordset->accessor, recordset->index_hacc, NULL); + recordset->index_hacc = 0; + } + if (recordset->accessor && recordset->accessor != NO_INTERFACE ) IAccessor_Release( recordset->accessor ); recordset->accessor = NULL; @@ -3325,8 +3349,119 @@ static HRESULT WINAPI recordset_Resync( _Recordset *iface, AffectEnum affect_rec static HRESULT WINAPI recordset_Seek( _Recordset *iface, VARIANT key_values, SeekEnum seek_option ) { - FIXME( "%p, %s, %u\n", iface, debugstr_variant(&key_values), seek_option ); - return E_NOTIMPL; + struct recordset *recordset = impl_from_Recordset( iface ); + DBINDEXCOLUMNDESC *columns; + ULONG i, j, prop_sets_no; + DBPROPSET *prop_sets; + DBORDINAL columns_no; + SAFEARRAY *sa = NULL; + void *data = NULL; + HRESULT hr = S_OK; + DBSEEK dbseek; + + TRACE( "%p, %s, %u\n", iface, debugstr_variant(&key_values), seek_option ); + + if (!recordset->rowset_idx) + { + hr = IRowset_QueryInterface( recordset->row_set, &IID_IRowsetIndex, + (void **)&recordset->rowset_idx ); + if (FAILED(hr) || !recordset->rowset_idx) + recordset->rowset_idx = NO_INTERFACE; + } + if (recordset->rowset_idx == NO_INTERFACE) + return MAKE_ADO_HRESULT( adErrFeatureNotAvailable ); + + if (!recordset->index_hacc) + { + DBBINDING *bindings; + + hr = IRowsetIndex_GetIndexInfo( recordset->rowset_idx, + &columns_no, &columns, &prop_sets_no, &prop_sets ); + if (FAILED(hr)) return hr; + for (i = 0; i < prop_sets_no; i++) + { + for (j = 0; j < prop_sets[i].cProperties; j++) + VariantClear( &prop_sets[i].rgProperties[j].vValue ); + CoTaskMemFree( prop_sets[i].rgProperties ); + } + CoTaskMemFree( prop_sets ); + if (!columns_no) return MAKE_ADO_HRESULT( adErrFeatureNotAvailable ); + + hr = E_OUTOFMEMORY; + bindings = calloc( columns_no, sizeof(*bindings) ); + if (bindings) + { + for (i = 0; i < columns_no; i++) + { + struct field *field; + VARIANT name; + ULONG idx; + + V_VT(&name) = VT_BSTR; + V_BSTR(&name) = columns[i].pColumnID->uName.pwszName; + hr = map_index( &recordset->fields, &name, &idx ); + if (FAILED(hr)) break; + field = recordset->fields.field[idx]; + + bindings[i].iOrdinal = field->ordinal; + bindings[i].obValue = i * sizeof(VARIANT); + bindings[i].dwPart = DBPART_VALUE; + bindings[i].cbMaxLen = sizeof(VARIANT); + bindings[i].wType = DBTYPE_VARIANT; + bindings[i].bPrecision = field->prec; + bindings[i].bScale = field->scale; + } + } + if (SUCCEEDED(hr)) + { + hr = IAccessor_CreateAccessor( recordset->accessor, DBACCESSOR_ROWDATA, + columns_no, bindings, 0, &recordset->index_hacc, NULL ); + } + free( bindings ); + + for (i = 0; i < columns_no; i++) + { + CoTaskMemFree( columns[i].pColumnID->uName.pwszName ); + CoTaskMemFree( columns[i].pColumnID ); + } + CoTaskMemFree( columns ); + if (FAILED(hr)) return hr; + } + + if (V_VT( &key_values ) == (VT_ARRAY | VT_VARIANT)) + { + sa = V_ARRAY( &key_values ); + hr = SafeArrayLock( sa ); + if (SUCCEEDED(hr)) + { + columns_no = sa->rgsabound[0].cElements; + data = sa->pvData; + } + } + else + { + columns_no = 1; + data = &key_values; + } + + dbseek = 0; + if (seek_option & adSeekFirstEQ) dbseek |= DBSEEK_FIRSTEQ; + if (seek_option & adSeekLastEQ) dbseek |= DBSEEK_LASTEQ; + if (seek_option & adSeekAfterEQ) dbseek |= DBSEEK_AFTEREQ; + if (seek_option & adSeekAfter) dbseek |= DBSEEK_AFTER; + if (seek_option & adSeekBeforeEQ) dbseek |= DBSEEK_BEFOREEQ; + if (seek_option & adSeekBefore) dbseek |= DBSEEK_BEFORE; + + if (SUCCEEDED(hr)) + { + hr = IRowsetIndex_Seek( recordset->rowset_idx, recordset->index_hacc, columns_no, data, dbseek ); + if (V_VT( &key_values ) == (VT_ARRAY | VT_VARIANT)) SafeArrayUnlock( sa ); + } + if (FAILED( hr )) return hr; + + VariantClear( &recordset->bookmark ); + recordset->cache.dir = 0; + return cache_get( recordset, TRUE ); } static HRESULT WINAPI recordset_put_Index( _Recordset *iface, BSTR index ) @@ -3356,7 +3491,13 @@ static HRESULT WINAPI recordset_put_Index( _Recordset *iface, BSTR index ) hr = IRowsetCurrentIndex_SetIndex( recordset->rowset_cur_idx, &dbid ); if (FAILED(hr)) return hr; - return _Recordset_MoveFirst( iface ); + hr = _Recordset_MoveFirst( iface ); + if (recordset->index_hacc) + { + IAccessor_ReleaseAccessor( recordset->accessor, recordset->index_hacc, NULL ); + recordset->index_hacc = 0; + } + return hr; } static HRESULT WINAPI recordset_get_Index( _Recordset *iface, BSTR *index ) diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index 0574559d3c5..42b937ec8f5 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -90,6 +90,8 @@ DEFINE_EXPECT(rowset_view_CreateView); DEFINE_EXPECT(view_chapter_OpenViewChapter); DEFINE_EXPECT(view_filter_SetFilter); DEFINE_EXPECT(chaptered_rowset_ReleaseChapter); +DEFINE_EXPECT(rowset_current_index_GetIndexInfo); +DEFINE_EXPECT(rowset_current_index_Seek); DEFINE_EXPECT(rowset_current_index_GetIndex); DEFINE_EXPECT(rowset_current_index_SetIndex); DEFINE_EXPECT(open_rowset_QI_ISessionProperties); @@ -1232,15 +1234,33 @@ static HRESULT WINAPI rowset_current_index_GetIndexInfo(IRowsetCurrentIndex *ifa DBORDINAL *pcKeyColumns, DBINDEXCOLUMNDESC **prgIndexColumnDesc, ULONG *pcIndexPropertySets, DBPROPSET **prgIndexPropertySets) { - ok(0, "unexpected call\n"); - return E_NOTIMPL; + static const WCHAR name[] = L"Column1"; + + CHECK_EXPECT(rowset_current_index_GetIndexInfo); + + *pcKeyColumns = 1; + *prgIndexColumnDesc = CoTaskMemAlloc(sizeof(**prgIndexColumnDesc)); + memset(*prgIndexColumnDesc, 0, sizeof(**prgIndexColumnDesc)); + (*prgIndexColumnDesc)[0].pColumnID = CoTaskMemAlloc(sizeof(*(*prgIndexColumnDesc)[0].pColumnID)); + (*prgIndexColumnDesc)[0].pColumnID->eKind = DBKIND_NAME; + (*prgIndexColumnDesc)[0].pColumnID->uName.pwszName = CoTaskMemAlloc(sizeof(name)); + memcpy((*prgIndexColumnDesc)[0].pColumnID->uName.pwszName, name, sizeof(name)); + *pcIndexPropertySets = 0; + *prgIndexPropertySets = NULL; + return S_OK; } static HRESULT WINAPI rowset_current_index_Seek(IRowsetCurrentIndex *iface, HACCESSOR hAccessor, DBORDINAL cKeyValues, void *pData, DBSEEK dwSeekOptions) { - ok(0, "unexpected call\n"); - return E_NOTIMPL; + VARIANT *v = pData; + + CHECK_EXPECT(rowset_current_index_Seek); + ok(cKeyValues == 1, "cKeyValues = %Iu\n", cKeyValues); + ok(V_VT(v) == VT_I4, "V_VT(pData) = %d\n", V_VT(v)); + ok(V_I4(v) == 0x17, "V_I4(pData) = %ld\n", V_I4(v)); + ok(dwSeekOptions == DBSEEK_FIRSTEQ, "dwSeekOptions = %ld\n", dwSeekOptions); + return S_OK; } static HRESULT WINAPI rowset_current_index_SetRange(IRowsetCurrentIndex *iface, @@ -2024,6 +2044,25 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) } SysFreeString( bstr ); + V_VT(&v) = VT_I4; + V_I4(&v) = 0x17; + SET_EXPECT(rowset_current_index_GetIndexInfo); + SET_EXPECT(accessor_CreateAccessor); + SET_EXPECT(rowset_current_index_Seek); + SET_EXPECT(rowset_AddRefRows); + SET_EXPECT(rowset_ReleaseRows); + SET_EXPECT(rowset_GetNextRows); + if (exact_scroll) SET_EXPECT(rowset_GetData); + hr = _Recordset_Seek( recordset, v, adSeekFirstEQ ); + ok( hr == S_OK, "got %08lx\n", hr ); + CHECK_CALLED(rowset_current_index_GetIndexInfo); + CHECK_CALLED(accessor_CreateAccessor); + CHECK_CALLED(rowset_current_index_Seek); + CHECK_CALLED(rowset_AddRefRows); + CHECK_CALLED(rowset_ReleaseRows); + CHECK_CALLED(rowset_GetNextRows); + if (exact_scroll) CHECK_CALLED(rowset_GetData); + SET_EXPECT( rowset_ReleaseRows ); if (!exact_scroll) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9891
participants (2)
-
Piotr Caban -
Piotr Caban (@piotr)