[PATCH 0/4] MR10742: msado15: Add partial implementation of IRowsetFind::FindNextRow in rowset wrapper.
From: Piotr Caban <piotr@codeweavers.com> --- dlls/msado15/rowsetex.c | 84 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/dlls/msado15/rowsetex.c b/dlls/msado15/rowsetex.c index 969d93ba614..fd9a884678e 100644 --- a/dlls/msado15/rowsetex.c +++ b/dlls/msado15/rowsetex.c @@ -32,6 +32,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msado15); struct rowsetex { IRowsetExactScroll IRowsetExactScroll_iface; + IAccessor IAccessor_iface; LONG refs; IRowset *rowset; @@ -48,6 +49,11 @@ static inline struct rowsetex *impl_from_IRowsetExactScroll(IRowsetExactScroll * return CONTAINING_RECORD(iface, struct rowsetex, IRowsetExactScroll_iface); } +static inline struct rowsetex *impl_from_IAccessor(IAccessor *iface) +{ + return CONTAINING_RECORD(iface, struct rowsetex, IAccessor_iface); +} + static HRESULT WINAPI rowsetex_QueryInterface(IRowsetExactScroll *iface, REFIID riid, void **obj) { struct rowsetex *rowset = impl_from_IRowsetExactScroll(iface); @@ -67,6 +73,16 @@ static HRESULT WINAPI rowsetex_QueryInterface(IRowsetExactScroll *iface, REFIID if (!rowset->rowset_loc) return E_NOINTERFACE; *obj = &rowset->IRowsetExactScroll_iface; } + else if (IsEqualGUID(&IID_IAccessor, riid)) + { + if (!rowset->accessor) + { + HRESULT hr = IRowset_QueryInterface(rowset->rowset, + &IID_IAccessor, (void**)&rowset->accessor); + if (FAILED(hr)) return hr; + } + *obj = &rowset->IAccessor_iface; + } else if (IsEqualGUID(&IID_IColumnsInfo, riid) || IsEqualGUID(&IID_IRowsetIndex, riid) || IsEqualGUID(&IID_IRowsetCurrentIndex, riid)) @@ -365,6 +381,73 @@ static const struct IRowsetExactScrollVtbl rowsetex_vtbl = rowsetex_GetExactPosition }; +static HRESULT WINAPI accessor_QueryInterface(IAccessor *iface, REFIID riid, void **obj) +{ + struct rowsetex *rowset = impl_from_IAccessor(iface); + return IRowsetExactScroll_QueryInterface(&rowset->IRowsetExactScroll_iface, riid, obj); +} + +static ULONG WINAPI accessor_AddRef(IAccessor *iface) +{ + struct rowsetex *rowset = impl_from_IAccessor(iface); + return IRowsetExactScroll_AddRef(&rowset->IRowsetExactScroll_iface); +} + +static ULONG WINAPI accessor_Release(IAccessor *iface) +{ + struct rowsetex *rowset = impl_from_IAccessor(iface); + return IRowsetExactScroll_Release(&rowset->IRowsetExactScroll_iface); +} + +static HRESULT WINAPI accessor_AddRefAccessor(IAccessor *iface, HACCESSOR hacc, DBREFCOUNT *refs) +{ + struct rowsetex *rowset = impl_from_IAccessor(iface); + + TRACE("%p, %Id, %p\n", rowset, hacc, refs); + return IAccessor_AddRefAccessor(rowset->accessor, hacc, refs); +} + +static HRESULT WINAPI accessor_CreateAccessor(IAccessor *iface, DBACCESSORFLAGS flags, + DBCOUNTITEM bindings_no, const DBBINDING bindings[], DBLENGTH row_size, + HACCESSOR *hacc, DBBINDSTATUS status[]) +{ + struct rowsetex *rowset = impl_from_IAccessor(iface); + + /* FIXME: native modifies bindings and wraps returned accessor */ + TRACE("%p, %ld, %Id, %p, %Id, %p, %p\n", rowset, flags, bindings_no, + bindings, row_size, hacc, status); + return IAccessor_CreateAccessor(rowset->accessor, flags, + bindings_no, bindings, row_size, hacc, status); +} + +static HRESULT WINAPI accessor_GetBindings(IAccessor *iface, HACCESSOR hacc, + DBACCESSORFLAGS *flags, DBCOUNTITEM *bindings_no, DBBINDING **bindings) +{ + struct rowsetex *rowset = impl_from_IAccessor(iface); + + TRACE("%p, %Id, %p, %p, %p\n", rowset, hacc, flags, bindings_no, bindings); + return IAccessor_GetBindings(rowset->accessor, hacc, flags, bindings_no, bindings); +} + +static HRESULT WINAPI accessor_ReleaseAccessor(IAccessor *iface, HACCESSOR hacc, DBREFCOUNT *refs) +{ + struct rowsetex *rowset = impl_from_IAccessor(iface); + + TRACE("%p, %Id, %p\n", rowset, hacc, refs); + return IAccessor_ReleaseAccessor(rowset->accessor, hacc, refs); +} + +static const struct IAccessorVtbl accessor_vtbl = +{ + accessor_QueryInterface, + accessor_AddRef, + accessor_Release, + accessor_AddRefAccessor, + accessor_CreateAccessor, + accessor_GetBindings, + accessor_ReleaseAccessor +}; + HRESULT create_rowsetex(IUnknown *rowset, IUnknown **ret) { struct rowsetex *rowsetex; @@ -374,6 +457,7 @@ HRESULT create_rowsetex(IUnknown *rowset, IUnknown **ret) if (!rowsetex) return E_OUTOFMEMORY; rowsetex->IRowsetExactScroll_iface.lpVtbl = &rowsetex_vtbl; + rowsetex->IAccessor_iface.lpVtbl = &accessor_vtbl; rowsetex->refs = 1; hr = IUnknown_QueryInterface(rowset, &IID_IRowset, (void **)&rowsetex->rowset); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10742
From: Piotr Caban <piotr@codeweavers.com> --- dlls/msado15/rowset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/msado15/rowset.c b/dlls/msado15/rowset.c index 937b14bd62d..20f0fd0bbd6 100644 --- a/dlls/msado15/rowset.c +++ b/dlls/msado15/rowset.c @@ -77,7 +77,7 @@ static void dbtype_free(DBTYPE type, void *data) if (p) { dbtype_free(type & ~DBTYPE_BYREF, p); - free(p); + CoTaskMemFree(p); } return; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10742
From: Piotr Caban <piotr@codeweavers.com> --- dlls/msado15/rowsetex.c | 92 ++++++++++++++++++++++++----------------- 1 file changed, 53 insertions(+), 39 deletions(-) diff --git a/dlls/msado15/rowsetex.c b/dlls/msado15/rowsetex.c index fd9a884678e..a8094249807 100644 --- a/dlls/msado15/rowsetex.c +++ b/dlls/msado15/rowsetex.c @@ -269,8 +269,8 @@ static HRESULT WINAPI rowsetex_GetRowsAtRatio(IRowsetExactScroll *iface, HWATCHR return E_NOTIMPL; } -static HRESULT WINAPI rowsetex_GetExactPosition(IRowsetExactScroll *iface, HCHAPTER chapter, - DBBKMARK bookmark_size, const BYTE *bookmark, DBCOUNTITEM *position, DBCOUNTITEM *rows) +static HRESULT get_bookmark(struct rowsetex *rowset, HROW hrow, DBBKMARK *size, + BYTE **bookmark, BYTE buf[sizeof(long long)]) { struct bookmark_data { @@ -283,11 +283,55 @@ static HRESULT WINAPI rowsetex_GetExactPosition(IRowsetExactScroll *iface, HCHAP DBLENGTH len; DBSTATUS status; } bookmark_data; + HRESULT hr; + + 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, rowset->bookmark_hacc, &bookmark_data); + if (FAILED(hr)) return hr; + if (rowset->bookmark_type == DBTYPE_I4) + { + *size = sizeof(int); + memcpy(buf, &bookmark_data.val.i4, *size); + *bookmark = buf; + } + else if (rowset->bookmark_type == DBTYPE_I8) + { + *size = sizeof(long long); + memcpy(buf, &bookmark_data.val.i8, *size); + *bookmark = buf; + } + else + { + *size = bookmark_data.len; + *bookmark = bookmark_data.val.ptr; + } + return S_OK; +} + +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); + BYTE tmp[sizeof(long long)], *bm = tmp; DBCOUNTITEM got_rows, n = 0; HROW hrow[64], *prow = hrow; - BYTE tmp, *bm = &tmp; DBBKMARK size; HRESULT hr; @@ -303,53 +347,23 @@ static HRESULT WINAPI rowsetex_GetExactPosition(IRowsetExactScroll *iface, HCHAP if (!rows) return S_OK; size = 1; - bm[0] = DBBMK_FIRST; + tmp[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 (bm != tmp) CoTaskMemFree(bm); 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 + hr = get_bookmark(rowset, hrow[got_rows - 1], &size, &bm, tmp); + if (FAILED(hr)) { - size = bookmark_data.len; - bm = bookmark_data.val.ptr; + IRowset_ReleaseRows(rowset->rowset, got_rows, hrow, NULL, NULL, NULL); + return hr; } } IRowset_ReleaseRows(rowset->rowset, got_rows, hrow, NULL, NULL, NULL); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10742
From: Piotr Caban <piotr@codeweavers.com> --- dlls/msado15/msado15_private.h | 2 + dlls/msado15/rowset.c | 2 +- dlls/msado15/rowsetex.c | 266 +++++++++++++++++++++++++++++++++ dlls/msado15/tests/msado15.c | 143 +++++++++++++++++- 4 files changed, 407 insertions(+), 6 deletions(-) diff --git a/dlls/msado15/msado15_private.h b/dlls/msado15/msado15_private.h index 6d4d169671a..40120fc2f28 100644 --- a/dlls/msado15/msado15_private.h +++ b/dlls/msado15/msado15_private.h @@ -46,4 +46,6 @@ typedef enum tid_t { HRESULT get_typeinfo(tid_t tid, ITypeInfo **typeinfo); +void dbtype_free( DBTYPE, void *data ); + #endif /* _WINE_MSADO15_PRIVATE_H_ */ diff --git a/dlls/msado15/rowset.c b/dlls/msado15/rowset.c index 20f0fd0bbd6..beb75ae788e 100644 --- a/dlls/msado15/rowset.c +++ b/dlls/msado15/rowset.c @@ -68,7 +68,7 @@ struct accessor DBBINDING bindings[1]; }; -static void dbtype_free(DBTYPE type, void *data) +void dbtype_free(DBTYPE type, void *data) { if (type & DBTYPE_BYREF) { diff --git a/dlls/msado15/rowsetex.c b/dlls/msado15/rowsetex.c index a8094249807..07b2a70e288 100644 --- a/dlls/msado15/rowsetex.c +++ b/dlls/msado15/rowsetex.c @@ -33,12 +33,14 @@ struct rowsetex { IRowsetExactScroll IRowsetExactScroll_iface; IAccessor IAccessor_iface; + IRowsetFind IRowsetFind_iface; LONG refs; IRowset *rowset; IRowsetLocate *rowset_loc; IRowsetExactScroll *rowset_es; IAccessor *accessor; + IRowsetFind *rowset_find; DBTYPE bookmark_type; HACCESSOR bookmark_hacc; @@ -54,6 +56,11 @@ static inline struct rowsetex *impl_from_IAccessor(IAccessor *iface) return CONTAINING_RECORD(iface, struct rowsetex, IAccessor_iface); } +static inline struct rowsetex *impl_from_IRowsetFind(IRowsetFind *iface) +{ + return CONTAINING_RECORD(iface, struct rowsetex, IRowsetFind_iface); +} + static HRESULT WINAPI rowsetex_QueryInterface(IRowsetExactScroll *iface, REFIID riid, void **obj) { struct rowsetex *rowset = impl_from_IRowsetExactScroll(iface); @@ -83,6 +90,10 @@ static HRESULT WINAPI rowsetex_QueryInterface(IRowsetExactScroll *iface, REFIID } *obj = &rowset->IAccessor_iface; } + else if (IsEqualGUID(&IID_IRowsetFind, riid)) + { + *obj = &rowset->IRowsetFind_iface; + } else if (IsEqualGUID(&IID_IColumnsInfo, riid) || IsEqualGUID(&IID_IRowsetIndex, riid) || IsEqualGUID(&IID_IRowsetCurrentIndex, riid)) @@ -127,6 +138,8 @@ static ULONG WINAPI rowsetex_Release(IRowsetExactScroll *iface) if (rowset->bookmark_hacc) IAccessor_ReleaseAccessor(rowset->accessor, rowset->bookmark_hacc, NULL); if (rowset->accessor) IAccessor_Release(rowset->accessor); + if (rowset->rowset_find && rowset->rowset_find != NO_INTERFACE) + IRowsetFind_Release(rowset->rowset_find); free(rowset); } return refs; @@ -462,6 +475,258 @@ static const struct IAccessorVtbl accessor_vtbl = accessor_ReleaseAccessor }; +static HRESULT WINAPI find_QueryInterface(IRowsetFind *iface, REFIID riid, void **obj) +{ + struct rowsetex *rowset = impl_from_IRowsetFind(iface); + return IRowsetExactScroll_QueryInterface(&rowset->IRowsetExactScroll_iface, riid, obj); +} + +static ULONG WINAPI find_AddRef(IRowsetFind *iface) +{ + struct rowsetex *rowset = impl_from_IRowsetFind(iface); + return IRowsetExactScroll_AddRef(&rowset->IRowsetExactScroll_iface); +} + +static ULONG WINAPI find_Release(IRowsetFind *iface) +{ + struct rowsetex *rowset = impl_from_IRowsetFind(iface); + return IRowsetExactScroll_Release(&rowset->IRowsetExactScroll_iface); +} + +static HRESULT int_compare(DBCOMPAREOP compare_op, long long x, long long y) +{ + switch (compare_op) + { + case DBCOMPAREOPS_LT: + return x < y ? S_OK : S_FALSE; + case DBCOMPAREOPS_LE: + return x <= y ? S_OK : S_FALSE; + case DBCOMPAREOPS_EQ: + return x == y ? S_OK : S_FALSE; + case DBCOMPAREOPS_GE: + return x >= y ? S_OK : S_FALSE; + case DBCOMPAREOPS_GT: + return x > y ? S_OK : S_FALSE; + case DBCOMPAREOPS_NE: + return x != y ? S_OK : S_FALSE; + default: + return S_FALSE; + } +} + +static HRESULT WINAPI find_FindNextRow(IRowsetFind *iface, HCHAPTER chapter, HACCESSOR hacc, + void *find_value, DBCOMPAREOP compare_op, DBBKMARK bookmark_size, const BYTE *bookmark, + DBROWOFFSET offset, DBROWCOUNT rows, DBCOUNTITEM *obtained, HROW **hrows) +{ + BYTE tmp[sizeof(long long)], *bm = (BYTE *)bookmark, *data_buf = NULL; + struct rowsetex *rowset = impl_from_IRowsetFind(iface); + DWORD status = DBSTATUS_S_OK; + DBBINDING *bindings = NULL; + DBCOUNTITEM bindings_no; + HROW row, *prow = &row; + DBACCESSORFLAGS flags; + BOOL free_val = FALSE; + DBCOUNTITEM count = 0; + size_t data_size; + VARIANT conv; + HRESULT hr; + + TRACE("%p, %Id, %Id, %p, %ld, %Id, %p, %Id, %Id, %p, %p\n", rowset, chapter, hacc, + find_value, compare_op, bookmark_size, bookmark, offset, rows, obtained, hrows); + + if (!rowset->rowset_find) + { + HRESULT hr = IRowset_QueryInterface(rowset->rowset, + &IID_IRowsetFind, (void**)&rowset->rowset_find); + if (FAILED(hr)) + rowset->rowset_find = NO_INTERFACE; + } + + if (rowset->rowset_find != NO_INTERFACE) + { + return IRowsetFind_FindNextRow(rowset->rowset_find, chapter, hacc, find_value, + compare_op, bookmark_size, bookmark, offset, rows, obtained, hrows); + } + + if (!obtained || !hrows) return E_INVALIDARG; + if (rows != -1 && rows != 1) + { + FIXME("rows = %Id\n", rows); + return E_NOTIMPL; + } + + if (!hacc || !rowset->accessor) + return DB_E_BADACCESSORHANDLE; + /* TODO: Use custom HACCESSOR instead of calling IAccessor::GetBinding. */ + hr = IAccessor_GetBindings(rowset->accessor, hacc, &flags, &bindings_no, &bindings); + if (FAILED(hr)) return hr; + VariantInit(&conv); + if (bindings_no != 1 || !(flags & DBACCESSOR_ROWDATA) || !(bindings->dwPart & DBPART_VALUE)) + { + hr = DB_E_BADACCESSORTYPE; + goto done; + } + + if (bindings->dwPart & DBPART_STATUS) + status = *(DWORD *)((BYTE *)find_value + bindings->obStatus); + if (status != DBSTATUS_S_OK) + { + FIXME("unhandled pattern status: %ld\n", status); + hr = E_NOTIMPL; + goto done; + } + + data_size = bindings->obValue + bindings->cbMaxLen; + if (bindings->dwPart & DBPART_LENGTH && bindings->obLength + sizeof(DBLENGTH) > data_size) + data_size = bindings->obLength + sizeof(DBLENGTH); + if (bindings->dwPart & DBPART_STATUS && bindings->obStatus + sizeof(DWORD) > data_size) + data_size = bindings->obStatus + sizeof(DWORD); + data_buf = malloc(data_size); + if (!data_buf) + { + hr = E_OUTOFMEMORY; + goto done; + } + + /* Non DBBMK_FIRST bookmark is ignored if IRowsetLocate is not implemented */ + if (!rowset->rowset_loc && bookmark_size == 1 && *bookmark == DBBMK_FIRST) + { + hr = IRowset_RestartPosition(rowset->rowset, chapter); + if (FAILED(hr)) goto done; + } + if (!rowset->rowset_loc) bookmark_size = 0; + + while (1) + { + BYTE *x = data_buf + bindings->obValue; + BYTE *y = (BYTE *)find_value + bindings->obValue; + DBTYPE type = bindings->wType; + + if (bookmark_size) + { + hr = IRowsetLocate_GetRowsAt(rowset->rowset_loc, 0, chapter, + bookmark_size, bm, offset, rows, &count, &prow); + if (bm != bookmark && bm != tmp) + { + CoTaskMemFree(bm); + bm = NULL; + } + } + else + { + hr = IRowset_GetNextRows(rowset->rowset, chapter, offset, rows, &count, &prow); + } + if (FAILED(hr)) goto done; + if (!count) break; + offset = bookmark_size ? 1 : 0; + + hr = IRowset_GetData(rowset->rowset, row, hacc, data_buf); + if (FAILED(hr)) goto done; + free_val = TRUE; + if (compare_op == DBCOMPAREOPS_IGNORE) break; + + if (bindings->dwPart & DBPART_STATUS) + status = *(DWORD *)(data_buf + bindings->obStatus); + if (status == DBSTATUS_S_ISNULL) + type = DBTYPE_NULL; + else if (status != DBSTATUS_S_OK) + { + FIXME("unhandled status: %ld\n", status); + hr = E_NOTIMPL; + goto done; + } + + if (bookmark_size) + { + hr = get_bookmark(rowset, row, &bookmark_size, &bm, tmp); + if (FAILED(hr)) goto done; + } + + if (type == DBTYPE_VARIANT) + { + VARIANT *xv = (VARIANT *)x; + VARIANT *yv = (VARIANT *)y; + + type = V_VT(xv); + if (type != V_VT(yv)) + { + if (type != V_VT(&conv)) + { + VariantClear(&conv); + hr = VariantChangeType(&conv, yv, 0, type); + if (FAILED(hr)) goto done; + } + yv = &conv; + } + + x = &V_UI1(xv); + y = &V_UI1(yv); + } + + switch (type) + { + case DBTYPE_I1: + hr = int_compare(compare_op, *(char *)x, *(char *)y); + break; + case DBTYPE_I2: + hr = int_compare(compare_op, *(short *)x, *(short *)y); + break; + case DBTYPE_I4: + hr = int_compare(compare_op, *(int *)x, *(int *)y); + break; + case DBTYPE_I8: + hr = int_compare(compare_op, *(long long*)x, *(long long*)y); + break; + default: + FIXME("unhandled data type: %d\n", type); + hr = E_NOTIMPL; + break; + } + + if (hr != S_FALSE) break; + if (bindings->dwMemOwner == DBMEMOWNER_CLIENTOWNED) + dbtype_free(bindings->wType, data_buf + bindings->obValue); + free_val = FALSE; + IRowset_ReleaseRows(rowset->rowset, count, prow, NULL, NULL, NULL); + count = 0; + } + +done: + if (free_val && bindings->dwMemOwner == DBMEMOWNER_CLIENTOWNED) + dbtype_free(bindings->wType, data_buf + bindings->obValue); + if (bm != bookmark && bm != tmp) CoTaskMemFree(bm); + VariantClear(&conv); + CoTaskMemFree(bindings); + free(data_buf); + + if (SUCCEEDED(hr)) + { + if (count && !*hrows) + { + *hrows = CoTaskMemAlloc(sizeof(**hrows)); + if (*hrows) hr = E_OUTOFMEMORY; + } + if (count && *hrows) + { + IRowset_AddRefRows(rowset->rowset, 1, &row, NULL, NULL); + *hrows[0] = row; + } + } + if (count) IRowset_ReleaseRows(rowset->rowset, count, prow, NULL, NULL, NULL); + if (FAILED(hr)) return hr; + + *obtained = count; + return count ? hr : DB_S_ENDOFROWSET; +} + +static const struct IRowsetFindVtbl find_vtbl = +{ + find_QueryInterface, + find_AddRef, + find_Release, + find_FindNextRow +}; + HRESULT create_rowsetex(IUnknown *rowset, IUnknown **ret) { struct rowsetex *rowsetex; @@ -472,6 +737,7 @@ HRESULT create_rowsetex(IUnknown *rowset, IUnknown **ret) rowsetex->IRowsetExactScroll_iface.lpVtbl = &rowsetex_vtbl; rowsetex->IAccessor_iface.lpVtbl = &accessor_vtbl; + rowsetex->IRowsetFind_iface.lpVtbl = &find_vtbl; rowsetex->refs = 1; hr = IUnknown_QueryInterface(rowset, &IID_IRowset, (void **)&rowsetex->rowset); diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index d6881b70e80..551d18890f6 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -68,6 +68,7 @@ static char mdbpath[MAX_PATH]; expect_ ## func = called_ ## func = FALSE; \ }while(0) +DEFINE_EXPECT(rowset_QI_IConvertType); DEFINE_EXPECT(rowset_QI_IDBAsynchStatus); DEFINE_EXPECT(rowset_info_GetProperties); DEFINE_EXPECT(column_info_GetColumnInfo); @@ -588,6 +589,7 @@ struct test_rowset BOOL exact_scroll; BOOL locate; + BOOL find_test; int idx; }; @@ -1092,8 +1094,18 @@ static HRESULT WINAPI accessor_CreateAccessor(IAccessor *iface, DBACCESSORFLAGS static HRESULT WINAPI accessor_GetBindings(IAccessor *iface, HACCESSOR hAccessor, DBACCESSORFLAGS *pdwAccessorFlags, DBCOUNTITEM *pcBindings, DBBINDING **prgBindings) { - ok(0, "unexpected call\n"); - return E_NOTIMPL; + struct haccessor *accessor = (struct haccessor *)hAccessor; + + todo_wine ok(0, "unexpected call\n"); + + *pdwAccessorFlags = DBACCESSOR_ROWDATA; + *pcBindings = (hAccessor == 1 ? 0 : 1); + if (*pcBindings) + { + *prgBindings = CoTaskMemAlloc(sizeof(accessor->binding)); + (*prgBindings)[0] = accessor->binding; + } + return S_OK; } static HRESULT WINAPI accessor_ReleaseAccessor(IAccessor *iface, @@ -1545,6 +1557,8 @@ static HRESULT WINAPI rowset_QueryInterface(IRowsetExactScroll *iface, REFIID ri } else if (IsEqualIID(riid, &IID_IRowsetFind)) { + if (!rowset->IRowsetFind_iface.lpVtbl) + return E_NOINTERFACE; *obj = &rowset->IRowsetFind_iface; } else if (IsEqualIID(riid, &IID_IRowsetView)) @@ -1560,6 +1574,11 @@ static HRESULT WINAPI rowset_QueryInterface(IRowsetExactScroll *iface, REFIID ri { *obj = &rowset->IRowsetCurrentIndex_iface; } + else if (IsEqualIID(riid, &IID_IConvertType)) + { + CHECK_EXPECT(rowset_QI_IConvertType); + return E_NOINTERFACE; + } else if (IsEqualIID(riid, &UNK_INTERFACE) || IsEqualIID(riid, &UNK2_INTERFACE)) { trace("Unknown interface (%s)\n", wine_dbgstr_guid(riid)); @@ -1597,6 +1616,7 @@ static HRESULT WINAPI rowset_AddRefRows(IRowsetExactScroll *iface, DBCOUNTITEM c static HRESULT WINAPI rowset_GetData(IRowsetExactScroll *iface, HROW hRow, HACCESSOR hAccessor, void *pData) { + struct test_rowset *rowset = impl_from_IRowsetExactScroll( iface ); struct haccessor *haccessor = (struct haccessor *)hAccessor; DBSTATUS status = DBSTATUS_S_OK; DBLENGTH len; @@ -1621,8 +1641,16 @@ static HRESULT WINAPI rowset_GetData(IRowsetExactScroll *iface, HROW hRow, HACCE break; case 1: - ok(haccessor->binding.dwPart == (DBPART_VALUE | DBPART_STATUS), - "dwPart = %ld\n", haccessor->binding.dwPart); + if (!rowset->IRowsetFind_iface.lpVtbl) + { + todo_wine ok(haccessor->binding.dwPart == (DBPART_VALUE | DBPART_STATUS | DBPART_LENGTH), + "dwPart = %ld\n", haccessor->binding.dwPart); + } + else + { + ok(haccessor->binding.dwPart == (DBPART_VALUE | DBPART_STATUS), + "dwPart = %ld\n", haccessor->binding.dwPart); + } ok(haccessor->binding.cbMaxLen == sizeof(VARIANT), "cbMaxLen = %Id\n", haccessor->binding.cbMaxLen); ok(haccessor->binding.wType == DBTYPE_VARIANT, "wType = %d\n", haccessor->binding.wType); @@ -3762,7 +3790,7 @@ static HRESULT WINAPI open_rowset_OpenRowset(IOpenRowset *iface, IUnknown *unk_o 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.IRowsetFind_iface.lpVtbl = &rowset_find; + open_rowset_test.IRowsetFind_iface.lpVtbl = NULL; open_rowset_test.refs = 1; open_rowset_test.IViewChapter_iface.lpVtbl = &view_chapter; open_rowset_test.IViewFilter_iface.lpVtbl = &view_filter; @@ -3786,13 +3814,18 @@ static void test_ADOConnectionConstruction(void) ADOConnectionConstruction15 *conn_constr; ADORecordsetConstruction *rec_constr; IRowsetExactScroll *rowset_es; + HROW hrow, *hrows = &hrow; _Recordset *recordset; DBCOUNTITEM rows, pos; IUnknown *unk, *unk2; + IAccessor *accessor; VARIANT v, missing; _Connection *conn; + IRowsetFind *find; + DBBINDING binding; IColumnsInfo *ci; IRowset *rowset; + HACCESSOR hacc; BYTE bookmark; LONG state; HRESULT hr; @@ -3909,6 +3942,106 @@ static void test_ADOConnectionConstruction(void) ok(hr == E_INVALIDARG, "got %08lx\n", hr); IRowsetExactScroll_Release(rowset_es); + hr = IRowset_QueryInterface(rowset, &IID_IRowsetFind, (void **)&find); + ok(hr == S_OK, "got %08lx\n", hr); + + hr = IRowsetFind_QueryInterface(find, &IID_IAccessor, (void **)&accessor); + ok(hr == S_OK, "got %08lx\n", hr); + memset(&binding, 0, sizeof(binding)); + binding.iOrdinal = 1; + binding.dwPart = DBPART_VALUE; + binding.cbMaxLen = sizeof(VARIANT); + binding.wType = DBTYPE_VARIANT; + SET_EXPECT(rowset_QI_IConvertType); + hr = IAccessor_CreateAccessor(accessor, DBACCESSOR_ROWDATA, 1, &binding, 0, &hacc, NULL); + ok(hr == S_OK, "got %08lx\n", hr); + todo_wine CHECK_CALLED(rowset_QI_IConvertType); + + hr = IRowsetFind_FindNextRow(find, 0, 0, NULL, DBCOMPAREOPS_EQ, 0, NULL, 0, 1, &rows, &hrows); + ok(hr == DB_E_BADACCESSORHANDLE, "got %08lx\n", hr); + + V_VT(&v) = VT_BSTR; + V_BSTR(&v) = SysAllocString(L"1'1"); + SET_EXPECT(rowset_GetNextRows); + SET_EXPECT(rowset_GetData); + SET_EXPECT(rowset_ReleaseRows); + hr = IRowsetFind_FindNextRow(find, 0, hacc, &v, DBCOMPAREOPS_EQ, 0, NULL, 0, 1, &rows, &hrows); + CHECK_CALLED(rowset_GetNextRows); + CHECK_CALLED(rowset_GetData); + CHECK_CALLED(rowset_ReleaseRows); + ok(hr == DISP_E_TYPEMISMATCH, "got %08lx\n", hr); + VariantClear(&v); + + V_VT(&v) = VT_BSTR; + V_BSTR(&v) = SysAllocString(L"1"); + rows = 1; + SET_EXPECT(rowset_GetNextRows); + SET_EXPECT(rowset_GetData); + SET_EXPECT(rowset_ReleaseRows); + hr = IRowsetFind_FindNextRow(find, 0, hacc, &v, DBCOMPAREOPS_EQ, 0, NULL, 0, 1, &rows, &hrows); + CHECK_CALLED(rowset_GetNextRows); + CHECK_CALLED(rowset_GetData); + CHECK_CALLED(rowset_ReleaseRows); + ok(hr == DB_S_ENDOFROWSET, "got %08lx\n", hr); + ok(!rows, "rows = %Id\n", rows); + VariantClear(&v); + + SET_EXPECT(rowset_RestartPosition); + hr = IRowset_RestartPosition(rowset, 0); + CHECK_CALLED(rowset_RestartPosition); + ok(hr == S_OK, "got %08lx\n", hr); + V_VT(&v) = VT_BSTR; + V_BSTR(&v) = SysAllocString(L"123"); + rows = 123; + hrow = 0xdeadbeef; + SET_EXPECT(rowset_GetNextRows); + SET_EXPECT(rowset_GetData); + SET_EXPECT(rowset_AddRefRows); + SET_EXPECT(rowset_ReleaseRows); + hr = IRowsetFind_FindNextRow(find, 0, hacc, &v, DBCOMPAREOPS_EQ, 0, NULL, 0, 1, &rows, &hrows); + CHECK_CALLED(rowset_GetNextRows); + CHECK_CALLED(rowset_GetData); + CHECK_CALLED(rowset_AddRefRows); + CHECK_CALLED(rowset_ReleaseRows); + ok(hr == S_OK, "got %08lx\n", hr); + ok(rows == 1, "rows = %Id\n", rows); + ok(hrow == 1, "hrow = %Id\n", hrow); + + SET_EXPECT(rowset_GetNextRows); + SET_EXPECT(rowset_GetData); + SET_EXPECT(rowset_AddRefRows); + SET_EXPECT(rowset_ReleaseRows); + hr = IRowsetFind_FindNextRow(find, 0, hacc, &v, DBCOMPAREOPS_EQ, 0, NULL, 0, 1, &rows, &hrows); + CHECK_CALLED(rowset_GetNextRows); + CHECK_CALLED(rowset_GetData); + CHECK_CALLED(rowset_AddRefRows); + CHECK_CALLED(rowset_ReleaseRows); + ok(hr == S_OK, "got %08lx\n", hr); + ok(rows == 1, "rows = %Id\n", rows); + ok(hrow == 2, "hrow = %Id\n", hrow); + + V_BSTR(&v)[0] = '2'; + bookmark = DBBMK_FIRST; + SET_EXPECT(rowset_GetRowsAt); + SET_EXPECT(rowset_GetData); + SET_EXPECT(rowset_ReleaseRows); + hr = IRowsetFind_FindNextRow(find, 0, hacc, &v, DBCOMPAREOPS_EQ, + sizeof(bookmark), &bookmark, 0, 1, &rows, &hrows); + CHECK_CALLED(rowset_GetRowsAt); + CHECK_CALLED(rowset_GetData); + CHECK_CALLED(rowset_ReleaseRows); + ok(hr == DB_S_ENDOFROWSET, "got %08lx\n", hr); + ok(!rows, "rows = %Id\n", rows); + ok(hrow == 2, "hrow = %Id\n", hrow); + VariantClear(&v); + + SET_EXPECT(accessor_ReleaseAccessor); + hr = IAccessor_ReleaseAccessor(accessor, hacc, NULL); + ok(hr == S_OK, "got %08lx\n", hr); + CHECK_CALLED(accessor_ReleaseAccessor); + IAccessor_Release(accessor); + IRowsetFind_Release(find); + 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/10742
participants (2)
-
Piotr Caban -
Piotr Caban (@piotr)