From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/rowset.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/dlls/msado15/rowset.c b/dlls/msado15/rowset.c index a4019ef6612..f5de78d5e30 100644 --- a/dlls/msado15/rowset.c +++ b/dlls/msado15/rowset.c @@ -148,8 +148,14 @@ static HRESULT WINAPI rowset_AddRefRows(IRowsetExactScroll *iface, DBCOUNTITEM c { struct rowset *rowset = impl_from_IRowsetExactScroll(iface);
- FIXME("%p, %Id, %p, %p, %p\n", rowset, count, rows, ref_counts, status); - return E_NOTIMPL; + TRACE("%p, %Id, %p, %p, %p\n", rowset, count, rows, ref_counts, status); + if (ref_counts || status) + { + FIXME("unhandled parameters\n"); + return E_NOTIMPL; + } + + return S_OK; }
static HRESULT WINAPI rowset_GetData(IRowsetExactScroll *iface, HROW row, HACCESSOR accessor, void *data)
From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/rowset.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/msado15/rowset.c b/dlls/msado15/rowset.c index f5de78d5e30..c68280c5240 100644 --- a/dlls/msado15/rowset.c +++ b/dlls/msado15/rowset.c @@ -232,8 +232,10 @@ static HRESULT WINAPI rowset_RestartPosition(IRowsetExactScroll *iface, HCHAPTER { struct rowset *rowset = impl_from_IRowsetExactScroll(iface);
- FIXME("%p, %Id\n", rowset, reserved); - return E_NOTIMPL; + TRACE("%p, %Id\n", rowset, reserved); + + rowset->index = 0; + return S_OK; }
static HRESULT WINAPI rowset_Compare(IRowsetExactScroll *iface, HCHAPTER hReserved, DBBKMARK cbBookmark1,
From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/tests/msado15.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index 2901f468b3e..8b1d7c4499b 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -523,6 +523,7 @@ struct test_rowset IAccessor IAccessor_iface; LONG refs; BOOL exact_scroll; + int idx; };
struct haccessor @@ -1073,7 +1074,7 @@ static HRESULT WINAPI rowset_GetData(IRowsetExactScroll *iface, HROW hRow, HACCE static HRESULT WINAPI rowset_GetNextRows(IRowsetExactScroll *iface, HCHAPTER hReserved, DBROWOFFSET lRowsOffset, DBROWCOUNT cRows, DBCOUNTITEM *pcRowObtained, HROW **prghRows) { - static int idx; + struct test_rowset *rowset = impl_from_IRowsetExactScroll( iface );
CHECK_EXPECT2(rowset_GetNextRows); ok(!hReserved, "hReserved = %Ix\n", hReserved); @@ -1081,7 +1082,7 @@ static HRESULT WINAPI rowset_GetNextRows(IRowsetExactScroll *iface, HCHAPTER hRe ok(prghRows != NULL, "prghRows = NULL\n"); ok(*prghRows != NULL, "*prghRows = NULL\n");
- if (idx == 2) + if (rowset->idx == 2) { *pcRowObtained = 0; return DB_S_ENDOFROWSET; @@ -1089,7 +1090,7 @@ static HRESULT WINAPI rowset_GetNextRows(IRowsetExactScroll *iface, HCHAPTER hRe
ok(!lRowsOffset, "lRowsOffset = %Id\n", lRowsOffset); *pcRowObtained = 1; - (*prghRows)[0] = idx++; + (*prghRows)[0] = ++rowset->idx; return S_OK; }
@@ -1259,6 +1260,7 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) testrowset.IAccessor_iface.lpVtbl = &accessor; testrowset.refs = 1; testrowset.exact_scroll = exact_scroll; + testrowset.idx = 0;
rowset = (IUnknown*)&testrowset.IRowsetExactScroll_iface;
@@ -1347,8 +1349,8 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) { SET_EXPECT( rowset_GetRowsAt ); SET_EXPECT( rowset_GetData ); - SET_EXPECT( rowset_AddRefRows ); } + SET_EXPECT( rowset_AddRefRows ); SET_EXPECT( rowset_ReleaseRows ); hr = _Recordset_MoveNext( recordset ); if (!exact_scroll) todo_wine CHECK_CALLED( rowset_GetNextRows ); @@ -1356,8 +1358,8 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) { todo_wine CHECK_CALLED( rowset_GetRowsAt ); todo_wine CHECK_CALLED( rowset_GetData ); - todo_wine CHECK_CALLED( rowset_AddRefRows ); } + todo_wine CHECK_CALLED( rowset_AddRefRows ); todo_wine CHECK_CALLED( rowset_ReleaseRows ); ok( hr == S_OK, "got %08lx\n", hr ); todo_wine ok( !is_eof( recordset ), "at eof\n" );
From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/recordset.c | 151 +++++++++++++++++++++++++++++++---- dlls/msado15/tests/msado15.c | 45 +++++++---- 2 files changed, 165 insertions(+), 31 deletions(-)
diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index 7f115ee2c72..3593f5171cb 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -92,9 +92,12 @@ struct recordset LONG alloc; LONG size; LONG fetched; + BOOL forward; LONG pos; HROW *rows; } cache; + VARIANT_BOOL is_bof; + VARIANT_BOOL is_eof; ADO_LONGPTR max_records; VARIANT filter;
@@ -113,9 +116,21 @@ static inline struct field *impl_from_Properties( Properties *iface ) return CONTAINING_RECORD( iface, struct field, Properties_iface ); }
+static inline BOOL cache_is_empty( struct recordset *recordset ) +{ + return !recordset->cache.fetched; +} + static void cache_release( struct recordset *recordset ) { - if (!recordset->cache.fetched) return; + if (cache_is_empty( recordset )) + { + if (recordset->current_row) + IRowset_ReleaseRows( recordset->row_set, 1, &recordset->current_row, NULL, NULL, NULL); + recordset->current_row = DB_NULL_HROW; + return; + } + IRowset_ReleaseRows( recordset->row_set, recordset->cache.fetched, recordset->cache.rows, NULL, NULL, NULL ); recordset->cache.fetched = 0; @@ -123,14 +138,79 @@ static void cache_release( struct recordset *recordset ) recordset->current_row = DB_NULL_HROW; }
-static void cache_add( struct recordset *recordset, HROW row ) +static HRESULT cache_get( struct recordset *recordset, BOOL forward ) { - assert( !recordset->cache.fetched ); - assert( !recordset->cache.pos ); + int dir = forward ? 1 : -1; + LONG off, fetch = 0; + + if (!forward == !recordset->cache.forward) + { + if (recordset->cache.pos + 1 > recordset->cache.fetched) + { + off = 0; + fetch = dir * recordset->cache.size; + } + } + else + { + if (recordset->cache.pos -1 <= 0) + { + off = dir * recordset->cache.fetched; + fetch = dir * recordset->cache.size; + } + } + + if (fetch) + { + DBCOUNTITEM count; + HROW row = 0; + HRESULT hr; + + if (!cache_is_empty( recordset )) + { + if (SUCCEEDED(IRowset_AddRefRows(recordset->row_set, 1, &recordset->current_row, NULL, NULL))) + row = recordset->current_row; + } + cache_release( recordset ); + recordset->current_row = row; + + hr = IRowset_GetNextRows(recordset->row_set, 0, off, fetch, &count, &recordset->cache.rows); + if (FAILED(hr)) return hr; + + if (recordset->current_row) + { + IRowset_ReleaseRows(recordset->row_set, 1, &recordset->current_row, NULL, NULL, NULL); + recordset->current_row = 0; + } + + if (!count) + { + if (!recordset->is_eof && forward) + { + recordset->is_eof = VARIANT_TRUE; + if (!row) recordset->is_bof = VARIANT_TRUE; + return S_OK; + } + if (!recordset->is_bof && !forward) + { + recordset->is_bof = VARIANT_TRUE; + return S_OK; + } + return MAKE_ADO_HRESULT(adErrNoCurrentRecord); + } + + + recordset->cache.pos = 0; + recordset->cache.fetched = count; + recordset->cache.forward = forward; + }
- recordset->cache.rows[0] = row; - recordset->cache.fetched = 1; - recordset->current_row = row; + recordset->is_bof = recordset->is_eof = VARIANT_FALSE; + if (!forward == !recordset->cache.forward) + recordset->current_row = recordset->cache.rows[recordset->cache.pos++]; + else + recordset->current_row = recordset->cache.rows[--recordset->cache.pos]; + return S_OK; }
static ULONG WINAPI field_AddRef( Field *iface ) @@ -1322,7 +1402,7 @@ static void close_recordset( struct recordset *recordset ) IRowset_QueryInterface(recordset->row_set, &IID_IAccessor, (void**)&accessor);
cache_release( recordset ); - recordset->current_row = DB_NULL_HROW; + recordset->is_bof = recordset->is_eof = VARIANT_FALSE; if ( recordset->hacc_empty ) { IAccessor_ReleaseAccessor( recordset->accessor, recordset->hacc_empty, NULL ); @@ -1805,7 +1885,6 @@ static HRESULT WINAPI recordset_AddNew( _Recordset *iface, VARIANT field_list, V struct recordset *recordset = impl_from_Recordset( iface ); DBREFCOUNT refcount; HRESULT hr; - HROW row;
TRACE( "%p, %s, %s\n", recordset, debugstr_variant(&field_list), debugstr_variant(&values) ); if (V_VT(&field_list) != VT_ERROR) @@ -1845,11 +1924,11 @@ static HRESULT WINAPI recordset_AddNew( _Recordset *iface, VARIANT field_list, V return MAKE_ADO_HRESULT( adErrNoCurrentRecord ); cache_release( recordset ); hr = IRowsetChange_InsertRow( recordset->rowset_change, 0, - recordset->hacc_empty, NULL, &row ); + recordset->hacc_empty, NULL, &recordset->current_row ); IAccessor_ReleaseAccessor( recordset->accessor, recordset->hacc_empty, &refcount ); if (FAILED(hr)) return MAKE_ADO_HRESULT( adErrNoCurrentRecord ); - cache_add( recordset, row ); + recordset->is_bof = recordset->is_eof = FALSE;
if (!resize_recordset( recordset, recordset->count + 1 )) return E_OUTOFMEMORY; recordset->index = recordset->count - 1; @@ -1904,21 +1983,43 @@ static HRESULT WINAPI recordset_Move( _Recordset *iface, ADO_LONGPTR num_records static HRESULT WINAPI recordset_MoveNext( _Recordset *iface ) { struct recordset *recordset = impl_from_Recordset( iface ); + HRESULT hr;
TRACE( "%p\n", recordset );
- if (recordset->index >= recordset->count) - return MAKE_ADO_HRESULT( adErrNoCurrentRecord ); - if (recordset->index < recordset->count) recordset->index++; + if (recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed ); + + if (!recordset->current_row) + { + hr = cache_get( recordset, TRUE ); + if (FAILED(hr)) return hr; + } + + hr = cache_get( recordset, TRUE ); + if (FAILED(hr)) return hr; + + recordset->index++; return S_OK; }
static HRESULT WINAPI recordset_MovePrevious( _Recordset *iface ) { struct recordset *recordset = impl_from_Recordset( iface ); + HRESULT hr;
TRACE( "%p\n", recordset );
+ if (recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed ); + + if (!recordset->current_row) + { + hr = cache_get( recordset, TRUE ); + if (FAILED(hr)) return hr; + } + + hr = cache_get( recordset, FALSE ); + if (FAILED(hr)) return hr; + if (recordset->index >= 0) recordset->index--; return S_OK; } @@ -1926,9 +2027,20 @@ static HRESULT WINAPI recordset_MovePrevious( _Recordset *iface ) static HRESULT WINAPI recordset_MoveFirst( _Recordset *iface ) { struct recordset *recordset = impl_from_Recordset( iface ); + HRESULT hr;
TRACE( "%p\n", recordset );
+ if (recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed ); + + cache_release( recordset ); + hr = IRowset_RestartPosition( recordset->row_set, DB_NULL_HCHAPTER ); + if (FAILED(hr)) return hr; + recordset->is_bof = recordset->is_eof = VARIANT_FALSE; + + hr = cache_get( recordset, TRUE ); + if (FAILED(hr)) return hr; + recordset->index = 0; return S_OK; } @@ -1936,9 +2048,20 @@ static HRESULT WINAPI recordset_MoveFirst( _Recordset *iface ) static HRESULT WINAPI recordset_MoveLast( _Recordset *iface ) { struct recordset *recordset = impl_from_Recordset( iface ); + HRESULT hr;
TRACE( "%p\n", recordset );
+ if (recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed ); + + cache_release( recordset ); + hr = IRowset_RestartPosition( recordset->row_set, DB_NULL_HCHAPTER ); + if (FAILED(hr)) return hr; + recordset->is_bof = recordset->is_eof = VARIANT_FALSE; + + hr = cache_get( recordset, FALSE ); + if (FAILED(hr)) return hr; + recordset->index = (recordset->count > 0) ? recordset->count - 1 : 0; return S_OK; } diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index 8b1d7c4499b..42900e39002 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -988,7 +988,7 @@ static HRESULT WINAPI rowset_QueryInterface(IRowsetExactScroll *iface, REFIID ri } else if (IsEqualIID(riid, &IID_IRowsetChange)) { - todo_wine CHECK_EXPECT(rowset_QI_IRowsetChange); + CHECK_EXPECT(rowset_QI_IRowsetChange); *obj = &rowset->IRowsetChange_iface; } else if (IsEqualIID(riid, &IID_IDBAsynchStatus)) @@ -1344,8 +1344,8 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) ok( hr == S_OK, "got %08lx\n", hr ); ok( size == (exact_scroll ? 3 : -1), "size = %Id\n", size );
- if (!exact_scroll) SET_EXPECT( rowset_GetNextRows ); - else + SET_EXPECT( rowset_GetNextRows ); + if (exact_scroll) { SET_EXPECT( rowset_GetRowsAt ); SET_EXPECT( rowset_GetData ); @@ -1353,38 +1353,48 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) SET_EXPECT( rowset_AddRefRows ); SET_EXPECT( rowset_ReleaseRows ); hr = _Recordset_MoveNext( recordset ); - if (!exact_scroll) todo_wine CHECK_CALLED( rowset_GetNextRows ); + if (!exact_scroll) CHECK_CALLED( rowset_GetNextRows ); else { + todo_wine CHECK_NOT_CALLED( rowset_GetNextRows ); todo_wine CHECK_CALLED( rowset_GetRowsAt ); todo_wine CHECK_CALLED( rowset_GetData ); } - todo_wine CHECK_CALLED( rowset_AddRefRows ); - todo_wine CHECK_CALLED( rowset_ReleaseRows ); + CHECK_CALLED( rowset_AddRefRows ); + CHECK_CALLED( rowset_ReleaseRows ); ok( hr == S_OK, "got %08lx\n", hr ); todo_wine ok( !is_eof( recordset ), "at eof\n" );
SET_EXPECT( rowset_AddRefRows ); SET_EXPECT( rowset_ReleaseRows ); - if (!exact_scroll) SET_EXPECT( rowset_GetNextRows ); - else SET_EXPECT( rowset_GetRowsAt ); + SET_EXPECT( rowset_GetNextRows ); + if (exact_scroll) SET_EXPECT( rowset_GetRowsAt ); hr = _Recordset_MoveNext( recordset ); - todo_wine CHECK_CALLED( rowset_AddRefRows ); - todo_wine CHECK_CALLED( rowset_ReleaseRows ); - if (!exact_scroll) todo_wine CHECK_CALLED( rowset_GetNextRows ); - else todo_wine CHECK_CALLED( rowset_GetRowsAt ); - todo_wine ok( hr == S_OK, "got %08lx\n", hr ); + CHECK_CALLED( rowset_AddRefRows ); + CHECK_CALLED( rowset_ReleaseRows ); + if (!exact_scroll) CHECK_CALLED( rowset_GetNextRows ); + else + { + todo_wine CHECK_NOT_CALLED( rowset_GetNextRows ); + todo_wine CHECK_CALLED( rowset_GetRowsAt ); + } + ok( hr == S_OK, "got %08lx\n", hr ); ok( is_eof( recordset ), "unexpected records\n" );
- if (!exact_scroll) SET_EXPECT( rowset_GetNextRows ); - else SET_EXPECT( rowset_GetRowsAt ); + SET_EXPECT( rowset_GetNextRows ); + if (exact_scroll) SET_EXPECT( rowset_GetRowsAt ); hr = _Recordset_MoveNext( recordset ); - if (!exact_scroll) todo_wine CHECK_CALLED( rowset_GetNextRows ); - else todo_wine CHECK_CALLED( rowset_GetRowsAt ); + if (!exact_scroll) CHECK_CALLED( rowset_GetNextRows ); + else + { + todo_wine CHECK_NOT_CALLED( rowset_GetNextRows ); + todo_wine CHECK_CALLED( rowset_GetRowsAt ); + } ok( hr == MAKE_ADO_HRESULT(adErrNoCurrentRecord), "got %08lx\n", hr );
V_VT( &missing ) = VT_ERROR; V_ERROR( &missing ) = DISP_E_PARAMNOTFOUND; + SET_EXPECT(rowset_QI_IRowsetChange); SET_EXPECT(rowset_QI_IAccessor); SET_EXPECT(accessor_CreateAccessor); SET_EXPECT(accessor_AddRefAccessor); @@ -1393,6 +1403,7 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) if (exact_scroll) SET_EXPECT(rowset_GetData); hr = _Recordset_AddNew( recordset, missing, missing ); ok( hr == S_OK, "got %08lx\n", hr ); + todo_wine CHECK_NOT_CALLED(rowset_QI_IRowsetChange); if (!exact_scroll) CHECK_CALLED(rowset_QI_IAccessor); else todo_wine CHECK_NOT_CALLED(rowset_QI_IAccessor); CHECK_CALLED(accessor_CreateAccessor);
From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/recordset.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index 3593f5171cb..e53d86d4ca0 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -1648,10 +1648,19 @@ static HRESULT WINAPI recordset_get_ActiveConnection( _Recordset *iface, VARIANT static HRESULT WINAPI recordset_get_BOF( _Recordset *iface, VARIANT_BOOL *bof ) { struct recordset *recordset = impl_from_Recordset( iface ); + HRESULT hr;
TRACE( "%p, %p\n", recordset, bof );
- *bof = (recordset->index < 0) ? VARIANT_TRUE : VARIANT_FALSE; + if (recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed ); + + if (!recordset->is_bof && !recordset->is_eof && !recordset->current_row) + { + hr = cache_get( recordset, TRUE ); + if (FAILED(hr)) return hr; + } + + *bof = recordset->is_bof; return S_OK; }
From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/recordset.c | 11 ++++++++++- dlls/msado15/tests/msado15.c | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index e53d86d4ca0..79e80c15e69 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -1777,10 +1777,19 @@ static HRESULT WINAPI recordset_put_CursorType( _Recordset *iface, CursorTypeEnu static HRESULT WINAPI recordset_get_EOF( _Recordset *iface, VARIANT_BOOL *eof ) { struct recordset *recordset = impl_from_Recordset( iface ); + HRESULT hr;
TRACE( "%p, %p\n", recordset, eof );
- *eof = (!recordset->count || recordset->index >= recordset->count) ? VARIANT_TRUE : VARIANT_FALSE; + if (recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed ); + + if (!recordset->is_eof && !recordset->is_bof && !recordset->current_row) + { + hr = cache_get( recordset, TRUE ); + if (FAILED(hr)) return hr; + } + + *eof = recordset->is_eof; return S_OK; }
diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index 42900e39002..a73ac67ec6d 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -1363,7 +1363,7 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) CHECK_CALLED( rowset_AddRefRows ); CHECK_CALLED( rowset_ReleaseRows ); ok( hr == S_OK, "got %08lx\n", hr ); - todo_wine ok( !is_eof( recordset ), "at eof\n" ); + ok( !is_eof( recordset ), "at eof\n" );
SET_EXPECT( rowset_AddRefRows ); SET_EXPECT( rowset_ReleaseRows );