It also contains fixes for bookmarks handling and removes `_Recordset::put_Filter()` hack.
From: Piotr Caban piotr@codeweavers.com
It's hard to preserve it while IRowset callbacks are used to obtain data. --- dlls/msado15/recordset.c | 35 ++++------------------------------- dlls/msado15/tests/msado15.c | 12 ++++++------ 2 files changed, 10 insertions(+), 37 deletions(-)
diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index 5a2b68a827d..d303b6d3c47 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -102,7 +102,6 @@ struct recordset VARIANT_BOOL is_bof; VARIANT_BOOL is_eof; ADO_LONGPTR max_records; - VARIANT filter;
DBTYPE *columntypes; HACCESSOR hacc_empty; /* haccessor for adding empty rows */ @@ -1516,8 +1515,6 @@ static void close_recordset( struct recordset *recordset ) IRowsetChange_Release( recordset->rowset_change ); recordset->rowset_change = NULL;
- VariantClear( &recordset->filter ); - col_count = get_column_count( recordset );
free(recordset->columntypes); @@ -2776,37 +2773,14 @@ static HRESULT WINAPI recordset_get_EditMode( _Recordset *iface, EditModeEnum *m
static HRESULT WINAPI recordset_get_Filter( _Recordset *iface, VARIANT *criteria ) { - struct recordset *recordset = impl_from_Recordset( iface ); - TRACE( "%p, %p\n", iface, criteria ); - - if (!criteria) return MAKE_ADO_HRESULT( adErrInvalidArgument ); - - VariantCopy(criteria, &recordset->filter); - return S_OK; + FIXME( "%p, %p\n", iface, criteria ); + return E_NOTIMPL; }
static HRESULT WINAPI recordset_put_Filter( _Recordset *iface, VARIANT criteria ) { - struct recordset *recordset = impl_from_Recordset( iface ); - TRACE( "%p, %s\n", recordset, debugstr_variant(&criteria) ); - - if (V_VT(&criteria) != VT_I2 && V_VT(&criteria) != VT_I4 && V_VT(&criteria) != VT_BSTR) - return MAKE_ADO_HRESULT( adErrInvalidArgument ); - - if (V_VT(&criteria) == VT_BSTR && recordset->state == adStateOpen) - { - FIXME("No filter performed. Reporting no records found.\n"); - - /* Set the index to signal we didn't find a record. */ - recordset->index = -1; - } - else - { - recordset->index = recordset->count ? 0 : -1; /* Reset */ - } - - VariantCopy(&recordset->filter, &criteria); - return S_OK; + TRACE( "%p, %s\n", iface, debugstr_variant(&criteria) ); + return E_NOTIMPL; }
static HRESULT WINAPI recordset_get_PageCount( _Recordset *iface, ADO_LONGPTR *count ) @@ -3377,7 +3351,6 @@ HRESULT Recordset_create( void **obj ) recordset->cache.size = 1; recordset->cache.rows = malloc( sizeof(*recordset->cache.rows) ); recordset->max_records = 0; - VariantInit( &recordset->filter ); recordset->columntypes = NULL; recordset->haccessors = NULL; Fields_create( recordset ); diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index 3cede5c170c..675c5b0dafa 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -221,23 +221,23 @@ static void test_Recordset(void)
VariantInit( &filter ); hr = _Recordset_put_Filter( recordset, filter ); - ok( hr == MAKE_ADO_HRESULT( adErrInvalidArgument ), "got %08lx\n", hr ); + todo_wine ok( hr == MAKE_ADO_HRESULT( adErrInvalidArgument ), "got %08lx\n", hr );
V_VT(&filter) = VT_BSTR; V_BSTR(&filter) = SysAllocString( L"field1 = 1" ); hr = _Recordset_put_Filter( recordset, filter ); - ok( hr == S_OK, "got %08lx\n", hr ); + todo_wine ok( hr == S_OK, "got %08lx\n", hr ); VariantClear(&filter);
V_VT(&filter) = VT_I4; V_I4(&filter) = 0; hr = _Recordset_put_Filter( recordset, filter ); - ok( hr == S_OK, "got %08lx\n", hr ); + todo_wine ok( hr == S_OK, "got %08lx\n", hr );
V_VT(&filter) = VT_I2; V_I2(&filter) = 0; hr = _Recordset_put_Filter( recordset, filter ); - ok( hr == S_OK, "got %08lx\n", hr ); + todo_wine ok( hr == S_OK, "got %08lx\n", hr );
VariantInit( &missing ); hr = _Recordset_AddNew( recordset, missing, missing ); @@ -399,13 +399,13 @@ static void test_Recordset(void) V_VT(&filter) = VT_BSTR; V_BSTR(&filter) = SysAllocString( L"field = 1" ); hr = _Recordset_put_Filter( recordset, filter ); - ok( hr == S_OK, "got %08lx\n", hr ); + todo_wine ok( hr == S_OK, "got %08lx\n", hr ); VariantClear(&filter);
V_VT(&filter) = VT_I4; V_I4(&filter) = 0; hr = _Recordset_put_Filter( recordset, filter ); - ok( hr == S_OK, "got %08lx\n", hr ); + todo_wine ok( hr == S_OK, "got %08lx\n", hr );
count = -1; hr = Fields_get_Count( fields2, &count );
From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/rowset.c | 54 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 6 deletions(-)
diff --git a/dlls/msado15/rowset.c b/dlls/msado15/rowset.c index 6f38d38f212..a75d383cbc7 100644 --- a/dlls/msado15/rowset.c +++ b/dlls/msado15/rowset.c @@ -317,15 +317,57 @@ static HRESULT WINAPI rowset_Compare(IRowsetExactScroll *iface, HCHAPTER hReserv return E_NOTIMPL; }
-static HRESULT WINAPI rowset_GetRowsAt(IRowsetExactScroll *iface, HWATCHREGION hReserved1, - HCHAPTER hReserved2, DBBKMARK cbBookmark, const BYTE *pBookmark, DBROWOFFSET lRowsOffset, - DBROWCOUNT cRows, DBCOUNTITEM *pcRowsObtained, HROW **prghRows) +static HRESULT WINAPI rowset_GetRowsAt(IRowsetExactScroll *iface, HWATCHREGION watchregion, + HCHAPTER chapter, DBBKMARK bookmark_size, const BYTE *bookmark, DBROWOFFSET offset, + DBROWCOUNT count, DBCOUNTITEM *obtained, HROW **rows) { struct rowset *rowset = impl_from_IRowsetExactScroll(iface); + int idx = -1, i, row_count;
- FIXME("%p, %Id, %Id, %Iu, %p, %Id, %Id, %p, %p\n", rowset, hReserved1, hReserved2, - cbBookmark, pBookmark, lRowsOffset, cRows, pcRowsObtained, prghRows); - return E_NOTIMPL; + TRACE("%p, %Id, %Id, %Iu, %p, %Id, %Id, %p, %p\n", rowset, watchregion, chapter, + bookmark_size, bookmark, offset, count, obtained, rows); + + if (!bookmark_size || !bookmark || !obtained || !rows) + return E_INVALIDARG; + *obtained = 0; + + if (watchregion || chapter) + { + FIXME("unsupported arguments\n"); + return E_NOTIMPL; + } + + if (bookmark_size == 1 && bookmark[0] == DBBMK_FIRST) + idx = 0; + else if (bookmark_size == 1 && bookmark[0] == DBBMK_LAST) + idx = rowset->row_cnt ? rowset->row_cnt - 1 : 0; + else if (bookmark_size == sizeof(int)) + idx = *(int*)bookmark - 1; + + if (idx < 0 || (idx && idx >= rowset->row_cnt)) return DB_E_BADBOOKMARK; + + idx += offset; + if (idx < 0 || (idx && idx >= rowset->row_cnt)) return DB_E_BADSTARTPOSITION; + + if (count > 0) row_count = min(rowset->row_cnt - idx, count); + else if (!rowset->row_cnt) row_count = 0; + else row_count = min(idx + 1, -count); + if (!row_count) return count ? DB_S_ENDOFROWSET : S_OK; + + if (!*rows) + { + *rows = CoTaskMemAlloc(sizeof(**rows) * row_count); + if (!*rows) return E_OUTOFMEMORY; + } + + for (i = 0; i < row_count; i++) + { + (*rows)[i] = idx + 1; + idx += (count > 0 ? 1 : -1); + } + + *obtained = row_count; + return row_count == count || row_count == -count ? S_OK : DB_S_ENDOFROWSET; }
static HRESULT WINAPI rowset_GetRowsByBookmark(IRowsetExactScroll *iface, HCHAPTER hReserved,
From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/rowset.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-)
diff --git a/dlls/msado15/rowset.c b/dlls/msado15/rowset.c index a75d383cbc7..1d6fe4e54da 100644 --- a/dlls/msado15/rowset.c +++ b/dlls/msado15/rowset.c @@ -594,17 +594,6 @@ static HRESULT WINAPI rowset_change_SetData(IRowsetChange *iface, HROW row, HACC if (rowset->columns[accessor->bindings[i].iOrdinal].wType != DBTYPE_VARIANT) FIXME("convert data to column type\n");
- if (idx > rowset->data_cnt) - { - size_t size = max(max(rowset->data_cnt, idx), 8); - VARIANT *data = realloc(rowset->data, size * sizeof(*rowset->data)); - - if (!data) return E_OUTOFMEMORY; - memset(data + rowset->data_cnt, 0, (size - rowset->data_cnt) * sizeof(*rowset->data)); - rowset->data = data; - rowset->data_cnt = size; - } - len = sizeof(VARIANT); status = DBSTATUS_S_OK; if (accessor->bindings[i].cbMaxLen < len) @@ -640,6 +629,7 @@ static HRESULT WINAPI rowset_change_InsertRow(IRowsetChange *iface, HCHAPTER res HACCESSOR accessor, void *data, HROW *row) { struct rowset *rowset = impl_from_IRowsetChange(iface); + int idx, size;
TRACE("%p, %Iu, %Id, %p, %p\n", rowset, reserved, accessor, data, row);
@@ -649,7 +639,26 @@ static HRESULT WINAPI rowset_change_InsertRow(IRowsetChange *iface, HCHAPTER res return E_NOTIMPL; }
+ idx = rowset->row_cnt * rowset->columns_cnt; + size = idx + rowset->columns_cnt; + if (size > rowset->data_cnt) + { + VARIANT *tmp; + + size = max(size, rowset->data_cnt * 2); + size = max(size, 8 * rowset->columns_cnt); + tmp = realloc(rowset->data, size * sizeof(*rowset->data)); + if (!tmp) return E_OUTOFMEMORY; + + memset(tmp + rowset->data_cnt, 0, (size - rowset->data_cnt) * sizeof(*rowset->data)); + rowset->data = tmp; + rowset->data_cnt = size; + } + rowset->row_cnt++; + V_VT(&rowset->data[idx]) = VT_I4; + V_I4(&rowset->data[idx]) = rowset->row_cnt; + if (row) *row = rowset->row_cnt; return S_OK; }
From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/rowset.c | 47 ++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 14 deletions(-)
diff --git a/dlls/msado15/rowset.c b/dlls/msado15/rowset.c index 1d6fe4e54da..ba82d1d3b31 100644 --- a/dlls/msado15/rowset.c +++ b/dlls/msado15/rowset.c @@ -183,20 +183,19 @@ static HRESULT WINAPI rowset_GetData(IRowsetExactScroll *iface, HROW row, HACCES struct accessor *accessor = (struct accessor *)hacc; DBSTATUS status = DBSTATUS_S_OK; BOOL succ = FALSE, err = FALSE; + HRESULT hr = S_OK; DBLENGTH len; - VARIANT val; - HRESULT hr; int i, idx;
TRACE("%p, %Id, %Id, %p\n", rowset, row, hacc, data);
if (!accessor->bindings_count) return DB_E_BADACCESSORTYPE; - if (row > rowset->row_cnt) return DB_E_BADROWHANDLE; + if (row < 1 || row > rowset->row_cnt) return DB_E_BADROWHANDLE; for (i = 0; i < accessor->bindings_count; i++) { - if (accessor->bindings[i].wType != DBTYPE_VARIANT) + if (accessor->bindings[i].dwMemOwner != DBMEMOWNER_CLIENTOWNED) { - FIXME("data conversion not implemented\n"); + FIXME("dwMemOwner = %lx\n", accessor->bindings[i].dwMemOwner); return E_NOTIMPL; } } @@ -204,21 +203,41 @@ static HRESULT WINAPI rowset_GetData(IRowsetExactScroll *iface, HROW row, HACCES for (i = 0; i < accessor->bindings_count; i++) { idx = (row - 1) * rowset->columns_cnt + accessor->bindings[i].iOrdinal; - - len = sizeof(val); status = DBSTATUS_S_OK; + len = 0; + + if (accessor->bindings[i].wType != DBTYPE_VARIANT) + { + hr = IDataConvert_GetConversionSize(rowset->convert, DBTYPE_VARIANT, + accessor->bindings[i].wType, NULL, &len, &rowset->data[idx]); + if (FAILED(hr)) status = DBSTATUS_E_CANTCONVERTVALUE; + } + else len = sizeof(VARIANT); + + if (status != DBSTATUS_S_OK) {} if (accessor->bindings[i].cbMaxLen < len) status = DBSTATUS_E_DATAOVERFLOW; + else if (!(accessor->bindings[i].dwPart & DBPART_VALUE)) + status = DBSTATUS_E_BADACCESSOR; + else if (accessor->bindings[i].wType != DBTYPE_VARIANT) + { + hr = IDataConvert_DataConvert(rowset->convert, DBTYPE_VARIANT, + accessor->bindings[i].wType, sizeof(VARIANT), NULL, + &rowset->data[idx], (BYTE *)data + accessor->bindings[i].obValue, + accessor->bindings[i].cbMaxLen, DBSTATUS_S_OK, &status, + accessor->bindings[i].bPrecision, accessor->bindings[i].bScale, 0); + if (FAILED(hr) && status == DBSTATUS_S_OK) + status = DBSTATUS_E_CANTCONVERTVALUE; + } else { - VariantInit(&val); - if (idx < rowset->data_cnt) - { - hr = VariantCopy(&val, &rowset->data[idx]); - if (FAILED(hr)) return hr; - } + VARIANT val;
- if (accessor->bindings[i].dwPart & DBPART_VALUE && status == DBSTATUS_S_OK) + VariantInit(&val); + hr = VariantCopy(&val, &rowset->data[idx]); + if (FAILED(hr)) + status = DBSTATUS_E_CANTCONVERTVALUE; + else memcpy((BYTE *)data + accessor->bindings[i].obValue, &val, sizeof(val)); }
From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/recordset.c | 241 ++++++++++++++++++++++++++++++++--- dlls/msado15/tests/msado15.c | 56 ++++---- 2 files changed, 246 insertions(+), 51 deletions(-)
diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index d303b6d3c47..d37b37dbdd7 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -18,12 +18,14 @@
#include <stdarg.h> #include <assert.h> +#include <math.h> #include "windef.h" #include "winbase.h" #define COBJMACROS #include "objbase.h" #include "msado15_backcompat.h" #include "oledb.h" +#include "oledberr.h" #include "sqlucode.h"
#include "wine/debug.h" @@ -68,6 +70,17 @@ struct fields ULONG allocated; };
+struct bookmark_data +{ + union + { + int i; + SAFEARRAY *sa; + } val; + DBLENGTH len; + DBSTATUS status; +}; + struct recordset { _Recordset Recordset_iface; @@ -84,6 +97,7 @@ struct recordset CursorLocationEnum cursor_location; CursorTypeEnum cursor_type; IRowset *row_set; + IRowsetLocate *rowset_locate; IRowsetExactScroll *rowset_es; IRowsetChange *rowset_change; IAccessor *accessor; @@ -95,7 +109,7 @@ struct recordset LONG alloc; LONG size; LONG fetched; - BOOL forward; + int dir; LONG pos; HROW *rows; } cache; @@ -105,6 +119,10 @@ struct recordset
DBTYPE *columntypes; HACCESSOR hacc_empty; /* haccessor for adding empty rows */ + + HACCESSOR bookmark_hacc; + DBTYPE bookmark_type; + VARIANT bookmark; HACCESSOR *haccessors; };
@@ -136,20 +154,47 @@ static void cache_release( struct recordset *recordset ) IRowset_ReleaseRows( recordset->row_set, recordset->cache.fetched, recordset->cache.rows, NULL, NULL, NULL ); recordset->cache.fetched = 0; + recordset->cache.dir = 0; recordset->cache.pos = 0; recordset->current_row = DB_NULL_HROW; }
+static HRESULT get_bookmark( struct recordset *recordset, HROW row, VARIANT *bookmark ) +{ + struct bookmark_data bookmark_data = { 0 }; + HRESULT hr; + + hr = IRowset_GetData(recordset->row_set, row, recordset->bookmark_hacc, &bookmark_data); + if (FAILED(hr)) return hr; + + if (recordset->bookmark_type == DBTYPE_I4) + { + V_VT(bookmark) = VT_R8; + V_R8(bookmark) = bookmark_data.val.i; + return S_OK; + } + + V_VT(bookmark) = VT_ARRAY | VT_UI1; + V_ARRAY(bookmark) = bookmark_data.val.sa; + return S_OK; +} + static HRESULT cache_get( struct recordset *recordset, BOOL forward ) { int dir = forward ? 1 : -1; LONG off, fetch = 0;
- if (!forward == !recordset->cache.forward) + if (!recordset->cache.dir) + { + off = 0; + fetch = dir * recordset->cache.size; + } + else if (recordset->cache.dir == dir) { if (recordset->cache.pos + 1 > recordset->cache.fetched) { off = 0; + if (recordset->bookmark_hacc) off += dir; fetch = dir * recordset->cache.size; } } @@ -176,7 +221,81 @@ static HRESULT cache_get( struct recordset *recordset, BOOL forward ) cache_release( recordset ); recordset->current_row = row;
- hr = IRowset_GetNextRows(recordset->row_set, 0, off, fetch, &count, &recordset->cache.rows); + if (recordset->bookmark_hacc) + { + const BYTE *data; + BYTE byte_buf; + DBBKMARK len; + int int_buf; + + if (V_VT(&recordset->bookmark) == VT_R8) + { + if (isinf(V_R8(&recordset->bookmark))) + { + data = (BYTE *)&byte_buf; + if (V_R8(&recordset->bookmark) < 0) + { + byte_buf = DBBMK_FIRST; + if (!forward) off -= 2; + } + else + { + byte_buf = DBBMK_LAST; + if (forward) off += 2; + } + len = sizeof(byte_buf); + } + else + { + data = (BYTE *)&int_buf; + int_buf = V_R8(&recordset->bookmark); + len = sizeof(int_buf); + } + } + else + { + hr = SafeArrayLock(V_ARRAY(&recordset->bookmark)); + if (FAILED(hr)) return hr; + data = V_ARRAY(&recordset->bookmark)->pvData; + len = V_ARRAY(&recordset->bookmark)->rgsabound[0].cElements; + } + + hr = IRowsetLocate_GetRowsAt(recordset->rowset_locate, 0, 0, len, data, + off, fetch, &count, &recordset->cache.rows); + if (V_VT(&recordset->bookmark) & VT_ARRAY) + SafeArrayUnlock(V_ARRAY(&recordset->bookmark)); + + if (hr == DB_E_BADSTARTPOSITION) + { + count = 0; + hr = S_OK; + } + else if (hr == DB_S_ENDOFROWSET) + { + VariantClear(&recordset->bookmark); + V_VT(&recordset->bookmark) = VT_R8; + V_R8(&recordset->bookmark) = dir * INFINITY; + } + else if (SUCCEEDED(hr)) + { + VARIANT tmp; + + hr = get_bookmark(recordset, recordset->cache.rows[count - 1], &tmp); + if (FAILED(hr)) + { + cache_release( recordset ); + recordset->current_row = row; + return hr; + } + + VariantClear(&recordset->bookmark); + recordset->bookmark = tmp; + } + } + else + { + hr = IRowset_GetNextRows(recordset->row_set, 0, off, fetch, &count, &recordset->cache.rows); + } if (FAILED(hr)) return hr;
if (recordset->current_row) @@ -204,11 +323,11 @@ static HRESULT cache_get( struct recordset *recordset, BOOL forward )
recordset->cache.pos = 0; recordset->cache.fetched = count; - recordset->cache.forward = forward; + recordset->cache.dir = dir; }
recordset->is_bof = recordset->is_eof = VARIANT_FALSE; - if (!forward == !recordset->cache.forward) + if (dir == recordset->cache.dir) recordset->current_row = recordset->cache.rows[recordset->cache.pos++]; else recordset->current_row = recordset->cache.rows[--recordset->cache.pos]; @@ -1506,8 +1625,18 @@ static void close_recordset( struct recordset *recordset ) recordset->hacc_empty = 0; }
+ if (recordset->bookmark_hacc) + { + IAccessor_ReleaseAccessor( recordset->accessor, recordset->bookmark_hacc, NULL ); + recordset->bookmark_hacc = 0; + } + VariantClear( &recordset->bookmark ); + if ( recordset->row_set ) IRowset_Release( recordset->row_set ); recordset->row_set = NULL; + if ( recordset->rowset_locate ) + IRowsetLocate_Release( recordset->rowset_locate ); + recordset->rowset_locate = NULL; if ( recordset->rowset_es && recordset->rowset_es != NO_INTERFACE ) IRowsetExactScroll_Release( recordset->rowset_es ); recordset->rowset_es = NULL; @@ -2158,11 +2287,21 @@ static HRESULT WINAPI recordset_MoveFirst( _Recordset *iface )
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; + if (recordset->bookmark_hacc) + { + VariantClear( &recordset->bookmark ); + V_VT( &recordset->bookmark ) = VT_R8; + V_R8( &recordset->bookmark ) = -INFINITY; + recordset->cache.dir = 0; + } + else + { + 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;
@@ -2179,11 +2318,21 @@ static HRESULT WINAPI recordset_MoveLast( _Recordset *iface )
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; + if (recordset->bookmark_hacc) + { + VariantClear( &recordset->bookmark ); + V_VT( &recordset->bookmark ) = VT_R8; + V_R8( &recordset->bookmark ) = INFINITY; + recordset->cache.dir = 0; + } + else + { + 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;
@@ -3267,6 +3416,64 @@ static HRESULT WINAPI rsconstruction_get_Rowset(ADORecordsetConstruction *iface, return S_OK; }
+static void init_bookmark( struct recordset *recordset ) +{ + DBCOLUMNINFO *colinfo = NULL; + OLECHAR *strbuf = NULL; + DBORDINAL i, columns; + IColumnsInfo *info; + HRESULT hr; + + hr = IRowset_QueryInterface( recordset->row_set, &IID_IColumnsInfo, (void **)&info ); + if (FAILED(hr) || !info) return; + + 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; + + hr = IColumnsInfo_GetColumnInfo( info, &columns, &colinfo, &strbuf ); + IColumnsInfo_Release( info ); + if (FAILED(hr)) return; + CoTaskMemFree( strbuf ); + + for (i = 0; i < columns; i++) + { + if (colinfo[i].dwFlags & DBCOLUMNFLAGS_ISBOOKMARK) + { + DBBINDING binding; + + if (colinfo[i].ulColumnSize == sizeof(int)) + recordset->bookmark_type = DBTYPE_I4; + else + recordset->bookmark_type = DBTYPE_ARRAY | DBTYPE_UI1; + + memset(&binding, 0, sizeof(binding)); + binding.iOrdinal = colinfo[i].iOrdinal; + 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 = recordset->bookmark_type == DBTYPE_I4 ? sizeof(int) : sizeof(SAFEARRAY *); + binding.wType = recordset->bookmark_type; + binding.bPrecision = colinfo[i].bPrecision; + binding.bScale = colinfo[i].bScale; + hr = IAccessor_CreateAccessor( recordset->accessor, DBACCESSOR_ROWDATA, + 1, &binding, 0, &recordset->bookmark_hacc, NULL ); + if (FAILED(hr)) return; + + V_VT(&recordset->bookmark) = VT_R8; + V_R8(&recordset->bookmark) = -INFINITY; + return; + } + } + + CoTaskMemFree( colinfo ); +} + static HRESULT WINAPI rsconstruction_put_Rowset(ADORecordsetConstruction *iface, IUnknown *unk) { struct recordset *recordset = impl_from_ADORecordsetConstruction( iface ); @@ -3277,13 +3484,13 @@ static HRESULT WINAPI rsconstruction_put_Rowset(ADORecordsetConstruction *iface,
if (recordset->state == adStateOpen) return MAKE_ADO_HRESULT( adErrObjectOpen );
- hr = IUnknown_QueryInterface(unk, &IID_IRowset, (void**)&rowset); + hr = IUnknown_QueryInterface( unk, &IID_IRowset, (void**)&rowset ); if ( FAILED(hr) ) return E_FAIL; - - if ( recordset->row_set ) IRowset_Release( recordset->row_set ); recordset->row_set = rowset; - recordset->state = adStateOpen; + + hr = IRowset_QueryInterface( rowset, &IID_IRowsetLocate, (void**)&recordset->rowset_locate ); + if (SUCCEEDED(hr)) init_bookmark( recordset ); return S_OK; }
diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index 675c5b0dafa..039b71040db 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -923,6 +923,7 @@ static HRESULT WINAPI accessor_CreateAccessor(IAccessor *iface, DBACCESSORFLAGS return S_OK; }
+ ok(rgBindings[0].dwMemOwner == DBMEMOWNER_CLIENTOWNED, "dwMemOwner = %lx\n", rgBindings[0].dwMemOwner); haccessor = malloc(sizeof(*haccessor)); haccessor->ref = 1; haccessor->binding = rgBindings[0]; @@ -1183,10 +1184,10 @@ static HRESULT WINAPI rowset_GetRowsAt(IRowsetExactScroll *iface, HWATCHREGION h }
ok(cbBookmark == sizeof(int), "cbBookmark = %Id\n", cbBookmark); - ok(lRowsOffset == 1, "lRowsOffset = %Id\n", lRowsOffset); + ok(!lRowsOffset || lRowsOffset == 1, "lRowsOffset = %Id\n", lRowsOffset);
row = *(int *)pBookmark + lRowsOffset; - ok(row > 1 && row <= 3, "row = %d\n", row); + ok(row >= 1 && row <= 3, "row = %d\n", row); if (row == 3) { *pcRowsObtained = 0; @@ -1323,13 +1324,13 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) todo_wine CHECK_CALLED( rowset_QI_IRowsetChange ); todo_wine CHECK_CALLED( rowset_QI_IRowsetUpdate ); todo_wine CHECK_CALLED( rowset_QI_IRowsetFind ); - todo_wine CHECK_CALLED( rowset_QI_IRowsetExactScroll ); + CHECK_CALLED( rowset_QI_IRowsetExactScroll ); if (exact_scroll) { - todo_wine CHECK_CALLED( rowset_QI_IColumnsInfo ); - todo_wine CHECK_CALLED( column_info_GetColumnInfo ); - todo_wine CHECK_CALLED( rowset_QI_IAccessor ); - todo_wine CHECK_CALLED( accessor_CreateAccessor ); + CHECK_CALLED( rowset_QI_IColumnsInfo ); + CHECK_CALLED( column_info_GetColumnInfo ); + CHECK_CALLED( rowset_QI_IAccessor ); + CHECK_CALLED( accessor_CreateAccessor ); } todo_wine CHECK_CALLED( rowset_QI_IDBAsynchStatus ); ok( hr == S_OK, "got %08lx\n", hr ); @@ -1371,20 +1372,16 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) ok( hr == S_OK, "got %08lx\n", hr ); ok( scale == 1, "got %u\n", scale );
- SET_EXPECT( rowset_GetNextRows ); - if (exact_scroll) SET_EXPECT( rowset_GetRowsAt ); + if (!exact_scroll) SET_EXPECT( rowset_GetNextRows ); + else SET_EXPECT( rowset_GetRowsAt ); SET_EXPECT( rowset_QI_IAccessor ); SET_EXPECT( accessor_CreateAccessor ); SET_EXPECT( rowset_GetData ); hr = Field_get_Value( field, &v ); ok( hr == S_OK, "got %08lx\n", hr ); if (!exact_scroll) CHECK_CALLED( rowset_GetNextRows ); - else - { - todo_wine CHECK_NOT_CALLED( rowset_GetNextRows ); - todo_wine CHECK_CALLED( rowset_GetRowsAt ); - } - CHECK_CALLED( rowset_QI_IAccessor ); + else CHECK_CALLED( rowset_GetRowsAt ); + todo_wine_if(exact_scroll) CHECK_CALLED( rowset_QI_IAccessor ); CHECK_CALLED( accessor_CreateAccessor ); CHECK_CALLED( rowset_GetData ); ok( V_VT(&v) == VT_I4, "V_VT(&v) = %d\n", V_VT(&v) ); @@ -1418,8 +1415,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 );
- SET_EXPECT( rowset_GetNextRows ); - if (exact_scroll) + if (!exact_scroll) SET_EXPECT( rowset_GetNextRows ); + else { SET_EXPECT( rowset_GetRowsAt ); SET_EXPECT( rowset_GetData ); @@ -1430,9 +1427,8 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) 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 ); + CHECK_CALLED( rowset_GetRowsAt ); + CHECK_CALLED( rowset_GetData ); } CHECK_CALLED( rowset_AddRefRows ); CHECK_CALLED( rowset_ReleaseRows ); @@ -1441,29 +1437,21 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll)
SET_EXPECT( rowset_AddRefRows ); SET_EXPECT( rowset_ReleaseRows ); - SET_EXPECT( rowset_GetNextRows ); - if (exact_scroll) SET_EXPECT( rowset_GetRowsAt ); + if (!exact_scroll) SET_EXPECT( rowset_GetNextRows ); + else SET_EXPECT( rowset_GetRowsAt ); hr = _Recordset_MoveNext( recordset ); 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 ); - } + else CHECK_CALLED( rowset_GetRowsAt ); ok( hr == S_OK, "got %08lx\n", hr ); ok( is_eof( recordset ), "unexpected records\n" );
- SET_EXPECT( rowset_GetNextRows ); - if (exact_scroll) SET_EXPECT( rowset_GetRowsAt ); + if (!exact_scroll) SET_EXPECT( rowset_GetNextRows ); + else SET_EXPECT( rowset_GetRowsAt ); hr = _Recordset_MoveNext( recordset ); if (!exact_scroll) CHECK_CALLED( rowset_GetNextRows ); - else - { - todo_wine CHECK_NOT_CALLED( rowset_GetNextRows ); - todo_wine CHECK_CALLED( rowset_GetRowsAt ); - } + else CHECK_CALLED( rowset_GetRowsAt ); ok( hr == MAKE_ADO_HRESULT(adErrNoCurrentRecord), "got %08lx\n", hr );
V_VT( &missing ) = VT_ERROR;
From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/recordset.c | 31 ++++++++++++++++++++++++------- dlls/msado15/tests/msado15.c | 26 ++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 7 deletions(-)
diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index d37b37dbdd7..b3498246c46 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -1903,27 +1903,44 @@ static HRESULT WINAPI recordset_get_BOF( _Recordset *iface, VARIANT_BOOL *bof ) static HRESULT WINAPI recordset_get_Bookmark( _Recordset *iface, VARIANT *bookmark ) { struct recordset *recordset = impl_from_Recordset( iface ); + TRACE( "%p, %p\n", iface, bookmark );
if (recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed ); - if (recordset->index < 0) return MAKE_ADO_HRESULT( adErrNoCurrentRecord ); + if (!recordset->current_row && !recordset->is_eof && !recordset->is_bof) + { + HRESULT hr = cache_get( recordset, TRUE ); + if (FAILED(hr)) return hr; + } + if (!recordset->current_row) return MAKE_ADO_HRESULT( adErrNoCurrentRecord ); + if (!recordset->bookmark_hacc) + return MAKE_ADO_HRESULT( adErrFeatureNotAvailable );
- V_VT(bookmark) = VT_I4; - V_I4(bookmark) = recordset->index; - return S_OK; + return get_bookmark( recordset, recordset->current_row, bookmark ); }
static HRESULT WINAPI recordset_put_Bookmark( _Recordset *iface, VARIANT bookmark ) { struct recordset *recordset = impl_from_Recordset( iface ); + VARIANT copy; + HRESULT hr; + TRACE( "%p, %s\n", iface, debugstr_variant(&bookmark) );
if (recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed ); + if (V_VT(&bookmark) != VT_R8 && V_VT(&bookmark) != (VT_ARRAY | VT_UI1)) + return MAKE_ADO_HRESULT( adErrInvalidArgument ); + if (!recordset->bookmark_hacc) + return MAKE_ADO_HRESULT( adErrFeatureNotAvailable );
- if (V_VT(&bookmark) != VT_I4) return MAKE_ADO_HRESULT( adErrInvalidArgument ); + VariantInit( © ); + hr = VariantCopy( ©, &bookmark ); + if (FAILED(hr)) return hr;
- recordset->index = V_I4(&bookmark); - return S_OK; + VariantClear( &recordset->bookmark ); + recordset->bookmark = copy; + recordset->cache.dir = 0; + return cache_get( recordset, TRUE ); }
static HRESULT WINAPI recordset_get_CacheSize( _Recordset *iface, LONG *size ) diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index 039b71040db..345e17001f8 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -1407,6 +1407,32 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll)
Field_Release( field );
+ if (exact_scroll) SET_EXPECT( rowset_GetData ); + VariantInit(&v); + hr = _Recordset_get_Bookmark( recordset, &v ); + if (exact_scroll) + { + ok( hr == S_OK, "got %08lx\n", hr ); + CHECK_CALLED( rowset_GetData ); + ok( V_VT(&v) == VT_R8, "V_VT(v) = %x\n", V_VT(&v) ); + ok( V_R8(&v) == 1.0, "V_R8(v) = %lf\n", V_R8(&v) ); + } + else ok( hr == MAKE_ADO_HRESULT( adErrFeatureNotAvailable ), "got %08lx\n", hr ); + + if (exact_scroll) + { + SET_EXPECT( rowset_AddRefRows ); + SET_EXPECT( rowset_ReleaseRows ); + SET_EXPECT( rowset_GetRowsAt ); + SET_EXPECT( rowset_GetData ); + hr = _Recordset_put_Bookmark( recordset, v ); + ok( hr == S_OK, "hr = %lx\n", hr ); + CHECK_CALLED( rowset_AddRefRows ); + CHECK_CALLED( rowset_ReleaseRows ); + CHECK_CALLED( rowset_GetRowsAt ); + CHECK_CALLED( rowset_GetData ); + } + SET_EXPECT( rowset_QI_IRowsetExactScroll ); if (exact_scroll) SET_EXPECT( rowset_GetExactPosition ); hr = _Recordset_get_RecordCount( recordset, &size );
From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/tests/msado15.c | 63 ++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 9 deletions(-)
diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index 345e17001f8..e960d0fa037 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -84,6 +84,7 @@ DEFINE_EXPECT(rowset_ReleaseRows); DEFINE_EXPECT(rowset_GetRowsAt); DEFINE_EXPECT(rowset_GetExactPosition); DEFINE_EXPECT(rowset_GetData); +DEFINE_EXPECT(rowset_RestartPosition); DEFINE_EXPECT(rowset_change_SetData); DEFINE_EXPECT(rowset_change_InsertRow); DEFINE_EXPECT(accessor_AddRefAccessor); @@ -1119,16 +1120,17 @@ static HRESULT WINAPI rowset_GetNextRows(IRowsetExactScroll *iface, HCHAPTER hRe ok(pcRowObtained != NULL, "pcRowObtained = NULL\n"); ok(prghRows != NULL, "prghRows = NULL\n"); ok(*prghRows != NULL, "*prghRows = NULL\n"); + ok(lRowsOffset >= -1 && lRowsOffset <= 1, "lRowsOffset = %Id\n", lRowsOffset);
- if (rowset->idx == 2) + if ((cRows > 0 && rowset->idx + lRowsOffset >= 2) || (cRows < 0 && rowset->idx + lRowsOffset <= 0)) { *pcRowObtained = 0; return DB_S_ENDOFROWSET; }
- ok(!lRowsOffset, "lRowsOffset = %Id\n", lRowsOffset); *pcRowObtained = 1; - (*prghRows)[0] = ++rowset->idx; + rowset->idx += lRowsOffset; + (*prghRows)[0] = cRows > 0 ? ++rowset->idx : --rowset->idx; return S_OK; }
@@ -1141,8 +1143,13 @@ static HRESULT WINAPI rowset_ReleaseRows(IRowsetExactScroll *iface, DBCOUNTITEM
static HRESULT WINAPI rowset_RestartPosition(IRowsetExactScroll *iface, HCHAPTER hReserved) { - ok(0, "Unexpected call\n"); - return E_NOTIMPL; + struct test_rowset *rowset = impl_from_IRowsetExactScroll( iface ); + + CHECK_EXPECT(rowset_RestartPosition); + ok(!hReserved, "hReserved = %Ix\n", hReserved); + + rowset->idx = 0; + return S_OK; }
static HRESULT WINAPI rowset_Compare(IRowsetExactScroll *iface, HCHAPTER hReserved, DBBKMARK cbBookmark1, @@ -1161,7 +1168,7 @@ static HRESULT WINAPI rowset_GetRowsAt(IRowsetExactScroll *iface, HWATCHREGION h CHECK_EXPECT2(rowset_GetRowsAt); ok(!hReserved1, "hReserved1 = %Ix\n", hReserved1); ok(!hReserved2, "hReserved2 = %Ix\n", hReserved2); - ok(cRows == 1, "cRows = %Id\n", cRows); + ok(cRows == -1 || cRows == 1, "cRows = %Id\n", cRows); ok(pcRowsObtained != NULL, "pcRowsObtained == NULL\n"); ok(prghRows != NULL, "prghRows == NULL\n"); ok(*prghRows != NULL, "*prghRows == NULL\n"); @@ -1184,11 +1191,11 @@ static HRESULT WINAPI rowset_GetRowsAt(IRowsetExactScroll *iface, HWATCHREGION h }
ok(cbBookmark == sizeof(int), "cbBookmark = %Id\n", cbBookmark); - ok(!lRowsOffset || lRowsOffset == 1, "lRowsOffset = %Id\n", lRowsOffset); + ok(lRowsOffset >= -1 && lRowsOffset <= 1, "lRowsOffset = %Id\n", lRowsOffset);
row = *(int *)pBookmark + lRowsOffset; - ok(row >= 1 && row <= 3, "row = %d\n", row); - if (row == 3) + ok(row >= 0 && row <= 3, "row = %d\n", row); + if (!row || row == 3) { *pcRowsObtained = 0; return DB_S_ENDOFROWSET; @@ -1480,6 +1487,44 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) else CHECK_CALLED( rowset_GetRowsAt ); ok( hr == MAKE_ADO_HRESULT(adErrNoCurrentRecord), "got %08lx\n", hr );
+ if (!exact_scroll) + { + SET_EXPECT( rowset_RestartPosition ); + SET_EXPECT( rowset_GetNextRows ); + } + else + { + SET_EXPECT( rowset_GetRowsAt ); + SET_EXPECT( rowset_GetData ); + } + hr = _Recordset_MoveFirst( recordset ); + ok( hr == S_OK, "got %08lx\n", hr); + if (!exact_scroll) + { + CHECK_CALLED( rowset_RestartPosition ); + CHECK_CALLED( rowset_GetNextRows ); + } + else + { + CHECK_CALLED( rowset_GetRowsAt ); + CHECK_CALLED( rowset_GetData ); + } + ok( !is_bof( recordset ), "at bof\n" ); + 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 ); + hr = _Recordset_MovePrevious( recordset ); + ok( hr == S_OK, "got %08lx\n", hr ); + CHECK_CALLED( rowset_AddRefRows ); + CHECK_CALLED( rowset_ReleaseRows ); + if (!exact_scroll) CHECK_CALLED( rowset_GetNextRows ); + else CHECK_CALLED( rowset_GetRowsAt ); + ok( is_bof( recordset ), "not at bof\n" ); + ok( !is_eof( recordset ), "at eof\n" ); + V_VT( &missing ) = VT_ERROR; V_ERROR( &missing ) = DISP_E_PARAMNOTFOUND; SET_EXPECT(rowset_QI_IAccessor);
From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/recordset.c | 471 +-------------------------------------- 1 file changed, 10 insertions(+), 461 deletions(-)
diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index b3498246c46..f3cf3a66ab9 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -90,10 +90,6 @@ struct recordset _Connection *active_connection; LONG state; struct fields fields; - LONG count; - LONG allocated; - LONG index; - VARIANT *data; CursorLocationEnum cursor_location; CursorTypeEnum cursor_type; IRowset *row_set; @@ -117,13 +113,11 @@ struct recordset VARIANT_BOOL is_eof; ADO_LONGPTR max_records;
- DBTYPE *columntypes; HACCESSOR hacc_empty; /* haccessor for adding empty rows */
HACCESSOR bookmark_hacc; DBTYPE bookmark_type; VARIANT bookmark; - HACCESSOR *haccessors; };
static inline struct field *impl_from_Field( Field *iface ) @@ -497,11 +491,6 @@ static HRESULT WINAPI field_get_Type( Field *iface, DataTypeEnum *type ) return S_OK; }
-static LONG get_column_count( struct recordset *recordset ) -{ - return recordset->fields.count == -1 ? 0 : recordset->fields.count; -} - static HRESULT WINAPI field_get_Value( Field *iface, VARIANT *val ) { struct field *field = impl_from_Field( iface ); @@ -1610,12 +1599,7 @@ static ULONG WINAPI recordset_AddRef( _Recordset *iface )
static void close_recordset( struct recordset *recordset ) { - ULONG row, col, col_count; ULONG i; - IAccessor *accessor; - - if (recordset->haccessors) - IRowset_QueryInterface(recordset->row_set, &IID_IAccessor, (void**)&accessor);
cache_release( recordset ); recordset->is_bof = recordset->is_eof = VARIANT_FALSE; @@ -1644,11 +1628,7 @@ static void close_recordset( struct recordset *recordset ) IRowsetChange_Release( recordset->rowset_change ); recordset->rowset_change = NULL;
- col_count = get_column_count( recordset ); - - free(recordset->columntypes); - - for (i = 0; i < col_count; i++) + for (i = 0; i < recordset->fields.count; i++) { if (recordset->fields.field[i]->hacc_get) { @@ -1663,29 +1643,12 @@ static void close_recordset( struct recordset *recordset ) recordset->fields.field[i]->recordset = NULL;
Field_Release(&recordset->fields.field[i]->Field_iface); - - if (recordset->haccessors) - IAccessor_ReleaseAccessor(accessor, recordset->haccessors[i], NULL); } + recordset->fields.count = -1;
if (recordset->accessor && recordset->accessor != NO_INTERFACE ) IAccessor_Release( recordset->accessor ); recordset->accessor = NULL; - - if (recordset->haccessors) - { - IAccessor_Release(accessor); - free(recordset->haccessors); - recordset->haccessors = NULL; - } - recordset->fields.count = -1; - - for (row = 0; row < recordset->count; row++) - for (col = 0; col < col_count; col++) VariantClear( &recordset->data[row * col_count + col] ); - - recordset->count = recordset->allocated = recordset->index = 0; - free( recordset->data ); - recordset->data = NULL; }
static ULONG WINAPI recordset_Release( _Recordset *iface ) @@ -2133,24 +2096,6 @@ static HRESULT WINAPI recordset_get_Source( _Recordset *iface, VARIANT *source ) return E_NOTIMPL; }
-static BOOL resize_recordset( struct recordset *recordset, ULONG row_count ) -{ - ULONG row_size = get_column_count( recordset ) * sizeof(*recordset->data); - - if (row_count > recordset->allocated) - { - VARIANT *tmp; - ULONG count = max( row_count, recordset->allocated * 2 ); - if (!(tmp = realloc( recordset->data, count * row_size ))) return FALSE; - memset( (BYTE*)tmp + recordset->allocated * row_size, 0, (count - recordset->allocated) * row_size ); - recordset->data = tmp; - recordset->allocated = count; - } - - recordset->count = row_count; - return TRUE; -} - static HRESULT WINAPI recordset_AddNew( _Recordset *iface, VARIANT field_list, VARIANT values ) { struct recordset *recordset = impl_from_Recordset( iface ); @@ -2201,8 +2146,6 @@ static HRESULT WINAPI recordset_AddNew( _Recordset *iface, VARIANT field_list, V return MAKE_ADO_HRESULT( adErrNoCurrentRecord ); recordset->is_bof = recordset->is_eof = FALSE;
- if (!resize_recordset( recordset, recordset->count + 1 )) return E_OUTOFMEMORY; - recordset->index = recordset->count - 1; recordset->editmode = adEditAdd; return S_OK; } @@ -2254,7 +2197,6 @@ 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 );
@@ -2262,21 +2204,16 @@ static HRESULT WINAPI recordset_MoveNext( _Recordset *iface )
if (!recordset->current_row && !recordset->is_eof && !recordset->is_bof) { - hr = cache_get( recordset, TRUE ); + HRESULT 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; + return cache_get( recordset, TRUE ); }
static HRESULT WINAPI recordset_MovePrevious( _Recordset *iface ) { struct recordset *recordset = impl_from_Recordset( iface ); - HRESULT hr;
TRACE( "%p\n", recordset );
@@ -2284,15 +2221,11 @@ static HRESULT WINAPI recordset_MovePrevious( _Recordset *iface )
if (!recordset->current_row && !recordset->is_eof && !recordset->is_bof) { - hr = cache_get( recordset, TRUE ); + HRESULT 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; + return cache_get( recordset, FALSE ); }
static HRESULT WINAPI recordset_MoveFirst( _Recordset *iface ) @@ -2319,11 +2252,7 @@ static HRESULT WINAPI recordset_MoveFirst( _Recordset *iface ) }
recordset->is_bof = recordset->is_eof = VARIANT_FALSE; - hr = cache_get( recordset, TRUE ); - if (FAILED(hr)) return hr; - - recordset->index = 0; - return S_OK; + return cache_get( recordset, TRUE ); }
static HRESULT WINAPI recordset_MoveLast( _Recordset *iface ) @@ -2350,11 +2279,7 @@ static HRESULT WINAPI recordset_MoveLast( _Recordset *iface ) }
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; + return cache_get( recordset, FALSE ); }
static HRESULT get_rowset(struct recordset *recordset, IUnknown *session, BSTR source, IUnknown **rowset) @@ -2407,358 +2332,9 @@ static HRESULT get_rowset(struct recordset *recordset, IUnknown *session, BSTR s
hr = ICommandText_Execute(command_text, NULL, &IID_IUnknown, NULL, &affected, rowset); ICommandText_Release(command_text); - if (FAILED(hr)) - return hr; - - recordset->count = affected > 0 ? affected : 0; - return S_OK; -} - -#define ROUND_SIZE(size) (((size) + sizeof(void *) - 1) & ~(sizeof(void *) - 1)) - -DEFINE_GUID(DBPROPSET_ROWSET, 0xc8b522be, 0x5cf3, 0x11ce, 0xad, 0xe5, 0x00, 0xaa, 0x00, 0x44, 0x77, 0x3d); - -static HRESULT create_bindings(IUnknown *rowset, struct recordset *recordset, DBBINDING **bind, DBBYTEOFFSET *size) -{ - HRESULT hr; - IColumnsInfo *columninfo; - IAccessor *accessor; - DBORDINAL columns; - DBCOLUMNINFO *colinfo; - OLECHAR *stringsbuffer; - DBBINDING *bindings; - DBBYTEOFFSET offset; - - *size = 0; - - hr = IUnknown_QueryInterface(rowset, &IID_IColumnsInfo, (void**)&columninfo); - if (FAILED(hr)) - return hr; - - hr = IUnknown_QueryInterface(rowset, &IID_IAccessor, (void**)&accessor); - if (FAILED(hr)) - { - IColumnsInfo_Release(columninfo); - return hr; - } - - hr = IColumnsInfo_GetColumnInfo(columninfo, &columns, &colinfo, &stringsbuffer); - if (SUCCEEDED(hr)) - { - ULONG i, j; - DBOBJECT *dbobj; - offset = 1; - - recordset->columntypes = malloc(sizeof(DBTYPE) * columns); - recordset->haccessors = calloc(1, sizeof(HACCESSOR) * columns ); - - /* Do one allocation for the bindings and append the DBOBJECTS to the end. - * This is to save on multiple allocations vs a little bit of extra memory. - */ - bindings = CoTaskMemAlloc( (sizeof(DBBINDING) + sizeof(DBOBJECT)) * columns); - dbobj = (DBOBJECT *)((char*)bindings + (sizeof(DBBINDING) * columns)); - - for (i=0, j=0; i < columns; i++) - { - TRACE("Column %lu, pwszName: %s, pTypeInfo %p, iOrdinal %Iu, dwFlags 0x%08lx, " - "ulColumnSize %Iu, wType %d, bPrecision %d, bScale %d\n", - i, debugstr_w(colinfo[i].pwszName), colinfo[i].pTypeInfo, colinfo[i].iOrdinal, - colinfo[i].dwFlags, colinfo[i].ulColumnSize, colinfo[i].wType, - colinfo[i].bPrecision, colinfo[i].bScale); - - if (!colinfo[i].pwszName) - { - FIXME("skipping implicit column\n"); - continue; - } - - hr = append_field(&recordset->fields, &colinfo[i]); - if (FAILED(hr)) WARN("append_field failed: %lx\n", hr); - - bindings[j].iOrdinal = colinfo[i].iOrdinal; - bindings[j].obValue = offset; - bindings[j].pTypeInfo = NULL; - /* Always assigned the pObject even if it's not used. */ - bindings[j].pObject = &dbobj[i]; - bindings[j].pObject->dwFlags = 0; - bindings[j].pObject->iid = IID_ISequentialStream; - bindings[j].pBindExt = NULL; - bindings[j].dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS; - bindings[j].dwMemOwner = DBMEMOWNER_CLIENTOWNED; - bindings[j].eParamIO = 0; - - recordset->columntypes[j] = colinfo[i].wType; - if (colinfo[i].dwFlags & DBCOLUMNFLAGS_ISLONG) - { - colinfo[i].wType = DBTYPE_IUNKNOWN; - - bindings[j].cbMaxLen = (colinfo[i].ulColumnSize + 1) * sizeof(WCHAR); - offset += sizeof(ISequentialStream*); - } - else if(colinfo[i].wType == DBTYPE_WSTR) - { - /* ulColumnSize is the number of characters in the string not the actual buffer size */ - bindings[j].cbMaxLen = colinfo[i].ulColumnSize * sizeof(WCHAR); - offset += bindings[j].cbMaxLen; - } - else - { - bindings[j].cbMaxLen = colinfo[i].ulColumnSize; - offset += bindings[j].cbMaxLen; - } - - bindings[j].dwFlags = 0; - bindings[j].wType = colinfo[i].wType; - bindings[j].bPrecision = colinfo[i].bPrecision; - bindings[j].bScale = colinfo[i].bScale; - j++; - } - - offset = ROUND_SIZE(offset); - for (i=0, j=0; i < columns; i++) - { - if (!colinfo[i].pwszName) - continue; - - bindings[j].obLength = offset; - bindings[j].obStatus = offset + sizeof(DBBYTEOFFSET); - - offset += sizeof(DBBYTEOFFSET) + sizeof(DBBYTEOFFSET); - - hr = IAccessor_CreateAccessor(accessor, DBACCESSOR_ROWDATA, 1, &bindings[j], 0, &recordset->haccessors[j], NULL); - if (FAILED(hr)) - FIXME("IAccessor_CreateAccessor Failed 0x%0lx\n", hr); - j++; - } - - *size = offset; - *bind = bindings; - - CoTaskMemFree(colinfo); - CoTaskMemFree(stringsbuffer); - } - - IAccessor_Release(accessor); - - IColumnsInfo_Release(columninfo); - return hr; }
-static HRESULT load_all_recordset_data(struct recordset *recordset, IUnknown *rowset, DBBINDING *bindings, - DBBYTEOFFSET datasize) -{ - IRowset *rowset2; - LONG columns; - HRESULT hr; - DBCOUNTITEM obtained; - HROW *row = NULL; - int datarow = 0, datacol; - char *data; - - hr = Fields_get_Count(&recordset->fields.Fields_iface, &columns); - - hr = IUnknown_QueryInterface(rowset, &IID_IRowset, (void**)&rowset2); - if (FAILED(hr)) - { - WARN("Failed to get IRowset interface (0x%08lx)\n", hr); - return hr; - } - - hr = IRowset_GetNextRows(rowset2, 0, 0, 1, &obtained, &row); - if (hr != S_OK) - { - recordset->count = 0; - recordset->index = -1; - IRowset_Release(rowset2); - return FAILED(hr) ? hr : S_OK; - } - recordset->index = 0; - - data = malloc (datasize); - if (!data) - { - ERR("Failed to allocate row data (%Iu)\n", datasize); - IRowset_Release(rowset2); - return E_OUTOFMEMORY; - } - - do - { - VARIANT *v; - - if (!resize_recordset(recordset, datarow+1)) - { - IRowset_ReleaseRows(rowset2, 1, row, NULL, NULL, NULL); - free(data); - IRowset_Release(rowset2); - WARN("Failed to resize recordset\n"); - return E_OUTOFMEMORY; - } - - for (datacol = 0; datacol < columns; datacol++) - { - hr = IRowset_GetData(rowset2, *row, recordset->haccessors[datacol], data); - if (FAILED(hr)) - { - ERR("GetData Failed on Column %d (0x%08lx), status %Id\n", datacol, hr, - *(DBBYTEOFFSET*)(data + bindings[datacol].obStatus)); - break; - } - - v = &recordset->data[datarow * columns + datacol]; - VariantInit(v); - - if ( *(DBBYTEOFFSET*)(data + bindings[datacol].obStatus) == DBSTATUS_S_ISNULL) - { - V_VT(v) = VT_NULL; - continue; - } - - /* For most cases DBTYPE_* = VT_* type */ - V_VT(v) = bindings[datacol].wType; - switch(bindings[datacol].wType) - { - case DBTYPE_IUNKNOWN: - { - ISequentialStream *seq; - char unkdata[2048]; - ULONG size = 4096, dataRead = 0, total = 0; - char *buffer = malloc(size), *p = buffer; - HRESULT hr2; - - /* - * Cast directly to the object we specified in our bindings. As this object - * is referenced counted in some case and will error in GetData if the object - * hasn't been released. - */ - seq = *(ISequentialStream**)(data + bindings[datacol].obValue); - TRACE("Reading DBTYPE_IUNKNOWN %p\n", seq); - - do - { - dataRead = 0; - hr2 = ISequentialStream_Read(seq, unkdata, sizeof(unkdata), &dataRead); - if (FAILED(hr2) || !dataRead) break; - - total += dataRead; - memcpy(p, unkdata, dataRead); - p += dataRead; - if (total == size) - { - size *= 2; /* Double buffer */ - buffer = realloc(buffer, size); - p = buffer + total; - } - } while(hr2 == S_OK); - - if (recordset->columntypes[datacol] == DBTYPE_WSTR) - { - V_VT(v) = VT_BSTR; - V_BSTR(v) = SysAllocStringLen( (WCHAR*)buffer, total / sizeof(WCHAR) ); - } - else if (recordset->columntypes[datacol] == DBTYPE_BYTES) - { - SAFEARRAYBOUND sab; - - sab.lLbound = 0; - sab.cElements = total; - - V_VT(v) = (VT_ARRAY|VT_UI1); - V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab); - - memcpy( (BYTE*)V_ARRAY(v)->pvData, buffer, total); - } - else - { - FIXME("Unsupported conversion (%d)\n", recordset->columntypes[datacol]); - V_VT(v) = VT_NULL; - } - - free(buffer); - ISequentialStream_Release(seq); - - break; - } - case DBTYPE_R4: - V_R4(v) = *(float*)(data + bindings[datacol].obValue); - break; - case DBTYPE_R8: - V_R8(v) = *(DOUBLE*)(data + bindings[datacol].obValue); - break; - case DBTYPE_I8: - V_VT(v) = VT_I8; - V_I8(v) = *(LONGLONG*)(data + bindings[datacol].obValue); - break; - case DBTYPE_I4: - V_I4(v) = *(LONG*)(data + bindings[datacol].obValue); - break; - case DBTYPE_STR: - { - WCHAR *str = heap_strdupAtoW( (char*)(data + bindings[datacol].obValue) ); - - V_VT(v) = VT_BSTR; - V_BSTR(v) = SysAllocString(str); - free(str); - break; - } - case DBTYPE_WSTR: - { - V_VT(v) = VT_BSTR; - V_BSTR(v) = SysAllocString( (WCHAR*)(data + bindings[datacol].obValue) ); - break; - } - case DBTYPE_DBTIMESTAMP: - { - SYSTEMTIME st; - DBTIMESTAMP *ts = (DBTIMESTAMP *)(data + bindings[datacol].obValue); - DATE d; - - V_VT(v) = VT_DATE; - - st.wYear = ts->year; - st.wMonth = ts->month; - st.wDay = ts->day; - st.wHour = ts->hour; - st.wMinute = ts->minute; - st.wSecond = ts->second; - st.wMilliseconds = ts->fraction/1000000; - st.wDayOfWeek = 0; - hr = (SystemTimeToVariantTime(&st, &d) ? S_OK : E_FAIL); - - V_DATE(v) = d; - break; - } - case DBTYPE_VARIANT: - VariantInit(v); - VariantCopy(v, (VARIANT*)(data + bindings[datacol].obValue)); - break; - case DBTYPE_DATE: - V_DATE(v) = *(DATE*)(data + bindings[datacol].obValue); - break; - default: - V_VT(v) = VT_I2; - V_I2(v) = 0; - FIXME("Unknown Type %d\n", bindings[datacol].wType); - } - } - - datarow++; - - hr = IRowset_ReleaseRows(rowset2, 1, row, NULL, NULL, NULL); - if (FAILED(hr)) - ERR("Failed to ReleaseRows 0x%08lx\n", hr); - - hr = IRowset_GetNextRows(rowset2, 0, 0, 1, &obtained, &row); - } while(hr == S_OK); - - free(data); - IRowset_RestartPosition(rowset2, 0); - IRowset_Release(rowset2); - - return S_OK; -} - static HRESULT WINAPI recordset_Open( _Recordset *iface, VARIANT source, VARIANT active_connection, CursorTypeEnum cursor_type, LockTypeEnum lock_type, LONG options ) { @@ -2767,8 +2343,6 @@ static HRESULT WINAPI recordset_Open( _Recordset *iface, VARIANT source, VARIANT IUnknown *session; IUnknown *rowset; HRESULT hr; - DBBINDING *bindings; - DBBYTEOFFSET datasize;
TRACE( "%p, %s, %s, %d, %d, %ld\n", recordset, debugstr_variant(&source), debugstr_variant(&active_connection), cursor_type, lock_type, options ); @@ -2854,31 +2428,9 @@ static HRESULT WINAPI recordset_Open( _Recordset *iface, VARIANT source, VARIANT if (FAILED(hr) || !rowset) return hr;
- hr = create_bindings(rowset, recordset, &bindings, &datasize); - if (FAILED(hr)) - { - WARN("Failed to load bindings (%lx)\n", hr); - IUnknown_Release(rowset); - return hr; - } - resize_recordset(recordset, recordset->count); - - hr = load_all_recordset_data(recordset, rowset, bindings, datasize); - if (FAILED(hr)) - { - WARN("Failed to load all recordset data (%lx)\n", hr); - CoTaskMemFree(bindings); - IUnknown_Release(rowset); - return hr; - } - - CoTaskMemFree(bindings); - - ADORecordsetConstruction_put_Rowset(&recordset->ADORecordsetConstruction_iface, rowset); - recordset->cursor_type = cursor_type; - + hr = ADORecordsetConstruction_put_Rowset(&recordset->ADORecordsetConstruction_iface, rowset); IUnknown_Release(rowset); - + recordset->cursor_type = cursor_type; return hr; }
@@ -3566,7 +3118,6 @@ HRESULT Recordset_create( void **obj ) recordset->ADORecordsetConstruction_iface.lpVtbl = &rsconstruction_vtbl; recordset->active_connection = NULL; recordset->refs = 1; - recordset->index = -1; recordset->cursor_location = adUseServer; recordset->cursor_type = adOpenForwardOnly; recordset->row_set = NULL; @@ -3575,8 +3126,6 @@ HRESULT Recordset_create( void **obj ) recordset->cache.size = 1; recordset->cache.rows = malloc( sizeof(*recordset->cache.rows) ); recordset->max_records = 0; - recordset->columntypes = NULL; - recordset->haccessors = NULL; Fields_create( recordset );
*obj = &recordset->Recordset_iface;