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