[PATCH 0/4] MR9678: msado15: Partial _Recordset::Update and _Recordset::CancelUpdate implementation.
From: Piotr Caban <piotr(a)codeweavers.com> --- dlls/msado15/recordset.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index ae7289527f9..300ed759f75 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -2331,6 +2331,8 @@ static HRESULT get_rowset(struct recordset *recordset, IUnknown *session, BSTR s ICommandText *command_text; IOpenRowset *openrowset; DBROWCOUNT affected; + DBPROPSET propset; + DBPROP props[3]; ICommand *cmd; DBID table; HRESULT hr; @@ -2341,7 +2343,23 @@ static HRESULT get_rowset(struct recordset *recordset, IUnknown *session, BSTR s table.eKind = DBKIND_NAME; table.uName.pwszName = source; - hr = IOpenRowset_OpenRowset(openrowset, NULL, &table, NULL, &IID_IUnknown, 0, NULL, rowset); + + propset.guidPropertySet = DBPROPSET_ROWSET; + propset.cProperties = ARRAY_SIZE(props); + propset.rgProperties = props; + memset(props, 0, sizeof(props)); + props[0].dwPropertyID = DBPROP_IRowsetChange; + V_VT(&props[0].vValue) = VT_BOOL; + V_BOOL(&props[0].vValue) = (recordset->lock_type == adLockReadOnly ? VARIANT_FALSE : VARIANT_TRUE); + props[1].dwPropertyID = DBPROP_IRowsetUpdate; + V_VT(&props[1].vValue) = VT_BOOL; + V_BOOL(&props[1].vValue) = (recordset->lock_type == adLockBatchOptimistic ? VARIANT_TRUE : VARIANT_FALSE); + props[2].dwPropertyID = DBPROP_UPDATABILITY; + V_VT(&props[2].vValue) = VT_I4; + V_I4(&props[2].vValue) = (recordset->lock_type == adLockReadOnly ? 0 : + DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_DELETE | DBPROPVAL_UP_INSERT); + + hr = IOpenRowset_OpenRowset(openrowset, NULL, &table, NULL, &IID_IUnknown, 1, &propset, rowset); if (SUCCEEDED(hr)) { IOpenRowset_Release(openrowset); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9678
From: Piotr Caban <piotr(a)codeweavers.com> --- dlls/msado15/recordset.c | 38 ++++++++++++++++++++++++++++-- dlls/msado15/tests/msado15.c | 45 ++++++++++++++++++++++++++++++------ 2 files changed, 74 insertions(+), 9 deletions(-) diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index 300ed759f75..5ae4dbcb7fd 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -98,6 +98,7 @@ struct recordset IRowsetLocate *rowset_locate; IRowsetExactScroll *rowset_es; IRowsetChange *rowset_change; + IRowsetUpdate *rowset_update; IAccessor *accessor; IRowsetCurrentIndex *rowset_cur_idx; EditModeEnum editmode; @@ -1641,6 +1642,9 @@ static void close_recordset( struct recordset *recordset ) if ( recordset->rowset_change && recordset->rowset_change != NO_INTERFACE ) IRowsetChange_Release( recordset->rowset_change ); recordset->rowset_change = NULL; + if ( recordset->rowset_update && recordset->rowset_update != NO_INTERFACE ) + IRowsetUpdate_Release( recordset->rowset_update ); + recordset->rowset_update = NULL; if ( recordset->rowset_cur_idx && recordset->rowset_cur_idx != NO_INTERFACE ) IRowsetCurrentIndex_Release( recordset->rowset_cur_idx ); recordset->rowset_cur_idx = NULL; @@ -2196,12 +2200,42 @@ static HRESULT WINAPI recordset_AddNew( _Recordset *iface, VARIANT field_list, V static HRESULT WINAPI recordset_CancelUpdate( _Recordset *iface ) { struct recordset *recordset = impl_from_Recordset( iface ); + DBPENDINGSTATUS pending_status; + DBROWSTATUS *status; + DBCOUNTITEM count; + HRESULT hr; + HROW *row; - FIXME( "%p\n", iface ); + TRACE( "%p\n", iface ); - if (recordset->active_connection == NULL) + if (recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed ); + if (!recordset->current_row) return MAKE_ADO_HRESULT( adErrNoCurrentRecord ); + + if (!recordset->rowset_update) + { + hr = IRowset_QueryInterface( recordset->row_set, &IID_IRowsetUpdate, + (void **)&recordset->rowset_update ); + if (FAILED(hr) || !recordset->rowset_update) + recordset->rowset_update = NO_INTERFACE; + } + if (recordset->rowset_update == NO_INTERFACE) return S_OK; + + hr = IRowsetUpdate_GetRowStatus( recordset->rowset_update, 0, + 1, &recordset->current_row, &pending_status ); + if (FAILED(hr)) return S_OK; + if (pending_status & (DBPENDINGSTATUS_UNCHANGED | DBPENDINGSTATUS_INVALIDROW)) return S_OK; + if (!(pending_status & (DBPENDINGSTATUS_NEW | DBPENDINGSTATUS_CHANGED | DBPENDINGSTATUS_DELETED))) return S_OK; + row = NULL; + status = NULL; + hr = IRowsetUpdate_Undo( recordset->rowset_update, 0, 1, &recordset->current_row, &count, &row, &status ); + if (FAILED(hr)) return hr; + if (status[0] == DBROWSTATUS_E_CANCELED) FIXME("status = DBROWSTATUS_E_CANCELED\n"); + if (pending_status & DBPENDINGSTATUS_NEW) cache_release( recordset ); + CoTaskMemFree( row ); + CoTaskMemFree( status ); + recordset->editmode = adEditNone; return S_OK; } diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index 02228237e1f..430970caf3d 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -80,6 +80,8 @@ DEFINE_EXPECT(rowset_GetData); DEFINE_EXPECT(rowset_RestartPosition); DEFINE_EXPECT(rowset_update_SetData); DEFINE_EXPECT(rowset_update_InsertRow); +DEFINE_EXPECT(rowset_update_GetRowStatus); +DEFINE_EXPECT(rowset_update_Undo); DEFINE_EXPECT(accessor_AddRefAccessor); DEFINE_EXPECT(accessor_CreateAccessor); DEFINE_EXPECT(accessor_ReleaseAccessor); @@ -957,15 +959,32 @@ static HRESULT WINAPI rowset_update_GetPendingRows(IRowsetUpdate *iface, static HRESULT WINAPI rowset_update_GetRowStatus(IRowsetUpdate *iface, HCHAPTER reserved, DBCOUNTITEM count, const HROW rows[], DBPENDINGSTATUS status[]) { - ok(0, "Unexpected call\n"); - return E_NOTIMPL; + CHECK_EXPECT(rowset_update_GetRowStatus); + ok(!reserved, "reserved = %Id\n", reserved); + ok(count == 1, "count = %Id\n", count); + ok(rows[0] == 10, "rows[0] = %Id\n", rows[0]); + + status[0] = DBPENDINGSTATUS_NEW; + return S_OK; } static HRESULT WINAPI rowset_update_Undo(IRowsetUpdate *iface, HCHAPTER reserved, DBCOUNTITEM count, const HROW rows[], DBCOUNTITEM *undone_cnt, HROW **undone, DBROWSTATUS **status) { - ok(0, "Unexpected call\n"); - return E_NOTIMPL; + CHECK_EXPECT(rowset_update_Undo); + ok(!reserved, "reserved = %Id\n", reserved); + ok(count == 1, "count = %Id\n", count); + ok(rows[0] == 10, "rows[0] = %Id\n", rows[0]); + ok(undone_cnt != NULL, "undone_cnt = NULL\n"); + ok(undone != NULL, "undone = NULL\n"); + ok(status != NULL, "status = NULL\n"); + + *undone_cnt = 1; + *undone = CoTaskMemAlloc(sizeof(**undone)); + *undone[0] = rows[0]; + *status = CoTaskMemAlloc(sizeof(**status)); + *status[0] = DBROWSTATUS_S_OK; + return S_OK; } static HRESULT WINAPI rowset_update_Update(IRowsetUpdate *iface, HCHAPTER reserved, DBCOUNTITEM count, @@ -2047,9 +2066,22 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) CHECK_CALLED(accessor_ReleaseAccessor); if (exact_scroll) CHECK_EXPECT(rowset_GetData); + SET_EXPECT(rowset_update_GetRowStatus); + SET_EXPECT(rowset_update_Undo); + SET_EXPECT(rowset_AddRefRows); + SET_EXPECT(rowset_ReleaseRows); + hr = _Recordset_CancelUpdate( recordset ); + ok( hr == S_OK, "got %08lx\n", hr ); + CHECK_CALLED(rowset_update_GetRowStatus); + CHECK_CALLED(rowset_update_Undo); + todo_wine CHECK_CALLED(rowset_AddRefRows); + CHECK_CALLED(rowset_ReleaseRows); + + hr = _Recordset_CancelUpdate( recordset ); + ok( hr == MAKE_ADO_HRESULT( adErrNoCurrentRecord ), "got %08lx\n", hr ); + V_VT(&v) = VT_BSTR; V_BSTR(&v) = SysAllocString( L"Column1 = 1" ); - SET_EXPECT(rowset_AddRefRows); SET_EXPECT(rowset_ReleaseRows); SET_EXPECT(accessor_CreateAccessor); SET_EXPECT(accessor_AddRefAccessor); @@ -2069,7 +2101,6 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) } hr = _Recordset_put_Filter( recordset, v ); todo_wine ok( hr == S_OK, "got %08lx\n", hr ); - todo_wine CHECK_CALLED(rowset_AddRefRows); todo_wine CHECK_CALLED(rowset_ReleaseRows); todo_wine CHECK_CALLED(accessor_CreateAccessor); todo_wine CHECK_CALLED(accessor_AddRefAccessor); @@ -2095,7 +2126,7 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) SET_EXPECT(accessor_ReleaseAccessor); SET_EXPECT(chaptered_rowset_ReleaseChapter); ok( !_Recordset_Release( recordset ), "_Recordset not released\n" ); - CHECK_CALLED(rowset_ReleaseRows ); + todo_wine CHECK_CALLED(rowset_ReleaseRows ); CHECK_CALLED(accessor_ReleaseAccessor); todo_wine CHECK_CALLED(chaptered_rowset_ReleaseChapter); ok( testrowset.refs == 1, "got %ld\n", testrowset.refs ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9678
From: Piotr Caban <piotr(a)codeweavers.com> --- dlls/msado15/recordset.c | 40 +++++++++++++++++++++++++++++++++--- dlls/msado15/tests/msado15.c | 6 ++++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index 5ae4dbcb7fd..dcb6d483801 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -2547,14 +2547,48 @@ static HRESULT WINAPI recordset__xResync( _Recordset *iface, AffectEnum affect_r static HRESULT WINAPI recordset_Update( _Recordset *iface, VARIANT fields, VARIANT values ) { struct recordset *recordset = impl_from_Recordset( iface ); + DBPENDINGSTATUS pending_status; + DBROWSTATUS *status; + HRESULT hr; + HROW *row; - FIXME( "%p, %s, %s\n", iface, debugstr_variant(&fields), debugstr_variant(&values) ); + TRACE( "%p, %s, %s\n", iface, debugstr_variant(&fields), debugstr_variant(&values) ); + if (V_VT(&fields) != VT_ERROR) + FIXME( "ignoring field list and values\n" ); - if (recordset->active_connection == NULL) + if (recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed ); + if (!recordset->current_row) return MAKE_ADO_HRESULT( adErrNoCurrentRecord ); + + if (recordset->lock_type != adLockPessimistic && recordset->lock_type != adLockOptimistic) + return S_OK; + + if (!recordset->rowset_update) + { + hr = IRowset_QueryInterface( recordset->row_set, &IID_IRowsetUpdate, + (void **)&recordset->rowset_update ); + if (FAILED(hr) || !recordset->rowset_update) + recordset->rowset_update = NO_INTERFACE; + } + if (recordset->rowset_update == NO_INTERFACE) return S_OK; + hr = IRowsetUpdate_GetRowStatus( recordset->rowset_update, 0, + 1, &recordset->current_row, &pending_status ); + if (FAILED(hr)) return S_OK; + if (pending_status & (DBPENDINGSTATUS_UNCHANGED | DBPENDINGSTATUS_INVALIDROW)) return S_OK; + if (!(pending_status & (DBPENDINGSTATUS_NEW | DBPENDINGSTATUS_CHANGED | DBPENDINGSTATUS_DELETED))) + return S_OK; + + row = NULL; + status = NULL; + hr = IRowsetUpdate_Update( recordset->rowset_update, 0, 1, &recordset->current_row, NULL, &row, &status ); + if (FAILED(hr)) return hr; + if (status[0] == DBROWSTATUS_E_CANCELED) FIXME("status = DBROWSTATUS_E_CANCELED\n"); + CoTaskMemFree( row ); + CoTaskMemFree( status ); + recordset->editmode = adEditNone; - return E_NOTIMPL; + return S_OK; } static HRESULT WINAPI recordset_get_AbsolutePage( _Recordset *iface, PositionEnum_Param *pos ) diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index 430970caf3d..67609d9bd8f 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -2066,6 +2066,9 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) CHECK_CALLED(accessor_ReleaseAccessor); if (exact_scroll) CHECK_EXPECT(rowset_GetData); + hr = _Recordset_Update( recordset, missing, missing ); + ok( hr == S_OK, "got %08lx\n", hr ); + SET_EXPECT(rowset_update_GetRowStatus); SET_EXPECT(rowset_update_Undo); SET_EXPECT(rowset_AddRefRows); @@ -2080,6 +2083,9 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) hr = _Recordset_CancelUpdate( recordset ); ok( hr == MAKE_ADO_HRESULT( adErrNoCurrentRecord ), "got %08lx\n", hr ); + hr = _Recordset_Update( recordset, missing, missing ); + ok( hr == MAKE_ADO_HRESULT( adErrNoCurrentRecord ), "got %08lx\n", hr ); + V_VT(&v) = VT_BSTR; V_BSTR(&v) = SysAllocString( L"Column1 = 1" ); SET_EXPECT(rowset_ReleaseRows); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9678
From: Piotr Caban <piotr(a)codeweavers.com> --- dlls/msado15/recordset.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index dcb6d483801..611c509003d 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -142,6 +142,17 @@ static inline BOOL cache_is_empty( struct recordset *recordset ) return !recordset->cache.fetched; } +static HRESULT update_current_row( struct recordset *recordset ) +{ + VARIANT missing; + + if ( !recordset->current_row ) return S_OK; + + V_VT( &missing ) = VT_ERROR; + V_ERROR( &missing ) = DISP_E_PARAMNOTFOUND; + return _Recordset_Update( &recordset->Recordset_iface, missing, missing); +} + static void cache_release( struct recordset *recordset ) { if (cache_is_empty( recordset )) @@ -207,6 +218,10 @@ static HRESULT cache_get( struct recordset *recordset, BOOL forward ) { int dir = forward ? 1 : -1; LONG off, fetch = 0; + HRESULT hr; + + hr = update_current_row( recordset ); + if (FAILED(hr)) return hr; if (!recordset->cache.dir) { @@ -235,7 +250,6 @@ static HRESULT cache_get( struct recordset *recordset, BOOL forward ) { DBCOUNTITEM count; HROW row = 0; - HRESULT hr; if (!cache_is_empty( recordset )) { @@ -2174,6 +2188,10 @@ static HRESULT WINAPI recordset_AddNew( _Recordset *iface, VARIANT field_list, V if (recordset->accessor == NO_INTERFACE) return MAKE_ADO_HRESULT( adErrFeatureNotAvailable ); + hr = update_current_row( recordset ); + if (FAILED(hr)) return hr; + cache_release( recordset ); + if (!recordset->hacc_empty) { hr = IAccessor_CreateAccessor( recordset->accessor, DBACCESSOR_ROWDATA, @@ -2185,7 +2203,6 @@ 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 ); - cache_release( recordset ); hr = IRowsetChange_InsertRow( recordset->rowset_change, 0, recordset->hacc_empty, NULL, &recordset->current_row ); IAccessor_ReleaseAccessor( recordset->accessor, recordset->hacc_empty, &refcount ); @@ -2323,6 +2340,8 @@ static HRESULT WINAPI recordset_MoveFirst( _Recordset *iface ) } else { + hr = update_current_row( recordset ); + if (FAILED(hr)) return hr; cache_release( recordset ); hr = IRowset_RestartPosition( recordset->row_set, DB_NULL_HCHAPTER ); if (FAILED(hr)) return hr; @@ -2350,6 +2369,8 @@ static HRESULT WINAPI recordset_MoveLast( _Recordset *iface ) } else { + hr = update_current_row( recordset ); + if (FAILED(hr)) return hr; cache_release( recordset ); hr = IRowset_RestartPosition( recordset->row_set, DB_NULL_HCHAPTER ); if (FAILED(hr)) return hr; @@ -3048,6 +3069,8 @@ static HRESULT WINAPI recordset_put_Index( _Recordset *iface, BSTR index ) if (recordset->rowset_cur_idx == NO_INTERFACE) return MAKE_ADO_HRESULT( adErrFeatureNotAvailable ); + hr = update_current_row( recordset ); + if (FAILED(hr)) return hr; cache_release( recordset ); memset( &dbid, 0, sizeof(dbid) ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9678
participants (2)
-
Piotr Caban -
Piotr Caban (@piotr)