This patches allows setting/retrieving LockType. We don't take it into account while updating values.
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 2412890f7e4..6cb3b38e746 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -1960,6 +1960,7 @@ static HRESULT WINAPI recordset_put_CacheSize( _Recordset *iface, LONG size ) { if (V_VT(&propset->rgProperties[0].vValue) == VT_I4) recordset->cache.max_size = V_I4(&propset->rgProperties[0].vValue); + VariantClear( &propset->rgProperties[0].vValue ); CoTaskMemFree( propset->rgProperties ); CoTaskMemFree( propset ); }
From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/rowset.c | 118 +++++++++++++++++++++++++++++++----------- 1 file changed, 87 insertions(+), 31 deletions(-)
diff --git a/dlls/msado15/rowset.c b/dlls/msado15/rowset.c index 14d7788adf8..589bbae66d8 100644 --- a/dlls/msado15/rowset.c +++ b/dlls/msado15/rowset.c @@ -948,49 +948,105 @@ static HRESULT WINAPI rowset_info_GetProperties(IRowsetInfo *iface, const ULONG const DBPROPIDSET propidsets[], ULONG *count, DBPROPSET **propsets) { struct rowset *rowset = impl_from_IRowsetInfo(iface); - ULONG i, j, c = 0; - DBPROP *prop; + BOOL prop_fail = FALSE, prop_succ = FALSE; + int i, j;
TRACE("%p, %lu, %p, %p, %p\n", rowset, propidsets_count, propidsets, count, propsets);
- for (i = 0; i <propidsets_count; i++) + *count = 0; + *propsets = CoTaskMemAlloc(sizeof(**propsets) * propidsets_count); + for (i = 0; i < propidsets_count; i++) { - if (!IsEqualGUID(&DBPROPSET_ROWSET, &propidsets[i].guidPropertySet)) - { - FIXME("property set: %s\n", wine_dbgstr_guid(&propidsets[i].guidPropertySet)); - return E_NOTIMPL; - } + size_t size = sizeof(*(*propsets)[i].rgProperties) * propidsets[i].cPropertyIDs; + DBPROPSTATUS *status; + VARIANT *v; + + (*propsets)[i].rgProperties = CoTaskMemAlloc(size); + memset((*propsets)[i].rgProperties, 0, size); + (*propsets)[i].cProperties = propidsets[i].cPropertyIDs; + (*propsets)[i].guidPropertySet = propidsets[i].guidPropertySet;
for (j = 0; j < propidsets[i].cPropertyIDs; j++) { - if (propidsets[i].rgPropertyIDs[j] != DBPROP_BOOKMARKS) + (*propsets)[i].rgProperties[j].dwPropertyID = propidsets[i].rgPropertyIDs[j]; + status = &(*propsets)[i].rgProperties[j].dwStatus; + v = &(*propsets)[i].rgProperties[j].vValue; + + if (IsEqualGUID(&propidsets[i].guidPropertySet, &DBPROPSET_ROWSET)) { - FIXME("DBPROPSET_ROWSET property %lu\n", propidsets[i].rgPropertyIDs[j]); - return E_NOTIMPL; + switch (propidsets[i].rgPropertyIDs[j]) + { + case DBPROP_OTHERUPDATEDELETE: + V_VT(v) = VT_BOOL; + V_BOOL(v) = VARIANT_FALSE; + prop_succ = TRUE; + break; + case DBPROP_OTHERINSERT: + V_VT(v) = VT_BOOL; + V_BOOL(v) = VARIANT_FALSE; + break; + case DBPROP_CANHOLDROWS: + V_VT(v) = VT_BOOL; + V_BOOL(v) = VARIANT_TRUE; + break; + case DBPROP_CANSCROLLBACKWARDS: + V_VT(v) = VT_BOOL; + V_BOOL(v) = VARIANT_TRUE; + break; + case DBPROP_UPDATABILITY: + V_VT(v) = VT_I4; + V_I4(v) = DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_DELETE | DBPROPVAL_UP_INSERT; + break; + case DBPROP_IRowsetLocate: + V_VT(v) = VT_BOOL; + V_BOOL(v) = VARIANT_TRUE; + break; + case DBPROP_IRowsetScroll: + V_VT(v) = VT_BOOL; + V_BOOL(v) = VARIANT_TRUE; + break; + case DBPROP_IRowsetUpdate: + V_VT(v) = VT_BOOL; + V_BOOL(v) = VARIANT_TRUE; + break; + case DBPROP_BOOKMARKSKIPPED: + V_VT(v) = VT_BOOL; + V_BOOL(v) = VARIANT_TRUE; + break; + case DBPROP_LOCKMODE: + *status = DBPROPSTATUS_NOTSUPPORTED; + prop_fail = TRUE; + break; + case DBPROP_IRowsetCurrentIndex: + *status = DBPROPSTATUS_NOTSUPPORTED; + prop_fail = TRUE; + break; + case DBPROP_REMOVEDELETED: + V_VT(v) = VT_BOOL; + V_BOOL(v) = VARIANT_TRUE; + break; + default: + FIXME("unsupported DBPROPSET_ROWSET property %ld\n", + propidsets[i].rgPropertyIDs[j]); + *status = DBPROPSTATUS_NOTSUPPORTED; + prop_fail = TRUE; + break; + } + } + else + { + FIXME("unsupported property %s %ld\n", + wine_dbgstr_guid(&propidsets[i].guidPropertySet), + propidsets[i].rgPropertyIDs[j]); + *status = DBPROPSTATUS_NOTSUPPORTED; + prop_fail = TRUE; } - c++; } } - if (c != 1) return E_NOTIMPL; - - prop = CoTaskMemAlloc(sizeof(*prop)); - if (!prop) return E_OUTOFMEMORY; - *propsets = CoTaskMemAlloc(sizeof(**propsets)); - if (!*propsets) - { - CoTaskMemFree(prop); - return E_OUTOFMEMORY; - }
- *count = 1; - (*propsets)->rgProperties = prop; - (*propsets)->cProperties = 1; - (*propsets)->guidPropertySet = DBPROPSET_ROWSET; - memset(prop, 0, sizeof(*prop)); - prop->dwPropertyID = DBPROP_BOOKMARKS; - V_VT(&prop->vValue) = VT_BOOL; - V_BOOL(&prop->vValue) = VARIANT_TRUE; - return S_OK; + *count = propidsets_count; + if (!prop_succ) return DB_E_ERRORSOCCURRED; + return prop_fail ? DB_S_ERRORSOCCURRED : S_OK; }
static HRESULT WINAPI rowset_info_GetReferencedRowset(IRowsetInfo *iface,
From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/recordset.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index 6cb3b38e746..5dcf98269d7 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -93,6 +93,7 @@ struct recordset struct fields fields; CursorLocationEnum cursor_location; CursorTypeEnum cursor_type; + LockTypeEnum lock_type; IRowset *row_set; IRowsetLocate *rowset_locate; IRowsetExactScroll *rowset_es; @@ -2033,14 +2034,28 @@ static HRESULT WINAPI recordset_get_Fields( _Recordset *iface, Fields **obj )
static HRESULT WINAPI recordset_get_LockType( _Recordset *iface, LockTypeEnum *lock_type ) { - FIXME( "%p, %p\n", iface, lock_type ); - return E_NOTIMPL; + struct recordset *recordset = impl_from_Recordset( iface ); + + TRACE( "%p, %p\n", iface, lock_type ); + + if (!lock_type) return MAKE_ADO_HRESULT( adErrInvalidArgument ); + + *lock_type = recordset->lock_type; + return S_OK; }
static HRESULT WINAPI recordset_put_LockType( _Recordset *iface, LockTypeEnum lock_type ) { - FIXME( "%p, %d\n", iface, lock_type ); - return E_NOTIMPL; + struct recordset *recordset = impl_from_Recordset( iface ); + + TRACE( "%p, %d\n", iface, lock_type ); + + if (recordset->state == adStateOpen) return MAKE_ADO_HRESULT( adErrObjectOpen ); + if (lock_type < adLockReadOnly || lock_type > adLockBatchOptimistic) + return MAKE_ADO_HRESULT( adErrInvalidArgument ); + + recordset->lock_type = lock_type; + return S_OK; }
static HRESULT WINAPI recordset_get_MaxRecords( _Recordset *iface, ADO_LONGPTR *max_records ) @@ -3133,6 +3148,7 @@ HRESULT Recordset_create( void **obj ) recordset->refs = 1; recordset->cursor_location = adUseServer; recordset->cursor_type = adOpenForwardOnly; + recordset->lock_type = adLockReadOnly; recordset->row_set = NULL; recordset->editmode = adEditNone; recordset->cache.alloc = 1;
From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/recordset.c | 86 +++++++++++++++++++++++++++++++++++- dlls/msado15/tests/msado15.c | 37 +++++++++++++++- 2 files changed, 119 insertions(+), 4 deletions(-)
diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index 5dcf98269d7..ffe3b2168b3 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -120,6 +120,9 @@ struct recordset HACCESSOR bookmark_hacc; DBTYPE bookmark_type; VARIANT bookmark; + + ULONG prop_count; + DBPROPSET *prop; };
static inline struct field *impl_from_Field( Field *iface ) @@ -1609,7 +1612,7 @@ static ULONG WINAPI recordset_AddRef( _Recordset *iface )
static void close_recordset( struct recordset *recordset ) { - int i; + int i, j;
cache_release( recordset ); recordset->is_bof = recordset->is_eof = VARIANT_FALSE; @@ -1659,6 +1662,16 @@ static void close_recordset( struct recordset *recordset ) if (recordset->accessor && recordset->accessor != NO_INTERFACE ) IAccessor_Release( recordset->accessor ); recordset->accessor = NULL; + + for (i = 0; i < recordset->prop_count; i++) + { + for (j = 0; j < recordset->prop[i].cProperties; j++) + VariantClear( &recordset->prop[i].rgProperties[j].vValue ); + CoTaskMemFree( recordset->prop[i].rgProperties ); + } + CoTaskMemFree( recordset->prop ); + recordset->prop_count = 0; + recordset->prop = NULL; }
static ULONG WINAPI recordset_Release( _Recordset *iface ) @@ -2382,6 +2395,10 @@ static HRESULT WINAPI recordset_Open( _Recordset *iface, VARIANT source, VARIANT return hr; }
+ _Recordset_put_CursorType( iface, cursor_type ); + if (lock_type < adLockReadOnly) lock_type = adLockReadOnly; + _Recordset_put_LockType( iface, lock_type ); + if (recordset->fields.count != -1) { DBCOLUMNINFO *info; @@ -2456,7 +2473,6 @@ static HRESULT WINAPI recordset_Open( _Recordset *iface, VARIANT source, VARIANT
hr = ADORecordsetConstruction_put_Rowset(&recordset->ADORecordsetConstruction_iface, rowset); IUnknown_Release(rowset); - recordset->cursor_type = cursor_type; return hr; }
@@ -3071,11 +3087,51 @@ static void init_bookmark( struct recordset *recordset ) CoTaskMemFree( colinfo ); }
+static BOOL recordset_get_prop( struct recordset *recordset, + const GUID *prop_set, DWORD propid, VARIANT *v ) +{ + HRESULT hr = E_FAIL; + int i, j; + + for (i = 0; i < recordset->prop_count; i++) + { + if (!IsEqualGUID( &recordset->prop[i].guidPropertySet, prop_set )) continue; + + for (j=0; j < recordset->prop[i].cProperties; j++) + { + if (recordset->prop[i].rgProperties[j].dwStatus == DBPROPSTATUS_OK && + recordset->prop[i].rgProperties[j].dwPropertyID == propid) + { + *v = recordset->prop[i].rgProperties[j].vValue; + break; + } + } + if (j != recordset->prop[i].cProperties) break; + } + if (i == recordset->prop_count) return FALSE; + + if (IsEqualGUID( prop_set, &DBPROPSET_ROWSET )) + { + switch (propid) + { + case DBPROP_UPDATABILITY: + hr = VariantChangeType( v, v, 0, VT_I4 ); + break; + case DBPROP_IRowsetUpdate: + hr = VariantChangeType( v, v, 0, VT_BOOL ); + break; + } + } + return SUCCEEDED( hr ); +} + static HRESULT WINAPI rsconstruction_put_Rowset(ADORecordsetConstruction *iface, IUnknown *unk) { struct recordset *recordset = impl_from_ADORecordsetConstruction( iface ); + IRowsetInfo *rowset_info; IRowset *rowset; HRESULT hr; + VARIANT v;
TRACE( "%p, %p\n", recordset, unk );
@@ -3086,6 +3142,32 @@ static HRESULT WINAPI rsconstruction_put_Rowset(ADORecordsetConstruction *iface, recordset->row_set = rowset; recordset->state = adStateOpen;
+ hr = IRowset_QueryInterface( rowset, &IID_IRowsetInfo, (void**)&rowset_info ); + if (SUCCEEDED(hr)) + { + DBPROPIDSET propidset; + DBPROPID propid[2]; + + propidset.guidPropertySet = DBPROPSET_ROWSET; + propidset.cPropertyIDs = 2; + propidset.rgPropertyIDs = propid; + propid[0] = DBPROP_UPDATABILITY; + propid[1] = DBPROP_IRowsetUpdate; + hr = IRowsetInfo_GetProperties( rowset_info, 1, &propidset, + &recordset->prop_count, &recordset->prop); + IRowsetInfo_Release( rowset_info ); + } + + if (recordset_get_prop( recordset, &DBPROPSET_ROWSET, DBPROP_UPDATABILITY, &v ) && V_I4( &v )) + { + if (recordset->lock_type != adLockOptimistic) + { + if (recordset_get_prop( recordset, &DBPROPSET_ROWSET, DBPROP_IRowsetUpdate, &v ) && V_BOOL( &v )) + recordset->lock_type = adLockBatchOptimistic; + } + } + else recordset->lock_type = adLockReadOnly; + 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 d7de54efd7e..3754e32b823 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -120,6 +120,7 @@ static void test_Recordset(void) BSTR name; HRESULT hr; VARIANT bookmark, filter, active; + LockTypeEnum lock_type; EditModeEnum editmode; IUnknown *rowset; LONG cache_size; @@ -241,19 +242,34 @@ static void test_Recordset(void) hr = _Recordset_AddNew( recordset, missing, missing ); ok( hr == MAKE_ADO_HRESULT( adErrObjectClosed ), "got %08lx\n", hr );
+ hr = _Recordset_get_LockType( recordset, &lock_type ); + ok( hr == S_OK, "got %08lx\n", hr ); + ok( lock_type == adLockReadOnly, "lock_type = %d\n", lock_type ); + + hr = _Recordset_put_LockType( recordset, adLockUnspecified ); + ok( hr == MAKE_ADO_HRESULT( adErrInvalidArgument ), "got %08lx\n", hr ); + V_VT( &missing ) = VT_ERROR; V_ERROR( &missing ) = DISP_E_PARAMNOTFOUND; hr = _Recordset_Open( recordset, missing, missing, adOpenStatic, adLockBatchOptimistic, adCmdUnspecified ); ok( hr == MAKE_ADO_HRESULT( adErrInvalidConnection ), "got %08lx\n", hr );
+ hr = _Recordset_get_LockType( recordset, &lock_type ); + ok( hr == S_OK, "got %08lx\n", hr ); + ok( lock_type == adLockBatchOptimistic, "lock_type = %d\n", lock_type ); + hr = _Recordset_get_Fields( recordset, &fields ); ok( hr == S_OK, "got %08lx\n", hr );
V_VT( &missing ) = VT_ERROR; V_ERROR( &missing ) = DISP_E_PARAMNOTFOUND; - hr = _Recordset_Open( recordset, missing, missing, adOpenStatic, adLockBatchOptimistic, adCmdUnspecified ); + hr = _Recordset_Open( recordset, missing, missing, adOpenStatic, adLockPessimistic, adCmdUnspecified ); ok( hr == MAKE_ADO_HRESULT( adErrInvalidConnection ), "got %08lx\n", hr );
+ hr = _Recordset_get_LockType( recordset, &lock_type ); + ok( hr == S_OK, "got %08lx\n", hr ); + ok( lock_type == adLockPessimistic, "lock_type = %d\n", lock_type ); + name = SysAllocString( L"field" ); hr = Fields__Append( fields, name, adInteger, 4, adFldUnspecified ); ok( hr == S_OK, "got %08lx\n", hr ); @@ -328,6 +344,10 @@ static void test_Recordset(void) ok( is_eof( recordset ), "not eof\n" ); ok( is_bof( recordset ), "not bof\n" );
+ hr = _Recordset_get_LockType( recordset, &lock_type ); + ok( hr == S_OK, "got %08lx\n", hr ); + ok( lock_type == adLockBatchOptimistic, "lock_type = %d\n", lock_type ); + hr = ADORecordsetConstruction_get_Rowset(recordset_constr, &rowset); ok(hr == S_OK, "failed %08lx\n", hr); ok(!!rowset, "rowset = NULL\n"); @@ -510,6 +530,10 @@ static void test_Recordset(void) hr = _Recordset_Close( recordset ); ok( hr == S_OK, "got %08lx\n", hr );
+ hr = _Recordset_get_LockType( recordset, &lock_type ); + ok( hr == S_OK, "got %08lx\n", hr ); + ok( lock_type == adLockBatchOptimistic, "lock_type = %d\n", lock_type ); + count = -1; hr = Fields_get_Count( fields, &count ); ok( !count, "got %ld\n", count ); @@ -1583,6 +1607,7 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) LONG count, state; unsigned char prec, scale; VARIANT index, missing, v; + LockTypeEnum lock_type; ADO_LONGPTR size; DataTypeEnum type;
@@ -1616,6 +1641,10 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll)
rowset = (IUnknown*)&testrowset.IRowsetExactScroll_iface;
+ hr = _Recordset_get_LockType( recordset, &lock_type ); + ok( hr == S_OK, "got %08lx\n", hr ); + ok( lock_type == adLockReadOnly, "lock_type = %d\n", lock_type ); + SET_EXPECT( rowset_info_GetProperties ); SET_EXPECT( rowset_QI_IRowsetFind ); if (exact_scroll) @@ -1625,7 +1654,7 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) } SET_EXPECT( rowset_QI_IDBAsynchStatus ); hr = ADORecordsetConstruction_put_Rowset( construct, rowset ); - todo_wine CHECK_CALLED( rowset_info_GetProperties ); + CHECK_CALLED( rowset_info_GetProperties ); todo_wine CHECK_CALLED( rowset_QI_IRowsetFind ); if (exact_scroll) { @@ -1639,6 +1668,10 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) ok( hr == S_OK, "got %08lx\n", hr ); ok( state == adStateOpen, "state = %ld\n", state );
+ hr = _Recordset_get_LockType( recordset, &lock_type ); + ok( hr == S_OK, "got %08lx\n", hr ); + ok( lock_type == adLockBatchOptimistic, "lock_type = %d\n", lock_type ); + count = -1; SET_EXPECT( column_info_GetColumnInfo ); hr = Fields_get_Count( fields, &count );