From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/recordset.c | 70 ++++++++++++++++++++++++++++++ dlls/msado15/rowset.c | 82 +++++++++++++++++++++++++++++++----- dlls/msado15/tests/msado15.c | 16 +++---- 3 files changed, 150 insertions(+), 18 deletions(-)
diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index a41023e03ef..79db8c55147 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -32,6 +32,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(msado15);
+#define NO_INTERFACE ((void*)-1) + struct recordset;
struct field @@ -79,12 +81,16 @@ struct recordset CursorLocationEnum cursor_location; CursorTypeEnum cursor_type; IRowset *row_set; + IRowsetChange *rowset_change; + IAccessor *accessor; EditModeEnum editmode; + HROW current_row; LONG cache_size; ADO_LONGPTR max_records; VARIANT filter;
DBTYPE *columntypes; + HACCESSOR hacc_empty; /* haccessor for adding empty rows */ HACCESSOR *haccessors; };
@@ -1253,8 +1259,25 @@ 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; + } + if ( recordset->hacc_empty ) + { + IAccessor_ReleaseAccessor( recordset->accessor, recordset->hacc_empty, NULL ); + recordset->hacc_empty = 0; + } + if ( recordset->row_set ) IRowset_Release( recordset->row_set ); recordset->row_set = NULL; + if ( recordset->rowset_change && recordset->rowset_change != NO_INTERFACE ) + IRowsetChange_Release( recordset->rowset_change ); + recordset->rowset_change = NULL; + if (recordset->accessor && recordset->accessor != NO_INTERFACE ) + IAccessor_Release( recordset->accessor ); + recordset->accessor = NULL;
VariantClear( &recordset->filter );
@@ -1653,6 +1676,8 @@ static BOOL resize_recordset( struct recordset *recordset, ULONG row_count ) static HRESULT WINAPI recordset_AddNew( _Recordset *iface, VARIANT field_list, VARIANT values ) { struct recordset *recordset = impl_from_Recordset( iface ); + DBREFCOUNT refcount; + HRESULT hr;
TRACE( "%p, %s, %s\n", recordset, debugstr_variant(&field_list), debugstr_variant(&values) ); if (V_VT(&field_list) != VT_ERROR) @@ -1660,6 +1685,51 @@ static HRESULT WINAPI recordset_AddNew( _Recordset *iface, VARIANT field_list, V
if (recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed );
+ if (!recordset->rowset_change) + { + hr = IRowset_QueryInterface( recordset->row_set, &IID_IRowsetChange, + (void **)&recordset->rowset_change ); + if (FAILED(hr) || !recordset->rowset_change) + recordset->rowset_change = NO_INTERFACE; + } + if (recordset->rowset_change == NO_INTERFACE) + return MAKE_ADO_HRESULT( adErrFeatureNotAvailable ); + + if (!recordset->accessor) + { + hr = IRowset_QueryInterface( recordset->row_set, &IID_IAccessor, (void **)&recordset->accessor ); + if (FAILED(hr) || !recordset->accessor) + recordset->accessor = NO_INTERFACE; + } + if (recordset->accessor == NO_INTERFACE) + return MAKE_ADO_HRESULT( adErrFeatureNotAvailable ); + + if (!recordset->hacc_empty) + { + hr = IAccessor_CreateAccessor( recordset->accessor, DBACCESSOR_ROWDATA, + 0, NULL, 0, &recordset->hacc_empty, NULL ); + if (FAILED(hr) || !recordset->hacc_empty) + return MAKE_ADO_HRESULT( adErrNoCurrentRecord ); + } + + 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; + } + } + hr = IRowsetChange_InsertRow( recordset->rowset_change, 0, + recordset->hacc_empty, NULL, &recordset->current_row ); + IAccessor_ReleaseAccessor( recordset->accessor, recordset->hacc_empty, &refcount ); + if (FAILED(hr)) + return MAKE_ADO_HRESULT( adErrNoCurrentRecord ); + if (!resize_recordset( recordset, recordset->count + 1 )) return E_OUTOFMEMORY; recordset->index = recordset->count - 1; recordset->editmode = adEditAdd; diff --git a/dlls/msado15/rowset.c b/dlls/msado15/rowset.c index 5e463c2de92..c776f6c3b3d 100644 --- a/dlls/msado15/rowset.c +++ b/dlls/msado15/rowset.c @@ -18,6 +18,7 @@
#define COBJMACROS #include "oledb.h" +#include "oledberr.h" #include "unknwn.h"
#include "wine/debug.h" @@ -35,6 +36,13 @@ struct rowset int columns_cnt; DBCOLUMNINFO *columns; OLECHAR *columns_buf; + + int row_cnt; +}; + +struct accessor +{ + LONG refs; };
static inline struct rowset *impl_from_IRowsetExactScroll(IRowsetExactScroll *iface) @@ -154,8 +162,15 @@ static HRESULT WINAPI rowset_ReleaseRows(IRowsetExactScroll *iface, DBCOUNTITEM { struct rowset *rowset = impl_from_IRowsetExactScroll(iface);
- FIXME("%p, %Id, %p, %p, %p, %p\n", rowset, count, rows, options, ref_counts, status); - return E_NOTIMPL; + TRACE("%p, %Id, %p, %p, %p, %p\n", rowset, count, rows, options, ref_counts, status); + + if (options || ref_counts || status) + { + FIXME("unhandled parameters\n"); + return E_NOTIMPL; + } + + return S_OK; }
static HRESULT WINAPI rowset_RestartPosition(IRowsetExactScroll *iface, HCHAPTER reserved) @@ -391,8 +406,17 @@ static HRESULT WINAPI rowset_change_InsertRow(IRowsetChange *iface, HCHAPTER res { struct rowset *rowset = impl_from_IRowsetChange(iface);
- FIXME("%p, %Iu, %Id, %p, %p\n", rowset, reserved, accessor, data, row); - return E_NOTIMPL; + TRACE("%p, %Iu, %Id, %p, %p\n", rowset, reserved, accessor, data, row); + + if (data) + { + FIXME("setting data not implemented\n"); + return E_NOTIMPL; + } + + rowset->row_cnt++; + if (row) *row = rowset->row_cnt; + return S_OK; }
static struct IRowsetChangeVtbl rowset_change_vtbl = @@ -425,10 +449,17 @@ static ULONG WINAPI accessor_Release(IAccessor *iface)
static HRESULT WINAPI accessor_AddRefAccessor(IAccessor *iface, HACCESSOR hAccessor, DBREFCOUNT *pcRefCount) { + struct accessor *accessor = (struct accessor *)hAccessor; struct rowset *rowset = impl_from_IAccessor(iface); + LONG ref;
- FIXME("%p, %Id, %p\n", rowset, hAccessor, pcRefCount); - return E_NOTIMPL; + TRACE("%p, %Id, %p\n", rowset, hAccessor, pcRefCount); + + if (!hAccessor) return DB_E_BADACCESSORHANDLE; + + ref = InterlockedIncrement(&accessor->refs); + if (pcRefCount) *pcRefCount = ref; + return S_OK; }
static HRESULT WINAPI accessor_CreateAccessor(IAccessor *iface, DBACCESSORFLAGS dwAccessorFlags, @@ -436,10 +467,31 @@ static HRESULT WINAPI accessor_CreateAccessor(IAccessor *iface, DBACCESSORFLAGS HACCESSOR *phAccessor, DBBINDSTATUS rgStatus[]) { struct rowset *rowset = impl_from_IAccessor(iface); + struct accessor *accessor;
- FIXME("%p, %lx, %Iu, %p %Id, %p %p\n", rowset, dwAccessorFlags, cBindings, + TRACE("%p, %lx, %Iu, %p %Id, %p %p\n", rowset, dwAccessorFlags, cBindings, rgBindings, cbRowSize, phAccessor, rgStatus); - return E_NOTIMPL; + + if (!phAccessor) return E_INVALIDARG; + *phAccessor = 0; + + if (cBindings || cbRowSize) + { + FIXME("accessing data not implemented\n"); + return E_NOTIMPL; + } + if (dwAccessorFlags != DBACCESSOR_ROWDATA) + { + FIXME("unsupported flags %lx\n", dwAccessorFlags); + return E_NOTIMPL; + } + + accessor = calloc(1, sizeof(*accessor)); + if (!accessor) return E_OUTOFMEMORY; + accessor->refs = 1; + + *phAccessor = (HACCESSOR)accessor; + return S_OK; }
static HRESULT WINAPI accessor_GetBindings(IAccessor *iface, HACCESSOR hAccessor, @@ -454,10 +506,20 @@ static HRESULT WINAPI accessor_GetBindings(IAccessor *iface, HACCESSOR hAccessor static HRESULT WINAPI accessor_ReleaseAccessor(IAccessor *iface, HACCESSOR hAccessor, DBREFCOUNT *pcRefCount) { + struct accessor *accessor = (struct accessor *)hAccessor; struct rowset *rowset = impl_from_IAccessor(iface); + LONG ref;
- FIXME("%p, %Id, %p\n", rowset, hAccessor, pcRefCount); - return E_NOTIMPL; + TRACE("%p, %Id, %p\n", rowset, hAccessor, pcRefCount); + + if (!hAccessor) return DB_E_BADACCESSORHANDLE; + + ref = InterlockedDecrement(&accessor->refs); + if (!ref) + free(accessor); + + if (pcRefCount) *pcRefCount = ref; + return S_OK; }
static struct IAccessorVtbl accessor_vtbl = diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index 4c974396727..111c93d99f7 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -1152,12 +1152,12 @@ 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 ); - todo_wine CHECK_CALLED(rowset_QI_IRowsetChange); - todo_wine CHECK_CALLED(rowset_QI_IAccessor); - todo_wine CHECK_CALLED(accessor_CreateAccessor); - todo_wine CHECK_CALLED(accessor_AddRefAccessor); - todo_wine CHECK_CALLED(rowset_change_InsertRow); - todo_wine CHECK_CALLED(accessor_ReleaseAccessor); + CHECK_CALLED(rowset_QI_IRowsetChange); + CHECK_CALLED(rowset_QI_IAccessor); + CHECK_CALLED(accessor_CreateAccessor); + CHECK_CALLED(accessor_AddRefAccessor); + CHECK_CALLED(rowset_change_InsertRow); + CHECK_CALLED(accessor_ReleaseAccessor);
Fields_Release(fields); ADORecordsetConstruction_Release(construct); @@ -1165,9 +1165,9 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) SET_EXPECT( rowset_QI_IAccessor ); SET_EXPECT(accessor_ReleaseAccessor); ok( !_Recordset_Release( recordset ), "_Recordset not released\n" ); - todo_wine CHECK_CALLED(rowset_ReleaseRows ); + CHECK_CALLED(rowset_ReleaseRows ); todo_wine CHECK_CALLED( rowset_QI_IAccessor ); - todo_wine CHECK_CALLED(accessor_ReleaseAccessor); + CHECK_CALLED(accessor_ReleaseAccessor); ok( testrowset.refs == 1, "got %ld\n", testrowset.refs ); }