[PATCH 0/7] MR9531: msado15: Reimplement Field::get_Value and Field::put_Value.
From: Piotr Caban <piotr(a)codeweavers.com> --- dlls/msado15/rowset.c | 53 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/dlls/msado15/rowset.c b/dlls/msado15/rowset.c index c68280c5240..d209d120187 100644 --- a/dlls/msado15/rowset.c +++ b/dlls/msado15/rowset.c @@ -21,6 +21,10 @@ #include "oledberr.h" #include "unknwn.h" +#include "initguid.h" +#include "msdadc.h" +#include "msdaguid.h" + #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(msado15); @@ -34,6 +38,8 @@ struct rowset IRowsetInfo IRowsetInfo_iface; LONG refs; + IDataConvert *convert; + int columns_cnt; DBCOLUMNINFO *columns; OLECHAR *columns_buf; @@ -46,6 +52,8 @@ struct rowset struct accessor { LONG refs; + int bindings_count; + DBBINDING bindings[1]; }; static inline struct rowset *impl_from_IRowsetExactScroll(IRowsetExactScroll *iface) @@ -136,6 +144,8 @@ static ULONG WINAPI rowset_Release(IRowsetExactScroll *iface) { TRACE("destroying %p\n", rowset); + if (rowset->convert) IDataConvert_Release(rowset->convert); + CoTaskMemFree(rowset->columns); CoTaskMemFree(rowset->columns_buf); free(rowset); @@ -528,6 +538,8 @@ static HRESULT WINAPI accessor_CreateAccessor(IAccessor *iface, DBACCESSORFLAGS { struct rowset *rowset = impl_from_IAccessor(iface); struct accessor *accessor; + HRESULT hr, ret = S_OK; + int i; TRACE("%p, %lx, %Iu, %p %Id, %p %p\n", rowset, dwAccessorFlags, cBindings, rgBindings, cbRowSize, phAccessor, rgStatus); @@ -535,9 +547,9 @@ static HRESULT WINAPI accessor_CreateAccessor(IAccessor *iface, DBACCESSORFLAGS if (!phAccessor) return E_INVALIDARG; *phAccessor = 0; - if (cBindings || cbRowSize) + if (cbRowSize) { - FIXME("accessing data not implemented\n"); + FIXME("cbRowSize not handled\n"); return E_NOTIMPL; } if (dwAccessorFlags != DBACCESSOR_ROWDATA) @@ -546,9 +558,44 @@ static HRESULT WINAPI accessor_CreateAccessor(IAccessor *iface, DBACCESSORFLAGS return E_NOTIMPL; } - accessor = calloc(1, sizeof(*accessor)); + for (i = 0; i < cBindings; i++) + { + if (rgBindings[i].iOrdinal >= rowset->columns_cnt) + { + if (rgStatus) rgStatus[i] = DBBINDSTATUS_BADORDINAL; + if (ret == S_OK) ret = DBSTATUS_E_BADACCESSOR; + continue; + } + + if (rgBindings[i].wType != rowset->columns[rgBindings[i].iOrdinal].wType) + { + if (!rowset->convert) + { + hr = CoCreateInstance(&CLSID_OLEDB_CONVERSIONLIBRARY, NULL, CLSCTX_INPROC_SERVER, + &IID_IDataConvert, (void **)&rowset->convert); + if (FAILED(hr)) return hr; + } + + hr = IDataConvert_CanConvert(rowset->convert, + rowset->columns[rgBindings[i].iOrdinal].wType, rgBindings[i].wType); + if (FAILED(hr)) return hr; + if (hr != S_OK) + { + if (rgStatus) rgStatus[i] = DBBINDSTATUS_UNSUPPORTEDCONVERSION; + if (ret == S_OK) ret = DBSTATUS_E_BADACCESSOR; + continue; + } + } + + if (rgStatus) rgStatus[i] = DBBINDSTATUS_OK; + } + if (ret != S_OK) return ret; + + accessor = calloc(1, offsetof(struct accessor, bindings[cBindings])); if (!accessor) return E_OUTOFMEMORY; accessor->refs = 1; + accessor->bindings_count = cBindings; + memcpy(accessor->bindings, rgBindings, sizeof(rgBindings[0]) * cBindings); *phAccessor = (HACCESSOR)accessor; return S_OK; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9531
From: Piotr Caban <piotr(a)codeweavers.com> --- dlls/msado15/rowset.c | 59 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/dlls/msado15/rowset.c b/dlls/msado15/rowset.c index d209d120187..84ef69511c9 100644 --- a/dlls/msado15/rowset.c +++ b/dlls/msado15/rowset.c @@ -47,6 +47,9 @@ struct rowset BOOL backward_fetch; int index; int row_cnt; + + int data_cnt; + VARIANT *data; }; struct accessor @@ -168,12 +171,62 @@ static HRESULT WINAPI rowset_AddRefRows(IRowsetExactScroll *iface, DBCOUNTITEM c return S_OK; } -static HRESULT WINAPI rowset_GetData(IRowsetExactScroll *iface, HROW row, HACCESSOR accessor, void *data) +static HRESULT WINAPI rowset_GetData(IRowsetExactScroll *iface, HROW row, HACCESSOR hacc, void *data) { struct rowset *rowset = impl_from_IRowsetExactScroll(iface); + struct accessor *accessor = (struct accessor *)hacc; + DBSTATUS status = DBSTATUS_S_OK; + BOOL succ = FALSE, err = FALSE; + DBLENGTH len; + VARIANT val; + HRESULT hr; + int i, idx; - FIXME("%p, %Id, %Id, %p\n", rowset, row, accessor, data); - return E_NOTIMPL; + 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; + for (i = 0; i < accessor->bindings_count; i++) + { + if (accessor->bindings[i].wType != DBTYPE_VARIANT) + { + FIXME("data conversion not implemented\n"); + return E_NOTIMPL; + } + } + + 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; + if (accessor->bindings[i].cbMaxLen < len) + status = DBSTATUS_E_DATAOVERFLOW; + else + { + VariantInit(&val); + if (idx < rowset->data_cnt) + { + hr = VariantCopy(&val, &rowset->data[idx]); + if (FAILED(hr)) return hr; + } + + if (accessor->bindings[i].dwPart & DBPART_VALUE && status == DBSTATUS_S_OK) + memcpy((BYTE *)data + accessor->bindings[i].obValue, &val, sizeof(val)); + } + + if (accessor->bindings[i].dwPart & DBPART_LENGTH) + memcpy((BYTE *)data + accessor->bindings[i].obLength, &len, sizeof(len)); + if (accessor->bindings[i].dwPart & DBPART_STATUS) + memcpy((BYTE *)data + accessor->bindings[i].obStatus, &status, sizeof(status)); + + if (status == DBSTATUS_S_OK) succ = TRUE; + else err = TRUE; + } + + if (!succ) return DB_E_ERRORSOCCURRED; + return err ? DB_S_ERRORSOCCURRED : S_OK; } static HRESULT WINAPI rowset_GetNextRows(IRowsetExactScroll *iface, HCHAPTER chapter, -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9531
From: Piotr Caban <piotr(a)codeweavers.com> --- dlls/msado15/rowset.c | 70 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 3 deletions(-) diff --git a/dlls/msado15/rowset.c b/dlls/msado15/rowset.c index 84ef69511c9..d11cbd5c28a 100644 --- a/dlls/msado15/rowset.c +++ b/dlls/msado15/rowset.c @@ -516,12 +516,76 @@ static HRESULT WINAPI rowset_change_DeleteRows(IRowsetChange *iface, HCHAPTER re return E_NOTIMPL; } -static HRESULT WINAPI rowset_change_SetData(IRowsetChange *iface, HROW row, HACCESSOR accessor, void *data) +static HRESULT WINAPI rowset_change_SetData(IRowsetChange *iface, HROW row, HACCESSOR hacc, void *data) { struct rowset *rowset = impl_from_IRowsetChange(iface); + struct accessor *accessor = (struct accessor *)hacc; + BOOL err = FALSE, succ = FALSE; + DBSTATUS status; + DBLENGTH len; + int i, idx; + HRESULT hr; - FIXME("%p, %Id, %Id, %p\n", rowset, row, accessor, data); - return E_NOTIMPL; + 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; + for (i = 0; i < accessor->bindings_count; i++) + { + if (accessor->bindings[i].wType != DBTYPE_VARIANT) + { + FIXME("data conversion not implemented\n"); + return E_NOTIMPL; + } + } + + for (i = 0; i < accessor->bindings_count; i++) + { + idx = (row - 1) * rowset->columns_cnt + accessor->bindings[i].iOrdinal; + + 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) + status = DBSTATUS_E_DATAOVERFLOW; + else if (accessor->bindings[i].dwPart & DBPART_VALUE) + { + hr = VariantCopy(&rowset->data[idx], (VARIANT *)((BYTE *)data + accessor->bindings[i].obValue)); + if (FAILED(hr)) + { + for (i--; i>=0; i--) + { + if (accessor->bindings[i].dwPart & DBPART_VALUE) + VariantClear((VARIANT *)((BYTE *)data + accessor->bindings[i].obValue)); + } + return hr; + } + } + + if (accessor->bindings[i].dwPart & DBPART_LENGTH) + memcpy((BYTE *)data + accessor->bindings[i].obLength, &len, sizeof(len)); + if (accessor->bindings[i].dwPart & DBPART_STATUS) + memcpy((BYTE *)data + accessor->bindings[i].obStatus, &status, sizeof(status)); + + if (status == DBSTATUS_S_OK) succ = TRUE; + else err = TRUE; + } + + if (!succ) return DB_E_ERRORSOCCURRED; + return err ? DB_S_ERRORSOCCURRED : S_OK; } static HRESULT WINAPI rowset_change_InsertRow(IRowsetChange *iface, HCHAPTER reserved, -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9531
From: Piotr Caban <piotr(a)codeweavers.com> --- dlls/msado15/recordset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index 8bb86f9ba7f..2091521be89 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -2007,7 +2007,7 @@ static HRESULT WINAPI recordset_MoveNext( _Recordset *iface ) if (recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed ); - if (!recordset->current_row) + if (!recordset->current_row && !recordset->is_eof && !recordset->is_bof) { hr = cache_get( recordset, TRUE ); if (FAILED(hr)) return hr; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9531
From: Piotr Caban <piotr(a)codeweavers.com> --- dlls/msado15/recordset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index 2091521be89..a7afacca75c 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -2029,7 +2029,7 @@ static HRESULT WINAPI recordset_MovePrevious( _Recordset *iface ) if (recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed ); - if (!recordset->current_row) + if (!recordset->current_row && !recordset->is_eof && !recordset->is_bof) { hr = cache_get( recordset, TRUE ); if (FAILED(hr)) return hr; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9531
From: Piotr Caban <piotr(a)codeweavers.com> --- dlls/msado15/recordset.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index a7afacca75c..a46a16e1251 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -42,6 +42,7 @@ struct field ISupportErrorInfo ISupportErrorInfo_iface; Properties Properties_iface; LONG refs; + DBORDINAL ordinal; WCHAR *name; DataTypeEnum type; LONG defined_size; @@ -1084,6 +1085,7 @@ static HRESULT append_field( struct fields *fields, const DBCOLUMNINFO *info ) hr = Field_create( info->pwszName, fields->count, fields_get_recordset(fields), &field ); if (hr != S_OK) return hr; + field->ordinal = info->iOrdinal; field->type = info->wType; field->defined_size = info->ulColumnSize; if (info->dwFlags != adFldUnspecified) field->attrs = info->dwFlags; @@ -1269,6 +1271,7 @@ static HRESULT WINAPI fields__Append( Fields *iface, BSTR name, DataTypeEnum typ if ((hr = init_fields( fields )) != S_OK) return hr; memset( &colinfo, 0, sizeof(colinfo) ); + colinfo.iOrdinal = fields->count ? (*fields->field)[fields->count - 1].ordinal + 1 : 1; colinfo.pwszName = name; colinfo.wType = type; colinfo.ulColumnSize = size; @@ -2538,7 +2541,7 @@ static HRESULT WINAPI recordset_Open( _Recordset *iface, VARIANT source, VARIANT struct field *field = recordset->fields.field[i - 1]; info[i].pwszName = field->name; - info[i].iOrdinal = i; + info[i].iOrdinal = field->ordinal; info[i].dwFlags = field->attrs; info[i].ulColumnSize = field->defined_size; info[i].wType = field->type; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9531
From: Piotr Caban <piotr(a)codeweavers.com> --- dlls/msado15/recordset.c | 149 ++++++++++++++++++++++++++++++----- dlls/msado15/tests/msado15.c | 116 +++++++++++++++++++++------ 2 files changed, 222 insertions(+), 43 deletions(-) diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index a46a16e1251..4aa72c039d0 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -51,6 +51,8 @@ struct field unsigned char prec; unsigned char scale; struct recordset *recordset; + HACCESSOR hacc_get; + HACCESSOR hacc_put; /* Field Properties */ VARIANT optimize; @@ -385,46 +387,139 @@ static LONG get_column_count( struct recordset *recordset ) static HRESULT WINAPI field_get_Value( Field *iface, VARIANT *val ) { struct field *field = impl_from_Field( iface ); - ULONG row = field->recordset->index, col = field->index, col_count; - VARIANT copy; + struct recordset *recordset = field->recordset; + struct buf + { + VARIANT val; + DBSTATUS status; + } buf; HRESULT hr; TRACE( "%p, %p\n", field, val ); - if (field->recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed ); - if (field->recordset->index < 0) return MAKE_ADO_HRESULT( adErrNoCurrentRecord ); + if (!recordset || 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; + } + if (!recordset->current_row) return MAKE_ADO_HRESULT( adErrNoCurrentRecord ); + + 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 (!field->hacc_get) + { + DBBINDSTATUS status = DBBINDSTATUS_OK; + DBBINDING binding; - col_count = get_column_count( field->recordset ); + memset(&binding, 0, sizeof(binding)); + binding.iOrdinal = field->ordinal; + binding.obStatus = offsetof(struct buf, status); + binding.dwPart = DBPART_VALUE | DBPART_STATUS; + binding.cbMaxLen = sizeof(buf.val); + binding.wType = DBTYPE_VARIANT; + binding.bPrecision = field->prec; + binding.bScale = field->scale; + hr = IAccessor_CreateAccessor( recordset->accessor, DBACCESSOR_ROWDATA, + 1, &binding, 0, &field->hacc_get, &status ); + if (FAILED(hr)) return hr; + if (status != DBBINDSTATUS_OK) + { + IAccessor_ReleaseAccessor( recordset->accessor, field->hacc_get, NULL ); + field->hacc_get = 0; + return E_FAIL; + } + } - VariantInit( © ); - if ((hr = VariantCopy( ©, &field->recordset->data[row * col_count + col] )) != S_OK) return hr; + memset(&buf, 0, sizeof(buf)); + hr = IRowset_GetData(recordset->row_set, recordset->current_row, field->hacc_get, &buf); + if (FAILED(hr)) return hr; + if (buf.status != DBSTATUS_S_OK) return E_FAIL; - *val = copy; + *val = buf.val; return S_OK; } static HRESULT WINAPI field_put_Value( Field *iface, VARIANT val ) { struct field *field = impl_from_Field( iface ); - ULONG row = field->recordset->index, col = field->index, col_count; - VARIANT copy; + struct recordset *recordset = field->recordset; + struct buf + { + VARIANT val; + DBSTATUS status; + DBLENGTH len; + } buf; HRESULT hr; TRACE( "%p, %s\n", field, debugstr_variant(&val) ); - if (field->recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed ); - if (field->recordset->index < 0) return MAKE_ADO_HRESULT( adErrNoCurrentRecord ); + if (!recordset || recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed ); - col_count = get_column_count( field->recordset ); + if (!recordset->is_eof && !recordset->is_bof && !recordset->current_row) + { + hr = cache_get( recordset, TRUE ); + if (FAILED(hr)) return hr; + } + if (!recordset->current_row) return MAKE_ADO_HRESULT( adErrNoCurrentRecord ); - VariantInit( © ); - if ((hr = VariantCopy( ©, &val )) != S_OK) return hr; + 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 ); - field->recordset->data[row * col_count + col] = copy; + 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 (field->recordset->editmode == adEditNone) - field->recordset->editmode = adEditInProgress; + if (!field->hacc_put) + { + DBBINDSTATUS status = DBBINDSTATUS_OK; + DBBINDING binding; + memset(&binding, 0, sizeof(binding)); + binding.iOrdinal = field->ordinal; + binding.obLength = offsetof(struct buf, len); + binding.obStatus = offsetof(struct buf, status); + binding.dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS; + binding.cbMaxLen = sizeof(buf.val); + binding.wType = DBTYPE_VARIANT; + binding.bPrecision = field->prec; + binding.bScale = field->scale; + hr = IAccessor_CreateAccessor( recordset->accessor, DBACCESSOR_ROWDATA, + 1, &binding, 0, &field->hacc_put, &status ); + if (FAILED(hr)) return hr; + if (status != DBBINDSTATUS_OK) + { + IAccessor_ReleaseAccessor( recordset->accessor, field->hacc_put, NULL ); + field->hacc_put = 0; + return E_FAIL; + } + } + + memset(&buf, 0, sizeof(buf)); + buf.val = val; + hr = IRowsetChange_SetData(recordset->rowset_change, recordset->current_row, field->hacc_put, &buf); + if (FAILED(hr)) return hr; + if (buf.status != DBSTATUS_S_OK) return E_FAIL; return S_OK; } @@ -1420,9 +1515,6 @@ 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->accessor && recordset->accessor != NO_INTERFACE ) - IAccessor_Release( recordset->accessor ); - recordset->accessor = NULL; VariantClear( &recordset->filter ); @@ -1432,13 +1524,28 @@ static void close_recordset( struct recordset *recordset ) for (i = 0; i < col_count; i++) { + if (recordset->fields.field[i]->hacc_get) + { + IAccessor_ReleaseAccessor(recordset->accessor, recordset->fields.field[i]->hacc_get, NULL); + recordset->fields.field[i]->hacc_get = 0; + } + if (recordset->fields.field[i]->hacc_put) + { + IAccessor_ReleaseAccessor(recordset->accessor, recordset->fields.field[i]->hacc_put, NULL); + recordset->fields.field[i]->hacc_put = 0; + } recordset->fields.field[i]->recordset = NULL; + Field_Release(&recordset->fields.field[i]->Field_iface); if (recordset->haccessors) IAccessor_ReleaseAccessor(accessor, recordset->haccessors[i], NULL); } + if (recordset->accessor && recordset->accessor != NO_INTERFACE ) + IAccessor_Release( recordset->accessor ); + recordset->accessor = NULL; + if (recordset->haccessors) { IAccessor_Release(accessor); diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index a73ac67ec6d..3cede5c170c 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -27,6 +27,7 @@ #include "wine/test.h" #include "msdasql.h" #include "odbcinst.h" +#include "msdadc.h" #define MAKE_ADO_HRESULT( err ) MAKE_HRESULT( SEVERITY_ERROR, FACILITY_CONTROL, err ) @@ -83,6 +84,7 @@ DEFINE_EXPECT(rowset_ReleaseRows); DEFINE_EXPECT(rowset_GetRowsAt); DEFINE_EXPECT(rowset_GetExactPosition); DEFINE_EXPECT(rowset_GetData); +DEFINE_EXPECT(rowset_change_SetData); DEFINE_EXPECT(rowset_change_InsertRow); DEFINE_EXPECT(accessor_AddRefAccessor); DEFINE_EXPECT(accessor_CreateAccessor); @@ -837,8 +839,18 @@ static HRESULT WINAPI rowset_change_DeleteRows(IRowsetChange *iface, HCHAPTER re static HRESULT WINAPI rowset_change_SetData(IRowsetChange *iface, HROW row, HACCESSOR accessor, void *data) { - ok(0, "unexpected call\n"); - return E_NOTIMPL; + VARIANT *v; + + CHECK_EXPECT(rowset_change_SetData); + + ok(row == 1, "row = %Id\n", row); + ok(accessor, "accessor = 0\n"); + ok(data != NULL, "data = NULL\n"); + + v = (VARIANT *)data; + ok(V_VT(v) == VT_I4, "V_VT(v) = %d\n", V_VT(v)); + ok(V_I4(v) == 123, "V_I4(v) = %ld\n", V_I4(v)); + return S_OK; } static HRESULT WINAPI rowset_change_InsertRow(IRowsetChange *iface, @@ -904,7 +916,6 @@ static HRESULT WINAPI accessor_CreateAccessor(IAccessor *iface, DBACCESSORFLAGS ok(!cBindings || cBindings == 1, "cBindings = %Iu\n", cBindings); ok(cbRowSize == 0, "cbRowSize = %Iu\n", cbRowSize); ok(phAccessor != NULL, "pHAccessor = NULL\n"); - ok(!rgStatus, "rgStatus != NULL\n"); if (!cBindings) { @@ -916,6 +927,8 @@ static HRESULT WINAPI accessor_CreateAccessor(IAccessor *iface, DBACCESSORFLAGS haccessor->ref = 1; haccessor->binding = rgBindings[0]; *phAccessor = (HACCESSOR)haccessor; + + if (rgStatus) rgStatus[0] = DBBINDSTATUS_OK; return S_OK; } @@ -1049,25 +1062,49 @@ static HRESULT WINAPI rowset_AddRefRows(IRowsetExactScroll *iface, DBCOUNTITEM c static HRESULT WINAPI rowset_GetData(IRowsetExactScroll *iface, HROW hRow, HACCESSOR hAccessor, void *pData) { struct haccessor *haccessor = (struct haccessor *)hAccessor; - DBSTATUS status; + DBSTATUS status = DBSTATUS_S_OK; DBLENGTH len; - int val; + union + { + int i; + VARIANT v; + } val; CHECK_EXPECT2(rowset_GetData); - ok(!haccessor->binding.iOrdinal, "iOrdinal = %Id\n", haccessor->binding.iOrdinal); - ok(haccessor->binding.dwPart == (DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS), - "dwPart = %ld\n", haccessor->binding.dwPart); - ok(haccessor->binding.cbMaxLen == sizeof(int), "cbMaxLen = %Id\n", haccessor->binding.cbMaxLen); - ok(haccessor->binding.wType == DBTYPE_I4, "wType = %d\n", haccessor->binding.wType); - - val = hRow; - len = sizeof(int); - status = DBSTATUS_S_OK; + switch(haccessor->binding.iOrdinal) + { + case 0: + ok(haccessor->binding.dwPart == (DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS), + "dwPart = %ld\n", haccessor->binding.dwPart); + ok(haccessor->binding.cbMaxLen == sizeof(int), "cbMaxLen = %Id\n", haccessor->binding.cbMaxLen); + ok(haccessor->binding.wType == DBTYPE_I4, "wType = %d\n", haccessor->binding.wType); + + val.i = hRow; + len = sizeof(val.i); + break; + + case 1: + ok(haccessor->binding.dwPart == (DBPART_VALUE | DBPART_STATUS), + "dwPart = %ld\n", haccessor->binding.dwPart); + ok(haccessor->binding.cbMaxLen == sizeof(VARIANT), "cbMaxLen = %Id\n", haccessor->binding.cbMaxLen); + ok(haccessor->binding.wType == DBTYPE_VARIANT, "wType = %d\n", haccessor->binding.wType); + + V_VT(&val.v) = VT_I4; + V_I4(&val.v) = 123; + len = sizeof(val.v); + break; + default: + ok(0, "unexpected GetData argument\n"); + return E_NOTIMPL; + } - memcpy((BYTE *)pData + haccessor->binding.obValue, &val, sizeof(val)); - memcpy((BYTE *)pData + haccessor->binding.obLength, &len, sizeof(len)); - memcpy((BYTE *)pData + haccessor->binding.obStatus, &status, sizeof(status)); + if (haccessor->binding.dwPart & DBPART_VALUE) + memcpy((BYTE *)pData + haccessor->binding.obValue, &val, len); + if (haccessor->binding.dwPart & DBPART_LENGTH) + memcpy((BYTE *)pData + haccessor->binding.obLength, &len, sizeof(len)); + if (haccessor->binding.dwPart & DBPART_STATUS) + memcpy((BYTE *)pData + haccessor->binding.obStatus, &status, sizeof(status)); return S_OK; } @@ -1235,7 +1272,7 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) HRESULT hr; LONG count, state; unsigned char prec, scale; - VARIANT index, missing; + VARIANT index, missing, v; ADO_LONGPTR size; DataTypeEnum type; @@ -1334,6 +1371,43 @@ 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 ); + 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 ); + CHECK_CALLED( accessor_CreateAccessor ); + CHECK_CALLED( rowset_GetData ); + ok( V_VT(&v) == VT_I4, "V_VT(&v) = %d\n", V_VT(&v) ); + ok( V_I4(&v) == 123, "V_I4(&v) = %ld\n", V_I4(&v) ); + + SET_EXPECT( rowset_GetData ); + hr = Field_get_Value( field, &v ); + ok( hr == S_OK, "got %08lx\n", hr ); + CHECK_CALLED( rowset_GetData ); + ok( V_VT(&v) == VT_I4, "V_VT(&v) = %d\n", V_VT(&v) ); + ok( V_I4(&v) == 123, "V_I4(&v) = %ld\n", V_I4(&v) ); + + SET_EXPECT(rowset_QI_IRowsetChange); + SET_EXPECT( rowset_QI_IAccessor ); + SET_EXPECT( accessor_CreateAccessor ); + SET_EXPECT( rowset_change_SetData ); + hr = Field_put_Value( field, v ); + ok( hr == S_OK, "got %08lx\n", hr ); + todo_wine CHECK_NOT_CALLED(rowset_QI_IRowsetChange); + todo_wine CHECK_CALLED( rowset_QI_IAccessor ); + CHECK_CALLED( accessor_CreateAccessor ); + CHECK_CALLED( rowset_change_SetData ); + Field_Release( field ); SET_EXPECT( rowset_QI_IRowsetExactScroll ); @@ -1394,7 +1468,6 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) 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); @@ -1403,9 +1476,8 @@ 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); + if (!exact_scroll) todo_wine CHECK_CALLED(rowset_QI_IAccessor); + else CHECK_NOT_CALLED(rowset_QI_IAccessor); CHECK_CALLED(accessor_CreateAccessor); CHECK_CALLED(accessor_AddRefAccessor); CHECK_CALLED(rowset_change_InsertRow); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9531
participants (2)
-
Piotr Caban -
Piotr Caban (@piotr)