[PATCH 0/8] MR9885: msado15: Performance and initialization improvements.
From: Piotr Caban <piotr@codeweavers.com> --- include/Makefile.in | 1 + include/msdshape.h | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 include/msdshape.h diff --git a/include/Makefile.in b/include/Makefile.in index e0987cead85..67f53da3ca0 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -500,6 +500,7 @@ SOURCES = \ msdasc.idl \ msdasql.h \ msdelta.h \ + msdshape.h \ mshtmcid.h \ mshtmdid.h \ mshtmhst.idl \ diff --git a/include/msdshape.h b/include/msdshape.h new file mode 100644 index 00000000000..deda2960df0 --- /dev/null +++ b/include/msdshape.h @@ -0,0 +1,39 @@ +/* + * Copyright 2025 Piotr Caban for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef DS_INCLUDED +#define DS_INCLUDED + +const CLSID CLSID_DataShapeProvider = { 0x3449a1c8, 0xc56c, 0x11d0, { 0xad, 0x72, 0x00, 0xc0, 0x4f, 0xc2, 0x98, 0x63 }}; +const CLSID DBPROPSET_MSDSDBINIT = { 0x55cb91a8, 0x5c7a, 0x11d1, { 0xad, 0xad, 0x00, 0xc0, 0x4f, 0xc2, 0x98, 0x63 }}; +const CLSID DBPROPSET_MSDSSESSION = { 0xedf17536, 0xafbf, 0x11d1, { 0x88, 0x47, 0x00, 0x00, 0xf8, 0x79, 0xf9, 0x8c }}; + +const char* PROGID_DataShapeProvider = "MSDataShape"; +const char* PROGID_DataShapeProvider_Version = "MSDataShape.1"; + +enum MSDSDBINITPROPENUM +{ + DBPROP_MSDS_DBINIT_DATAPROVIDER = 2, +}; + +enum MSDSSESSIONPROPENUM +{ + DBPROP_MSDS_SESS_UNIQUENAMES = 2, +}; + +#endif /* DS_INCLUDED */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9885
From: Piotr Caban <piotr@codeweavers.com> --- dlls/msado15/recordset.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index d0e2a32d835..a6330ed5d9f 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -46,6 +46,7 @@ struct field Properties Properties_iface; LONG refs; DBORDINAL ordinal; + int name_hash; WCHAR *name; DataTypeEnum type; LONG defined_size; @@ -1186,6 +1187,13 @@ static struct PropertiesVtbl field_properties_vtbl = field_props_get_Item }; +static int get_hash( const WCHAR *str ) +{ + int hash = 5381; + for (; *str; str++) hash += (hash << 5) + towlower( *str ); + return hash; +} + static HRESULT Field_create( const WCHAR *name, LONG index, struct recordset *recordset, struct field **field ) { if (!(*field = calloc( 1, sizeof(**field) ))) return E_OUTOFMEMORY; @@ -1198,6 +1206,7 @@ static HRESULT Field_create( const WCHAR *name, LONG index, struct recordset *re free( *field ); return E_OUTOFMEMORY; } + (*field)->name_hash = get_hash( name ); (*field)->index = index; (*field)->recordset = recordset; @@ -1454,6 +1463,7 @@ static HRESULT WINAPI fields_Refresh( Fields *iface ) static HRESULT map_index( struct fields *fields, VARIANT *index, ULONG *ret ) { + int hash; ULONG i; if (V_VT( index ) != VT_BSTR) @@ -1474,9 +1484,10 @@ static HRESULT map_index( struct fields *fields, VARIANT *index, ULONG *ret ) return MAKE_ADO_HRESULT(adErrItemNotFound); } + hash = get_hash( V_BSTR(index) ); for (i = 0; i < fields->count; i++) { - if (!wcsicmp( V_BSTR(index), fields->field[i]->name )) + if (hash == fields->field[i]->name_hash && !wcsicmp( V_BSTR(index), fields->field[i]->name )) { *ret = i; return S_OK; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9885
From: Piotr Caban <piotr@codeweavers.com> --- dlls/msado15/tests/msado15.c | 280 ++++++++++++++++++++++++++++++++++- 1 file changed, 277 insertions(+), 3 deletions(-) diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index 5276e1113b2..fc9b92cbbbe 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -28,6 +28,7 @@ #include "msdasql.h" #include "odbcinst.h" #include "msdadc.h" +#include "msdshape.h" #define MAKE_ADO_HRESULT( err ) MAKE_HRESULT( SEVERITY_ERROR, FACILITY_CONTROL, err ) @@ -91,6 +92,13 @@ DEFINE_EXPECT(view_filter_SetFilter); DEFINE_EXPECT(chaptered_rowset_ReleaseChapter); DEFINE_EXPECT(rowset_current_index_GetIndex); DEFINE_EXPECT(rowset_current_index_SetIndex); +DEFINE_EXPECT(open_rowset_QI_ISessionProperties); +DEFINE_EXPECT(open_rowset_QI_IBindResource); +DEFINE_EXPECT(open_rowset_QI_ICreateRow); +DEFINE_EXPECT(open_rowset_QI_IDBCreateCommand); +DEFINE_EXPECT(open_rowset_OpenRowset); +DEFINE_EXPECT(dbprops_GetProperties); +DEFINE_EXPECT(dbprops_SetProperties); static BOOL is_bof( _Recordset *recordset ) { @@ -556,7 +564,8 @@ static void test_Recordset(void) } /* This interface is queried for but is not documented anywhere. */ -DEFINE_GUID(UKN_INTERFACE, 0x6f1e39e1, 0x05c6, 0x11d0, 0xa7, 0x8b, 0x00, 0xaa, 0x00, 0xa3, 0xf0, 0x0d); +DEFINE_GUID(UNK_INTERFACE, 0x6f1e39e1, 0x05c6, 0x11d0, 0xa7, 0x8b, 0x00, 0xaa, 0x00, 0xa3, 0xf0, 0x0d); +DEFINE_GUID(UNK2_INTERFACE, 0x83693a20, 0xfbea, 0x11cf, 0xa7, 0x85, 0x00, 0xaa, 0x00, 0xa3, 0xf0, 0x0d); struct test_rowset { @@ -1456,9 +1465,9 @@ static HRESULT WINAPI rowset_QueryInterface(IRowsetExactScroll *iface, REFIID ri { *obj = &rowset->IRowsetCurrentIndex_iface; } - else if (IsEqualIID(riid, &UKN_INTERFACE)) + else if (IsEqualIID(riid, &UNK_INTERFACE) || IsEqualIID(riid, &UNK2_INTERFACE)) { - trace("Unknown interface\n"); + trace("Unknown interface (%s)\n", wine_dbgstr_guid(riid)); return E_NOINTERFACE; } @@ -3209,12 +3218,277 @@ static void cleanup_database(void) DeleteFileA(mdbpath); } +static HRESULT WINAPI dbprops_QueryInterface(IDBProperties *iface, REFIID riid, void **obj) +{ + ok(0, "unexpected QI(%s)\n", wine_dbgstr_guid(riid)); + *obj = NULL; + return E_NOTIMPL; +} + +static ULONG WINAPI dbprops_AddRef(IDBProperties *iface) +{ + return 2; +} + +static ULONG WINAPI dbprops_Release(IDBProperties *iface) +{ + return 1; +} + +static HRESULT WINAPI dbprops_GetProperties(IDBProperties *iface, ULONG propidsets_count, + const DBPROPIDSET propidsets[], ULONG *propsets_count, DBPROPSET **propsets) +{ + CHECK_EXPECT(dbprops_GetProperties); + ok(propidsets_count == 1, "propidsets_count = %lu\n", propidsets_count); + ok(IsEqualGUID(&propidsets[0].guidPropertySet, &DBPROPSET_MSDSDBINIT), + "guidPropertySet = %s\n", wine_dbgstr_guid(&propidsets[0].guidPropertySet)); + ok(propidsets[0].cPropertyIDs == 1, "cPropertyIDs = %lu\n", propidsets[0].cPropertyIDs); + ok(propidsets[0].rgPropertyIDs[0] == DBPROP_MSDS_DBINIT_DATAPROVIDER, + "rgPropertyIDs[0] = %lx\n", propidsets[0].rgPropertyIDs[0]); + return E_NOTIMPL; +} + +static HRESULT WINAPI dbprops_GetPropertyInfo(IDBProperties *iface, ULONG propidsets_count, + const DBPROPIDSET propidsets[], ULONG *propinfosets_count, + DBPROPINFOSET **propinfosets, OLECHAR **desc_buf) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI dbprops_SetProperties(IDBProperties *iface, + ULONG propsets_count, DBPROPSET propsets[]) +{ + DBPROP *prop; + + CHECK_EXPECT(dbprops_SetProperties); + ok(propsets_count == 1, "propsets_count = %lu\n", propsets_count); + ok(IsEqualGUID(&propsets[0].guidPropertySet, &DBPROPSET_DBINIT), + "guidPropertySet = %s\n", wine_dbgstr_guid(&propsets[0].guidPropertySet)); + ok(propsets[0].cProperties == 2, "cProperties = %lu\n", propsets[0].cProperties); + + prop = propsets[0].rgProperties; + ok(prop->dwPropertyID == DBPROP_INIT_TIMEOUT, "[0].dwPropertyID = %lx\n", prop->dwPropertyID); + ok(prop->dwOptions == DBPROPOPTIONS_OPTIONAL, "[0].dwOptions = %lx\n", prop->dwOptions); + ok(V_VT(&prop->vValue) == VT_I4, "[0].vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + ok(V_I4(&prop->vValue) == 15, "[0].vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + + prop = propsets[0].rgProperties + 1; + ok(prop->dwPropertyID == DBPROP_INIT_OLEDBSERVICES, "[1].dwPropertyID = %lx\n", prop->dwPropertyID); + ok(prop->dwOptions == DBPROPOPTIONS_REQUIRED, "[1].dwOptions = %lx\n", prop->dwOptions); + ok(V_VT(&prop->vValue) == VT_I4, "[1].vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + ok(V_I4(&prop->vValue) == (DBPROPVAL_OS_ENABLEALL & ~DBPROPVAL_OS_CLIENTCURSOR), + "[1].vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + return S_OK; +} + +static IDBPropertiesVtbl dbprops_vtbl = +{ + dbprops_QueryInterface, + dbprops_AddRef, + dbprops_Release, + dbprops_GetProperties, + dbprops_GetPropertyInfo, + dbprops_SetProperties +}; +static IDBProperties dbprops = { &dbprops_vtbl }; + +static HRESULT WINAPI dso_QueryInterface(IDBInitialize *iface, REFIID riid, void **obj) +{ + IID unk = { 0x986f3c20, 0x9879, 0x11d1, { 0xba, 0x17, 0x00, 0xaa, 0x00, 0x0d, 0x96, 0x65 } }; + + if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDBInitialize)) + { + *obj = iface; + return S_OK; + } + if (IsEqualGUID(riid, &IID_IDBProperties)) + { + *obj = &dbprops; + return S_OK; + } + if (IsEqualGUID(riid, &unk)) + { + *obj = NULL; + return E_NOINTERFACE; + } + + ok(0, "unexpected QI(%s)\n", wine_dbgstr_guid(riid)); + *obj = NULL; + return E_NOTIMPL; +} + +static ULONG WINAPI dso_AddRef(IDBInitialize *iface) +{ + return 2; +} + +static ULONG WINAPI dso_Release(IDBInitialize *iface) +{ + return 1; +} + +static HRESULT WINAPI dso_Initialize(IDBInitialize *iface) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI dso_Uninitialize(IDBInitialize *iface) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static IDBInitializeVtbl dso_vtbl = +{ + dso_QueryInterface, + dso_AddRef, + dso_Release, + dso_Initialize, + dso_Uninitialize +}; +static IDBInitialize dso = { &dso_vtbl }; + +static HRESULT WINAPI open_rowset_QueryInterface(IOpenRowset *iface, REFIID riid, void **obj) +{ + if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IOpenRowset)) + { + *obj = iface; + return S_OK; + } + else if (IsEqualGUID(riid, &IID_ISessionProperties)) + CHECK_EXPECT(open_rowset_QI_ISessionProperties); + else if (IsEqualGUID(riid, &IID_IBindResource)) + CHECK_EXPECT(open_rowset_QI_IBindResource); + else if (IsEqualGUID(riid, &IID_ICreateRow)) + CHECK_EXPECT(open_rowset_QI_ICreateRow); + else if (IsEqualGUID(riid, &IID_IDBCreateCommand)) + CHECK_EXPECT2(open_rowset_QI_IDBCreateCommand); + else + ok(0, "unexpected QI(%s)\n", wine_dbgstr_guid(riid)); + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI open_rowset_AddRef(IOpenRowset *iface) +{ + return 2; +} + +static ULONG WINAPI open_rowset_Release(IOpenRowset *iface) +{ + return 1; +} + +static HRESULT WINAPI open_rowset_OpenRowset(IOpenRowset *iface, IUnknown *unk_outer, + DBID *table_id, DBID *index_id, REFIID riid, ULONG propsets_count, + DBPROPSET propsets[], IUnknown **rowset) +{ + static struct test_rowset testrowset; + + CHECK_EXPECT(open_rowset_OpenRowset); + + testrowset.IRowsetExactScroll_iface.lpVtbl = &rowset_vtbl; + testrowset.IRowsetInfo_iface.lpVtbl = &rowset_info; + testrowset.IColumnsInfo_iface.lpVtbl = &column_info; + testrowset.IRowsetUpdate_iface.lpVtbl = &rowset_update; + testrowset.IAccessor_iface.lpVtbl = &accessor; + testrowset.IRowsetView_iface.lpVtbl = &rowset_view; + testrowset.IChapteredRowset_iface.lpVtbl = &chaptered_rowset; + testrowset.IRowsetCurrentIndex_iface.lpVtbl = &rowset_current_index; + testrowset.refs = 1; + testrowset.IViewChapter_iface.lpVtbl = &view_chapter; + testrowset.IViewFilter_iface.lpVtbl = &view_filter; + + *rowset = (IUnknown *)&testrowset.IRowsetExactScroll_iface; + return S_OK; +} + +static IOpenRowsetVtbl open_rowset_vtbl = +{ + open_rowset_QueryInterface, + open_rowset_AddRef, + open_rowset_Release, + open_rowset_OpenRowset +}; +static IOpenRowset open_rowset = { &open_rowset_vtbl }; + +static void test_ADOConnectionConstruction(void) +{ + ADOConnectionConstruction15 *conn_constr; + _Recordset *recordset; + VARIANT v, missing; + _Connection *conn; + LONG state; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_Connection, NULL, CLSCTX_INPROC_SERVER, + &IID__Connection, (void **)&conn); + ok(hr == S_OK, "got %08lx\n", hr); + + hr = _Connection_QueryInterface(conn, &IID_ADOConnectionConstruction15, (void **)&conn_constr); + ok(hr == S_OK, "got %08lx\n", hr); + SET_EXPECT(open_rowset_QI_ISessionProperties); + SET_EXPECT(open_rowset_QI_IBindResource); + SET_EXPECT(open_rowset_QI_ICreateRow); + SET_EXPECT(dbprops_GetProperties); + SET_EXPECT(dbprops_SetProperties); + hr = ADOConnectionConstruction15_WrapDSOandSession(conn_constr, + (IUnknown *)&dso, (IUnknown *)&open_rowset); + todo_wine ok(hr == S_OK, "got %08lx\n", hr); + todo_wine CHECK_CALLED(open_rowset_QI_ISessionProperties); + todo_wine CHECK_CALLED(open_rowset_QI_IBindResource); + todo_wine CHECK_CALLED(open_rowset_QI_ICreateRow); + todo_wine CHECK_CALLED(dbprops_GetProperties); + todo_wine CHECK_CALLED(dbprops_SetProperties); + ADOConnectionConstruction15_Release(conn_constr); + if (hr != S_OK) + { + skip("ADOConnectionConstruction15_WrapDSOandSession not implemented\n"); + _Connection_Release(conn); + return; + } + + hr = _Connection_get_State(conn, &state); + ok(hr == S_OK, "got %08lx\n", hr); + ok(state == adStateOpen, "state = %ld\n", state); + + hr = CoCreateInstance(&CLSID_Recordset, NULL, CLSCTX_INPROC_SERVER, + &IID__Recordset, (void **)&recordset); + ok(hr == S_OK, "got %08lx\n", hr); + + V_VT(&v) = VT_UNKNOWN; + V_UNKNOWN(&v) = (IUnknown *)conn; + hr = _Recordset_put_ActiveConnection(recordset, v); + ok(hr == S_OK, "got %08lx\n", hr); + + V_VT(&v) = VT_BSTR; + V_BSTR(&v) = SysAllocString(L"table name"); + V_VT(&missing) = VT_ERROR; + V_ERROR(&missing) = DISP_E_PARAMNOTFOUND; + SET_EXPECT(open_rowset_QI_IDBCreateCommand); + SET_EXPECT(open_rowset_OpenRowset); + SET_EXPECT(rowset_info_GetProperties); + hr = _Recordset_Open(recordset, v, missing, adOpenKeyset, adLockOptimistic, adCmdUnspecified); + ok(hr == S_OK, "got %08lx\n", hr); + CHECK_CALLED(open_rowset_QI_IDBCreateCommand); + CHECK_CALLED(open_rowset_OpenRowset); + CHECK_CALLED(rowset_info_GetProperties); + VariantClear(&v); + + ok(!_Recordset_Release(recordset), "_Recordset not released\n"); + _Connection_Release(conn); +} + START_TEST(msado15) { CoInitialize( NULL ); setup_database(); + test_ADOConnectionConstruction(); test_Connection(); test_Connection_Open(); test_ConnectionPoint(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9885
From: Piotr Caban <piotr@codeweavers.com> --- dlls/msado15/connection.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/dlls/msado15/connection.c b/dlls/msado15/connection.c index 02bd35c6e95..692e5ed0271 100644 --- a/dlls/msado15/connection.c +++ b/dlls/msado15/connection.c @@ -54,6 +54,7 @@ struct connection LONG refs; ObjectStateEnum state; LONG timeout; + LONG conn_timeout; WCHAR *datasource; WCHAR *provider; ConnectModeEnum mode; @@ -266,14 +267,18 @@ static HRESULT WINAPI connection_put_CommandTimeout( _Connection *iface, LONG ti static HRESULT WINAPI connection_get_ConnectionTimeout( _Connection *iface, LONG *timeout ) { - FIXME( "%p, %p\n", iface, timeout ); - return E_NOTIMPL; + struct connection *connection = impl_from_Connection( iface ); + TRACE( "%p, %p\n", connection, timeout ); + *timeout = connection->conn_timeout; + return S_OK; } static HRESULT WINAPI connection_put_ConnectionTimeout( _Connection *iface, LONG timeout ) { - FIXME( "%p, %ld\n", iface, timeout ); - return E_NOTIMPL; + struct connection *connection = impl_from_Connection( iface ); + TRACE( "%p, %ld\n", connection, timeout ); + connection->conn_timeout = timeout; + return S_OK; } static HRESULT WINAPI connection_get_Version( _Connection *iface, BSTR *str ) @@ -984,6 +989,7 @@ HRESULT Connection_create( void **obj ) connection->refs = 1; connection->state = adStateClosed; connection->timeout = 30; + connection->conn_timeout = 15; connection->datasource = NULL; if (!(connection->provider = wcsdup( L"MSDASQL" ))) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9885
From: Piotr Caban <piotr@codeweavers.com> --- dlls/msado15/connection.c | 106 +++++++++++++++++++++++------------ dlls/msado15/tests/msado15.c | 12 +--- 2 files changed, 72 insertions(+), 46 deletions(-) diff --git a/dlls/msado15/connection.c b/dlls/msado15/connection.c index 692e5ed0271..df8571f978e 100644 --- a/dlls/msado15/connection.c +++ b/dlls/msado15/connection.c @@ -60,6 +60,7 @@ struct connection ConnectModeEnum mode; CursorLocationEnum location; IUnknown *session; + BOOL dso_initialized; IDBInitialize *dso; struct connection_point cp_connev; }; @@ -108,12 +109,7 @@ static ULONG WINAPI connection_Release( _Connection *iface ) if (connection->cp_connev.sinks[i]) IUnknown_Release( connection->cp_connev.sinks[i] ); } - if (connection->session) IUnknown_Release( connection->session ); - if (connection->dso) - { - IDBInitialize_Uninitialize( connection->dso ); - IDBInitialize_Release( connection->dso ); - } + _Connection_Close( iface ); free( connection->cp_connev.sinks ); free( connection->provider ); free( connection->datasource ); @@ -304,7 +300,8 @@ static HRESULT WINAPI connection_Close( _Connection *iface ) } if (connection->dso) { - IDBInitialize_Uninitialize( connection->dso ); + if (connection->dso_initialized) + IDBInitialize_Uninitialize( connection->dso ); IDBInitialize_Release( connection->dso ); connection->dso = NULL; } @@ -390,50 +387,51 @@ static HRESULT WINAPI connection_Open( _Connection *iface, BSTR connect_str, BST LONG options ) { struct connection *connection = impl_from_Connection( iface ); - IDBProperties *props; + IDBCreateSession *create_session; + BOOL dso_initialized = FALSE; IDataInitialize *datainit; - IDBCreateSession *session = NULL; + IDBInitialize *dso = NULL; + IUnknown *session = NULL; HRESULT hr; TRACE( "%p, %s, %s, %p, %08lx\n", iface, debugstr_w(connect_str), debugstr_w(userid), password, options ); + /* TODO - Update username/password if required. */ + if ((userid && *userid) || (password && *password)) + FIXME("Username/password parameters currently not supported\n"); + if (connection->state == adStateOpen) return MAKE_ADO_HRESULT( adErrObjectOpen ); if (!connect_str) return E_FAIL; if ((hr = CoCreateInstance( &CLSID_MSDAINITIALIZE, NULL, CLSCTX_INPROC_SERVER, &IID_IDataInitialize, (void **)&datainit )) != S_OK) return hr; - if ((hr = IDataInitialize_GetDataSource( datainit, NULL, CLSCTX_INPROC_SERVER, connect_str, &IID_IDBInitialize, - (IUnknown **)&connection->dso )) != S_OK) goto done; - if ((hr = IDBInitialize_QueryInterface( connection->dso, &IID_IDBProperties, (void **)&props )) != S_OK) goto done; + hr = IDataInitialize_GetDataSource( datainit, NULL, CLSCTX_INPROC_SERVER, connect_str, + &IID_IDBInitialize, (IUnknown **)&dso); + IDataInitialize_Release( datainit ); + if (hr != S_OK) goto done; - /* TODO - Update username/password if required. */ - if ((userid && *userid) || (password && *password)) - FIXME("Username/password parameters currently not supported\n"); + if ((hr = IDBInitialize_Initialize( dso )) != S_OK) goto done; + dso_initialized = TRUE; - if ((hr = IDBInitialize_Initialize( connection->dso )) != S_OK) goto done; - if ((hr = IDBInitialize_QueryInterface( connection->dso, &IID_IDBCreateSession, (void **)&session )) != S_OK) goto done; - if ((hr = IDBCreateSession_CreateSession( session, NULL, &IID_IUnknown, &connection->session )) == S_OK) + hr = IDBInitialize_QueryInterface( dso, &IID_IDBCreateSession, (void **)&create_session ); + if (hr == S_OK) { - connection->state = adStateOpen; + hr = IDBCreateSession_CreateSession( create_session, NULL, &IID_IUnknown, &session ); + IDBCreateSession_Release( create_session ); } - IDBCreateSession_Release( session ); + if (hr != S_OK) goto done; -done: - if (hr != S_OK) + hr = ADOConnectionConstruction15_WrapDSOandSession( + &connection->ADOConnectionConstruction15_iface, (IUnknown *)dso, session ); + if (hr == S_OK) { - if(connection->session) - IUnknown_Release( connection->session ); - connection->session = NULL; - - if (connection->dso) - { - IDBInitialize_Uninitialize( connection->dso ); - IDBInitialize_Release( connection->dso ); - } - connection->dso = NULL; + connection->dso_initialized = TRUE; + dso_initialized = FALSE; } - - IDataInitialize_Release( datainit ); +done: + if (session) IUnknown_Release( session ); + if (dso_initialized) IDBInitialize_Uninitialize( dso ); + if (dso) IDBInitialize_Release( dso ); TRACE("ret 0x%08lx\n", hr); return hr; @@ -963,8 +961,42 @@ static HRESULT WINAPI adoconstruct_WrapDSOandSession(ADOConnectionConstruction15 IUnknown *session) { struct connection *connection = impl_from_ADOConnectionConstruction15( iface ); - FIXME("%p, %p, %p\n", connection, dso, session); - return E_NOTIMPL; + IDBInitialize *dbinit; + IDBProperties *props; + DBPROPSET propset; + DBPROP prop[2]; + HRESULT hr; + + TRACE("%p, %p, %p\n", connection, dso, session); + + hr = IUnknown_QueryInterface( dso, &IID_IDBProperties, (void **)&props ); + if (FAILED(hr)) return hr; + propset.guidPropertySet = DBPROPSET_DBINIT; + propset.cProperties = ARRAY_SIZE(prop); + propset.rgProperties = prop; + memset(prop, 0, sizeof(prop)); + prop[0].dwPropertyID = DBPROP_INIT_TIMEOUT; + prop[0].dwOptions = DBPROPOPTIONS_OPTIONAL; + V_VT(&prop[0].vValue) = VT_I4; + V_I4(&prop[0].vValue) = connection->conn_timeout; + prop[1].dwPropertyID = DBPROP_INIT_OLEDBSERVICES; + prop[1].dwOptions = DBPROPOPTIONS_REQUIRED; + V_VT(&prop[1].vValue) = VT_I4; + V_I4(&prop[1].vValue) = DBPROPVAL_OS_ENABLEALL; + if (connection->location != adUseClient) + V_I4(&prop[1].vValue) &= ~DBPROPVAL_OS_CLIENTCURSOR; + hr = IDBProperties_SetProperties( props, 1, &propset ); + IDBProperties_Release( props ); + if (FAILED(hr)) FIXME("SetProperties failed: %lx\n", hr); + + hr = IUnknown_QueryInterface( dso, &IID_IDBInitialize, (void **)&dbinit ); + if (FAILED(hr)) return hr; + + connection->dso = dbinit; + connection->session = session; + IUnknown_AddRef( session ); + connection->state = adStateOpen; + return S_OK; } struct ADOConnectionConstruction15Vtbl ado_construct_vtbl = @@ -981,7 +1013,7 @@ HRESULT Connection_create( void **obj ) { struct connection *connection; - if (!(connection = malloc( sizeof(*connection) ))) return E_OUTOFMEMORY; + if (!(connection = calloc( 1, sizeof(*connection) ))) return E_OUTOFMEMORY; connection->Connection_iface.lpVtbl = &connection_vtbl; connection->ISupportErrorInfo_iface.lpVtbl = &support_error_vtbl; connection->IConnectionPointContainer_iface.lpVtbl = &connpointcontainer_vtbl; diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index fc9b92cbbbe..de6a112a99a 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -3437,19 +3437,13 @@ static void test_ADOConnectionConstruction(void) SET_EXPECT(dbprops_SetProperties); hr = ADOConnectionConstruction15_WrapDSOandSession(conn_constr, (IUnknown *)&dso, (IUnknown *)&open_rowset); - todo_wine ok(hr == S_OK, "got %08lx\n", hr); + ok(hr == S_OK, "got %08lx\n", hr); todo_wine CHECK_CALLED(open_rowset_QI_ISessionProperties); todo_wine CHECK_CALLED(open_rowset_QI_IBindResource); todo_wine CHECK_CALLED(open_rowset_QI_ICreateRow); todo_wine CHECK_CALLED(dbprops_GetProperties); - todo_wine CHECK_CALLED(dbprops_SetProperties); + CHECK_CALLED(dbprops_SetProperties); ADOConnectionConstruction15_Release(conn_constr); - if (hr != S_OK) - { - skip("ADOConnectionConstruction15_WrapDSOandSession not implemented\n"); - _Connection_Release(conn); - return; - } hr = _Connection_get_State(conn, &state); ok(hr == S_OK, "got %08lx\n", hr); @@ -3473,7 +3467,7 @@ static void test_ADOConnectionConstruction(void) SET_EXPECT(rowset_info_GetProperties); hr = _Recordset_Open(recordset, v, missing, adOpenKeyset, adLockOptimistic, adCmdUnspecified); ok(hr == S_OK, "got %08lx\n", hr); - CHECK_CALLED(open_rowset_QI_IDBCreateCommand); + todo_wine CHECK_CALLED(open_rowset_QI_IDBCreateCommand); CHECK_CALLED(open_rowset_OpenRowset); CHECK_CALLED(rowset_info_GetProperties); VariantClear(&v); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9885
From: Piotr Caban <piotr@codeweavers.com> --- dlls/msado15/recordset.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index a6330ed5d9f..b14ffb14341 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -2624,9 +2624,10 @@ static HRESULT WINAPI recordset_Open( _Recordset *iface, VARIANT source, VARIANT return hr; } + if (cursor_type == adOpenUnspecified) cursor_type = adOpenForwardOnly; _Recordset_put_CursorType( iface, cursor_type ); - if (lock_type < adLockReadOnly) lock_type = adLockReadOnly; - _Recordset_put_LockType( iface, lock_type ); + if (lock_type != adLockUnspecified) + _Recordset_put_LockType( iface, lock_type ); if (recordset->fields.count != -1) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9885
From: Piotr Caban <piotr@codeweavers.com> --- dlls/msado15/recordset.c | 119 +++++++++++++++++++++++------ dlls/msado15/tests/msado15.c | 144 +++++++++++++++++++++++++++++++++++ 2 files changed, 241 insertions(+), 22 deletions(-) diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index b14ffb14341..e83ce92ab9b 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -28,6 +28,9 @@ #include "oledberr.h" #include "sqlucode.h" +#include "initguid.h" +#include "msdasql.h" + #include "wine/rbtree.h" #include "wine/debug.h" @@ -2521,24 +2524,40 @@ static HRESULT WINAPI recordset_MoveLast( _Recordset *iface ) return cache_get( recordset, FALSE ); } -static inline void set_bool_prop(DBPROP *prop, DBPROPID id, BOOL b) +static inline void add_bool_prop(DBPROPSET *propset, DWORD options, DBPROPID id, BOOL b) { + DBPROP *prop = propset->rgProperties + propset->cProperties; + prop->dwPropertyID = id; + prop->dwOptions = options; V_VT(&prop->vValue) = VT_BOOL; V_BOOL(&prop->vValue) = b ? VARIANT_TRUE : VARIANT_FALSE; + propset->cProperties++; +} + +static inline void add_int_prop(DBPROPSET *propset, DWORD options, DBPROPID id, int v) +{ + DBPROP *prop = propset->rgProperties + propset->cProperties; + + prop->dwPropertyID = id; + prop->dwOptions = options; + V_VT(&prop->vValue) = VT_I4; + V_I4(&prop->vValue) = v; + propset->cProperties++; } static HRESULT get_rowset(struct recordset *recordset, IUnknown *session, BSTR source, IUnknown **rowset) { + DBPROP props[17], provider_props[3]; IDBCreateCommand *create_command; ICommandText *command_text; IOpenRowset *openrowset; + DBPROPSET propsets[2]; DBROWCOUNT affected; - DBPROPSET propset; - DBPROP props[10]; ICommand *cmd; DBID table; HRESULT hr; + int i; hr = IUnknown_QueryInterface(session, &IID_IOpenRowset, (void**)&openrowset); if (FAILED(hr)) @@ -2547,26 +2566,82 @@ static HRESULT get_rowset(struct recordset *recordset, IUnknown *session, BSTR s table.eKind = DBKIND_NAME; table.uName.pwszName = source; - propset.guidPropertySet = DBPROPSET_ROWSET; - propset.cProperties = ARRAY_SIZE(props); - propset.rgProperties = props; + propsets[0].guidPropertySet = DBPROPSET_ROWSET; + propsets[0].cProperties = 0; + propsets[0].rgProperties = props; memset(props, 0, sizeof(props)); - set_bool_prop(props, DBPROP_CANSCROLLBACKWARDS, recordset->cursor_type != adOpenForwardOnly); - set_bool_prop(props + 1, DBPROP_OTHERINSERT, - recordset->cursor_type != adOpenStatic && recordset->cursor_type != adOpenKeyset); - set_bool_prop(props + 2, DBPROP_OTHERUPDATEDELETE, recordset->cursor_type != adOpenStatic); - props[3].dwPropertyID = DBPROP_UPDATABILITY; - V_VT(&props[3].vValue) = VT_I4; - V_I4(&props[3].vValue) = (recordset->lock_type == adLockReadOnly ? 0 : - DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_DELETE | DBPROPVAL_UP_INSERT); - set_bool_prop(props + 4, DBPROP_IColumnsRowset, TRUE); - set_bool_prop(props + 5, DBPROP_IRowsetChange, recordset->lock_type != adLockReadOnly); - set_bool_prop(props + 6, DBPROP_IRowsetLocate, TRUE); - set_bool_prop(props + 7, DBPROP_IRowsetUpdate, recordset->lock_type != adLockReadOnly); - set_bool_prop(props + 8, DBPROP_IRowsetIndex, TRUE); - set_bool_prop(props + 9, DBPROP_IRowsetCurrentIndex, TRUE); - - hr = IOpenRowset_OpenRowset(openrowset, NULL, &table, NULL, &IID_IUnknown, 1, &propset, rowset); + add_bool_prop(propsets, DBPROPOPTIONS_REQUIRED, DBPROP_IRowset, TRUE); + add_bool_prop(propsets, DBPROPOPTIONS_OPTIONAL, DBPROP_IColumnsRowset, TRUE); + if (recordset->cursor_type == adOpenForwardOnly) + add_bool_prop(propsets, DBPROPOPTIONS_REQUIRED, DBPROP_OWNUPDATEDELETE, 0); + add_bool_prop(propsets, DBPROPOPTIONS_OPTIONAL, DBPROP_IRowsetIndex, TRUE); + add_bool_prop(propsets, DBPROPOPTIONS_OPTIONAL, DBPROP_IRowsetCurrentIndex, TRUE); + if (recordset->cursor_type == adOpenDynamic) + add_bool_prop(propsets, DBPROPOPTIONS_REQUIRED, DBPROP_OTHERINSERT, TRUE); + if (recordset->cursor_type == adOpenKeyset) + add_bool_prop(propsets, DBPROPOPTIONS_REQUIRED, DBPROP_OTHERUPDATEDELETE, TRUE); + if (recordset->cursor_type == adOpenKeyset || recordset->cursor_type == adOpenStatic) + { + add_bool_prop(propsets, DBPROPOPTIONS_REQUIRED, DBPROP_OWNINSERT, TRUE); + add_bool_prop(propsets, DBPROPOPTIONS_REQUIRED, DBPROP_OWNUPDATEDELETE, TRUE); + add_bool_prop(propsets, DBPROPOPTIONS_REQUIRED, DBPROP_CANHOLDROWS, TRUE); + } + if (recordset->cursor_type != adOpenForwardOnly) + add_bool_prop(propsets, DBPROPOPTIONS_REQUIRED, DBPROP_CANSCROLLBACKWARDS, TRUE); + if (recordset->cursor_type == adOpenKeyset || recordset->cursor_type == adOpenStatic) + add_bool_prop(propsets, DBPROPOPTIONS_REQUIRED, DBPROP_IRowsetLocate, TRUE); + if (recordset->lock_type != adLockUnspecified) + { + add_bool_prop(propsets, DBPROPOPTIONS_REQUIRED, DBPROP_IRowsetChange, + recordset->lock_type != adLockReadOnly); + add_bool_prop(propsets, DBPROPOPTIONS_REQUIRED, DBPROP_IRowsetUpdate, + recordset->lock_type != adLockReadOnly); + add_int_prop(propsets, DBPROPOPTIONS_REQUIRED, DBPROP_UPDATABILITY, + recordset->lock_type == adLockReadOnly ? + 0 : DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_DELETE | DBPROPVAL_UP_INSERT); + } + if (recordset->cursor_type == adOpenKeyset) + add_bool_prop(propsets, DBPROPOPTIONS_REQUIRED, DBPROP_IRowsetResynch, TRUE); + if (recordset->cursor_type == adOpenKeyset || recordset->cursor_type == adOpenDynamic) + add_bool_prop(propsets, DBPROPOPTIONS_REQUIRED, DBPROP_REMOVEDELETED, TRUE); + if (recordset->cursor_type != adOpenForwardOnly) + add_bool_prop(propsets, DBPROPOPTIONS_REQUIRED, DBPROP_CANFETCHBACKWARDS, TRUE); + add_bool_prop(propsets, DBPROPOPTIONS_REQUIRED, DBPROP_ISequentialStream, TRUE); + + propsets[1].guidPropertySet = DBPROPSET_PROVIDERROWSET; + propsets[1].cProperties = 0; + propsets[1].rgProperties = provider_props; + if (recordset->cursor_type == adOpenKeyset) + add_bool_prop(propsets + 1, DBPROPOPTIONS_REQUIRED, KAGPROP_POSITIONONNEWROW, TRUE); + if (recordset->lock_type != adLockReadOnly) + add_int_prop(propsets + 1, DBPROPOPTIONS_REQUIRED, KAGPROP_CONCURRENCY, + KAGPROPVAL_CONCUR_ROWVER | KAGPROPVAL_CONCUR_VALUES | KAGPROPVAL_CONCUR_READ_ONLY); + if (recordset->cursor_type == adOpenForwardOnly) + add_bool_prop(propsets + 1, DBPROPOPTIONS_REQUIRED, KAGPROP_BLOBSONFOCURSOR, TRUE); + add_bool_prop(propsets + 1, DBPROPOPTIONS_REQUIRED, KAGPROP_FORCENOREEXECUTE, TRUE); + + hr = IOpenRowset_OpenRowset(openrowset, NULL, &table, NULL, &IID_IUnknown, 2, propsets, rowset); + if (hr == DB_E_ERRORSOCCURRED) + { + for (i = 0; i < propsets[1].cProperties; i++) + { + if (propsets[1].rgProperties[i].dwPropertyID == KAGPROP_FORCENOREEXECUTE) + { + propsets[1].rgProperties[i].dwOptions = DBPROPOPTIONS_OPTIONAL; + break; + } + } + hr = IOpenRowset_OpenRowset(openrowset, NULL, &table, NULL, &IID_IUnknown, 2, propsets, rowset); + } + if (hr == DB_E_ERRORSOCCURRED) + { + for (i = 0; i < propsets[0].cProperties; i++) + propsets[0].rgProperties[i].dwOptions = DBPROPOPTIONS_OPTIONAL; + for (i = 0; i < propsets[1].cProperties; i++) + propsets[1].rgProperties[i].dwOptions = DBPROPOPTIONS_OPTIONAL; + + hr = IOpenRowset_OpenRowset(openrowset, NULL, &table, NULL, &IID_IUnknown, 2, propsets, rowset); + } if (SUCCEEDED(hr)) { IOpenRowset_Release(openrowset); diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index de6a112a99a..03424b9e929 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -3387,8 +3387,152 @@ static HRESULT WINAPI open_rowset_OpenRowset(IOpenRowset *iface, IUnknown *unk_o DBPROPSET propsets[], IUnknown **rowset) { static struct test_rowset testrowset; + DBPROP *prop; + int i; CHECK_EXPECT(open_rowset_OpenRowset); + ok(!unk_outer, "unk_outer = %p\n", unk_outer); + ok(table_id != NULL, "table_id = NULL\n"); + ok(table_id->eKind == DBKIND_NAME, "table_id->eKind = %ld\n", table_id->eKind); + ok(!wcscmp(table_id->uName.pwszName, L"table name"), "table_id->pwszName = %s\n", + wine_dbgstr_w(table_id->uName.pwszName)); + ok(!index_id, "index_id != NULL\n"); + ok(IsEqualGUID(riid, &IID_IUnknown), "riid = %s\n", wine_dbgstr_guid(riid)); + ok(propsets_count == 2, "propsets_count = %lu\n", propsets_count); + + ok(IsEqualGUID(&propsets[0].guidPropertySet, &DBPROPSET_ROWSET), + "guidPropertySet = %s\n", wine_dbgstr_guid(&propsets[0].guidPropertySet)); + ok(propsets[0].cProperties == 17, "cProperties = %lu\n", propsets[0].cProperties); + for (i = 0; i < propsets[0].cProperties; i++) + { + prop = propsets[0].rgProperties + i; + + winetest_push_context("dwPropertyID = %lx", prop->dwPropertyID); + switch (prop->dwPropertyID) + { + case DBPROP_IRowset: + ok(prop->dwOptions == DBPROPOPTIONS_REQUIRED, "dwOptions = %ld\n", prop->dwOptions); + ok(V_VT(&prop->vValue) == VT_BOOL, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + ok(V_BOOL(&prop->vValue) == VARIANT_TRUE, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + break; + case DBPROP_IColumnsRowset: + ok(prop->dwOptions == DBPROPOPTIONS_OPTIONAL, "dwOptions = %ld\n", prop->dwOptions); + ok(V_VT(&prop->vValue) == VT_BOOL, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + ok(V_BOOL(&prop->vValue) == VARIANT_TRUE, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + break; + case DBPROP_IRowsetIndex: + ok(prop->dwOptions == DBPROPOPTIONS_OPTIONAL, "dwOptions = %ld\n", prop->dwOptions); + ok(V_VT(&prop->vValue) == VT_BOOL, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + ok(V_BOOL(&prop->vValue) == VARIANT_TRUE, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + break; + case DBPROP_IRowsetCurrentIndex: + ok(prop->dwOptions == DBPROPOPTIONS_OPTIONAL, "dwOptions = %ld\n", prop->dwOptions); + ok(V_VT(&prop->vValue) == VT_BOOL, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + ok(V_BOOL(&prop->vValue) == VARIANT_TRUE, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + break; + case DBPROP_OTHERUPDATEDELETE: + ok(prop->dwOptions == DBPROPOPTIONS_REQUIRED, "dwOptions = %ld\n", prop->dwOptions); + ok(V_VT(&prop->vValue) == VT_BOOL, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + ok(V_BOOL(&prop->vValue) == VARIANT_TRUE, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + break; + case DBPROP_OWNINSERT: + ok(prop->dwOptions == DBPROPOPTIONS_REQUIRED, "dwOptions = %ld\n", prop->dwOptions); + ok(V_VT(&prop->vValue) == VT_BOOL, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + ok(V_BOOL(&prop->vValue) == VARIANT_TRUE, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + break; + case DBPROP_OWNUPDATEDELETE: + ok(prop->dwOptions == DBPROPOPTIONS_REQUIRED, "dwOptions = %ld\n", prop->dwOptions); + ok(V_VT(&prop->vValue) == VT_BOOL, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + ok(V_BOOL(&prop->vValue) == VARIANT_TRUE, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + break; + case DBPROP_CANHOLDROWS: + ok(prop->dwOptions == DBPROPOPTIONS_REQUIRED, "dwOptions = %ld\n", prop->dwOptions); + ok(V_VT(&prop->vValue) == VT_BOOL, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + ok(V_BOOL(&prop->vValue) == VARIANT_TRUE, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + break; + case DBPROP_CANSCROLLBACKWARDS: + ok(prop->dwOptions == DBPROPOPTIONS_REQUIRED, "dwOptions = %ld\n", prop->dwOptions); + ok(V_VT(&prop->vValue) == VT_BOOL, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + ok(V_BOOL(&prop->vValue) == VARIANT_TRUE, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + break; + case DBPROP_IRowsetLocate: + ok(prop->dwOptions == DBPROPOPTIONS_REQUIRED, "dwOptions = %ld\n", prop->dwOptions); + ok(V_VT(&prop->vValue) == VT_BOOL, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + ok(V_BOOL(&prop->vValue) == VARIANT_TRUE, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + break; + case DBPROP_IRowsetChange: + ok(prop->dwOptions == DBPROPOPTIONS_REQUIRED, "dwOptions = %ld\n", prop->dwOptions); + ok(V_VT(&prop->vValue) == VT_BOOL, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + ok(V_BOOL(&prop->vValue) == VARIANT_TRUE, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + break; + case DBPROP_IRowsetUpdate: + ok(prop->dwOptions == DBPROPOPTIONS_REQUIRED, "dwOptions = %ld\n", prop->dwOptions); + ok(V_VT(&prop->vValue) == VT_BOOL, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + ok(V_BOOL(&prop->vValue) == VARIANT_TRUE, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + break; + case DBPROP_UPDATABILITY: + ok(prop->dwOptions == DBPROPOPTIONS_REQUIRED, "dwOptions = %ld\n", prop->dwOptions); + ok(V_VT(&prop->vValue) == VT_I4, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + ok(V_I4(&prop->vValue) == (DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_DELETE | DBPROPVAL_UP_INSERT), + "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + break; + case DBPROP_IRowsetResynch: + ok(prop->dwOptions == DBPROPOPTIONS_REQUIRED, "dwOptions = %ld\n", prop->dwOptions); + ok(V_VT(&prop->vValue) == VT_BOOL, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + ok(V_BOOL(&prop->vValue) == VARIANT_TRUE, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + break; + case DBPROP_REMOVEDELETED: + ok(prop->dwOptions == DBPROPOPTIONS_REQUIRED, "dwOptions = %ld\n", prop->dwOptions); + ok(V_VT(&prop->vValue) == VT_BOOL, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + ok(V_BOOL(&prop->vValue) == VARIANT_TRUE, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + break; + case DBPROP_CANFETCHBACKWARDS: + ok(prop->dwOptions == DBPROPOPTIONS_REQUIRED, "dwOptions = %ld\n", prop->dwOptions); + ok(V_VT(&prop->vValue) == VT_BOOL, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + ok(V_BOOL(&prop->vValue) == VARIANT_TRUE, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + break; + case DBPROP_ISequentialStream: + ok(prop->dwOptions == DBPROPOPTIONS_REQUIRED, "dwOptions = %ld\n", prop->dwOptions); + ok(V_VT(&prop->vValue) == VT_BOOL, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + ok(V_BOOL(&prop->vValue) == VARIANT_TRUE, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + break; + default: + ok(0, "vValue = %s (%lx)\n", wine_dbgstr_variant(&prop->vValue), prop->dwOptions); + } + winetest_pop_context(); + } + + ok(IsEqualGUID(&propsets[1].guidPropertySet, &DBPROPSET_PROVIDERROWSET), + "guidPropertySet = %s\n", wine_dbgstr_guid(&propsets[1].guidPropertySet)); + ok(propsets[1].cProperties == 3, "cProperties = %lu\n", propsets[1].cProperties); + for (i = 0; i < propsets[1].cProperties; i++) + { + prop = propsets[1].rgProperties + i; + + winetest_push_context("dwPropertyID = %lx", prop->dwPropertyID); + switch (prop->dwPropertyID) + { + case KAGPROP_POSITIONONNEWROW: + ok(prop->dwOptions == DBPROPOPTIONS_REQUIRED, "dwOptions = %ld\n", prop->dwOptions); + ok(V_VT(&prop->vValue) == VT_BOOL, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + ok(V_BOOL(&prop->vValue) == VARIANT_TRUE, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + break; + case KAGPROP_CONCURRENCY: + ok(prop->dwOptions == DBPROPOPTIONS_REQUIRED, "dwOptions = %ld\n", prop->dwOptions); + ok(V_VT(&prop->vValue) == VT_I4, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + ok(V_I4(&prop->vValue) == (KAGPROPVAL_CONCUR_ROWVER | KAGPROPVAL_CONCUR_VALUES | KAGPROPVAL_CONCUR_READ_ONLY), + "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + break; + case KAGPROP_FORCENOREEXECUTE: + ok(prop->dwOptions == DBPROPOPTIONS_REQUIRED, "dwOptions = %ld\n", prop->dwOptions); + ok(V_VT(&prop->vValue) == VT_BOOL, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + ok(V_BOOL(&prop->vValue) == VARIANT_TRUE, "vValue = %s\n", wine_dbgstr_variant(&prop->vValue)); + break; + default: + ok(0, "vValue = %s (%lx)\n", wine_dbgstr_variant(&prop->vValue), prop->dwOptions); + } + winetest_pop_context(); + } testrowset.IRowsetExactScroll_iface.lpVtbl = &rowset_vtbl; testrowset.IRowsetInfo_iface.lpVtbl = &rowset_info; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9885
From: Piotr Caban <piotr@codeweavers.com> --- dlls/msado15/recordset.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index e83ce92ab9b..c760cbabbd2 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -1737,6 +1737,7 @@ static ULONG WINAPI recordset_Release( _Recordset *iface ) { TRACE( "destroying %p\n", recordset ); close_recordset( recordset ); + if (recordset->active_connection) _Connection_Release( recordset->active_connection ); free( recordset->fields.field ); free( recordset->cache.rows ); free( recordset ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9885
participants (2)
-
Piotr Caban -
Piotr Caban (@piotr)