msado15: Move to newly created row in Recordset::AddNew.
[wine.git] / dlls / msado15 / recordset.c
blobd0ee85e0f59955946b1727a87ff5385d7acc913e
1 /*
2 * Copyright 2019 Hans Leidekker for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdarg.h>
20 #include <assert.h>
21 #include "windef.h"
22 #include "winbase.h"
23 #define COBJMACROS
24 #include "objbase.h"
25 #include "msado15_backcompat.h"
26 #include "oledb.h"
27 #include "sqlucode.h"
29 #include "wine/debug.h"
31 #include "msado15_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(msado15);
35 struct fields;
36 struct recordset
38 _Recordset Recordset_iface;
39 ADORecordsetConstruction ADORecordsetConstruction_iface;
40 ISupportErrorInfo ISupportErrorInfo_iface;
41 LONG refs;
42 VARIANT active_connection;
43 LONG state;
44 struct fields *fields;
45 LONG count;
46 LONG allocated;
47 LONG index;
48 VARIANT *data;
49 CursorLocationEnum cursor_location;
50 CursorTypeEnum cursor_type;
51 IRowset *row_set;
52 EditModeEnum editmode;
53 VARIANT filter;
55 DBTYPE *columntypes;
56 HACCESSOR *haccessors;
59 struct fields
61 Fields Fields_iface;
62 ISupportErrorInfo ISupportErrorInfo_iface;
63 LONG refs;
64 Field **field;
65 ULONG count;
66 ULONG allocated;
67 struct recordset *recordset;
70 struct field
72 Field Field_iface;
73 ISupportErrorInfo ISupportErrorInfo_iface;
74 Properties Properties_iface;
75 LONG refs;
76 WCHAR *name;
77 DataTypeEnum type;
78 LONG defined_size;
79 LONG attrs;
80 LONG index;
81 struct recordset *recordset;
83 /* Field Properties */
84 VARIANT optimize;
87 static inline struct field *impl_from_Field( Field *iface )
89 return CONTAINING_RECORD( iface, struct field, Field_iface );
92 static inline struct field *impl_from_Properties( Properties *iface )
94 return CONTAINING_RECORD( iface, struct field, Properties_iface );
97 static ULONG WINAPI field_AddRef( Field *iface )
99 struct field *field = impl_from_Field( iface );
100 LONG refs = InterlockedIncrement( &field->refs );
101 TRACE( "%p new refcount %ld\n", field, refs );
102 return refs;
105 static ULONG WINAPI field_Release( Field *iface )
107 struct field *field = impl_from_Field( iface );
108 LONG refs = InterlockedDecrement( &field->refs );
109 TRACE( "%p new refcount %ld\n", field, refs );
110 if (!refs)
112 TRACE( "destroying %p\n", field );
113 free( field->name );
114 free( field );
116 return refs;
119 static HRESULT WINAPI field_QueryInterface( Field *iface, REFIID riid, void **obj )
121 struct field *field = impl_from_Field( iface );
122 TRACE( "%p, %s, %p\n", iface, debugstr_guid(riid), obj );
124 if (IsEqualGUID( riid, &IID_Field ) || IsEqualGUID( riid, &IID_IDispatch ) ||
125 IsEqualGUID( riid, &IID_IUnknown ))
127 *obj = iface;
129 else if (IsEqualGUID( riid, &IID_ISupportErrorInfo ))
131 *obj = &field->ISupportErrorInfo_iface;
133 else
135 FIXME( "interface %s not implemented\n", debugstr_guid(riid) );
136 return E_NOINTERFACE;
138 field_AddRef( iface );
139 return S_OK;
142 static HRESULT WINAPI field_GetTypeInfoCount( Field *iface, UINT *count )
144 struct field *field = impl_from_Field( iface );
145 TRACE( "%p, %p\n", field, count );
146 *count = 1;
147 return S_OK;
150 static HRESULT WINAPI field_GetTypeInfo( Field *iface, UINT index, LCID lcid, ITypeInfo **info )
152 struct field *field = impl_from_Field( iface );
153 TRACE( "%p, %u, %lu, %p\n", field, index, lcid, info );
154 return get_typeinfo(Field_tid, info);
157 static HRESULT WINAPI field_GetIDsOfNames( Field *iface, REFIID riid, LPOLESTR *names, UINT count,
158 LCID lcid, DISPID *dispid )
160 struct field *field = impl_from_Field( iface );
161 HRESULT hr;
162 ITypeInfo *typeinfo;
164 TRACE( "%p, %s, %p, %u, %lu, %p\n", field, debugstr_guid(riid), names, count, lcid, dispid );
166 hr = get_typeinfo(Field_tid, &typeinfo);
167 if(SUCCEEDED(hr))
169 hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, dispid);
170 ITypeInfo_Release(typeinfo);
173 return hr;
176 static HRESULT WINAPI field_Invoke( Field *iface, DISPID member, REFIID riid, LCID lcid, WORD flags,
177 DISPPARAMS *params, VARIANT *result, EXCEPINFO *excep_info, UINT *arg_err )
179 struct field *field = impl_from_Field( iface );
180 HRESULT hr;
181 ITypeInfo *typeinfo;
183 TRACE( "%p, %ld, %s, %ld, %d, %p, %p, %p, %p\n", field, member, debugstr_guid(riid), lcid, flags, params,
184 result, excep_info, arg_err );
186 hr = get_typeinfo(Field_tid, &typeinfo);
187 if(SUCCEEDED(hr))
189 hr = ITypeInfo_Invoke(typeinfo, &field->Field_iface, member, flags, params,
190 result, excep_info, arg_err);
191 ITypeInfo_Release(typeinfo);
194 return hr;
197 static HRESULT WINAPI field_get_Properties( Field *iface, Properties **obj )
199 struct field *field = impl_from_Field( iface );
200 TRACE( "%p, %p\n", iface, obj );
202 *obj = &field->Properties_iface;
203 Properties_AddRef(&field->Properties_iface);
204 return S_OK;
207 static HRESULT WINAPI field_get_ActualSize( Field *iface, ADO_LONGPTR *size )
209 struct field *field = impl_from_Field( iface );
210 FIXME( "%p, %p\n", field, size );
211 *size = 0;
212 return S_OK;
215 static HRESULT WINAPI field_get_Attributes( Field *iface, LONG *attrs )
217 struct field *field = impl_from_Field( iface );
219 TRACE( "%p, %p\n", field, attrs );
221 *attrs = field->attrs;
222 return S_OK;
225 static HRESULT WINAPI field_get_DefinedSize( Field *iface, ADO_LONGPTR *size )
227 struct field *field = impl_from_Field( iface );
229 TRACE( "%p, %p\n", field, size );
231 *size = field->defined_size;
232 return S_OK;
235 static HRESULT WINAPI field_get_Name( Field *iface, BSTR *str )
237 struct field *field = impl_from_Field( iface );
238 BSTR name;
240 TRACE( "%p, %p\n", field, str );
242 if (!(name = SysAllocString( field->name ))) return E_OUTOFMEMORY;
243 *str = name;
244 return S_OK;
247 static HRESULT WINAPI field_get_Type( Field *iface, DataTypeEnum *type )
249 struct field *field = impl_from_Field( iface );
251 TRACE( "%p, %p\n", field, type );
253 *type = field->type;
254 return S_OK;
257 static LONG get_column_count( struct recordset *recordset )
259 return recordset->fields->count;
262 static HRESULT WINAPI field_get_Value( Field *iface, VARIANT *val )
264 struct field *field = impl_from_Field( iface );
265 ULONG row = field->recordset->index, col = field->index, col_count;
266 VARIANT copy;
267 HRESULT hr;
269 TRACE( "%p, %p\n", field, val );
271 if (field->recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed );
272 if (field->recordset->index < 0) return MAKE_ADO_HRESULT( adErrNoCurrentRecord );
274 col_count = get_column_count( field->recordset );
276 VariantInit( &copy );
277 if ((hr = VariantCopy( &copy, &field->recordset->data[row * col_count + col] )) != S_OK) return hr;
279 *val = copy;
280 return S_OK;
283 static HRESULT WINAPI field_put_Value( Field *iface, VARIANT val )
285 struct field *field = impl_from_Field( iface );
286 ULONG row = field->recordset->index, col = field->index, col_count;
287 VARIANT copy;
288 HRESULT hr;
290 TRACE( "%p, %s\n", field, debugstr_variant(&val) );
292 if (field->recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed );
293 if (field->recordset->index < 0) return MAKE_ADO_HRESULT( adErrNoCurrentRecord );
295 col_count = get_column_count( field->recordset );
297 VariantInit( &copy );
298 if ((hr = VariantCopy( &copy, &val )) != S_OK) return hr;
300 field->recordset->data[row * col_count + col] = copy;
301 return S_OK;
304 static HRESULT WINAPI field_get_Precision( Field *iface, unsigned char *precision )
306 FIXME( "%p, %p\n", iface, precision );
307 return E_NOTIMPL;
310 static HRESULT WINAPI field_get_NumericScale( Field *iface, unsigned char *scale )
312 FIXME( "%p, %p\n", iface, scale );
313 return E_NOTIMPL;
316 static HRESULT WINAPI field_AppendChunk( Field *iface, VARIANT data )
318 FIXME( "%p, %s\n", iface, debugstr_variant(&data) );
319 return E_NOTIMPL;
322 static HRESULT WINAPI field_GetChunk( Field *iface, LONG length, VARIANT *var )
324 FIXME( "%p, %ld, %p\n", iface, length, var );
325 return E_NOTIMPL;
328 static HRESULT WINAPI field_get_OriginalValue( Field *iface, VARIANT *val )
330 FIXME( "%p, %p\n", iface, val );
331 return E_NOTIMPL;
334 static HRESULT WINAPI field_get_UnderlyingValue( Field *iface, VARIANT *val )
336 FIXME( "%p, %p\n", iface, val );
337 return E_NOTIMPL;
340 static HRESULT WINAPI field_get_DataFormat( Field *iface, IUnknown **format )
342 FIXME( "%p, %p\n", iface, format );
343 return E_NOTIMPL;
346 static HRESULT WINAPI field_putref_DataFormat( Field *iface, IUnknown *format )
348 FIXME( "%p, %p\n", iface, format );
349 return E_NOTIMPL;
352 static HRESULT WINAPI field_put_Precision( Field *iface, unsigned char precision )
354 FIXME( "%p, %c\n", iface, precision );
355 return E_NOTIMPL;
358 static HRESULT WINAPI field_put_NumericScale( Field *iface, unsigned char scale )
360 FIXME( "%p, %c\n", iface, scale );
361 return E_NOTIMPL;
364 static HRESULT WINAPI field_put_Type( Field *iface, DataTypeEnum type )
366 struct field *field = impl_from_Field( iface );
368 TRACE( "%p, %u\n", field, type );
370 field->type = type;
371 return S_OK;
374 static HRESULT WINAPI field_put_DefinedSize( Field *iface, ADO_LONGPTR size )
376 struct field *field = impl_from_Field( iface );
378 TRACE( "%p, %Id\n", field, size );
380 field->defined_size = size;
381 return S_OK;
384 static HRESULT WINAPI field_put_Attributes( Field *iface, LONG attrs )
386 struct field *field = impl_from_Field( iface );
388 TRACE( "%p, %ld\n", field, attrs );
390 field->attrs = attrs;
391 return S_OK;
394 static HRESULT WINAPI field_get_Status( Field *iface, LONG *status )
396 FIXME( "%p, %p\n", iface, status );
397 return E_NOTIMPL;
400 static const struct FieldVtbl field_vtbl =
402 field_QueryInterface,
403 field_AddRef,
404 field_Release,
405 field_GetTypeInfoCount,
406 field_GetTypeInfo,
407 field_GetIDsOfNames,
408 field_Invoke,
409 field_get_Properties,
410 field_get_ActualSize,
411 field_get_Attributes,
412 field_get_DefinedSize,
413 field_get_Name,
414 field_get_Type,
415 field_get_Value,
416 field_put_Value,
417 field_get_Precision,
418 field_get_NumericScale,
419 field_AppendChunk,
420 field_GetChunk,
421 field_get_OriginalValue,
422 field_get_UnderlyingValue,
423 field_get_DataFormat,
424 field_putref_DataFormat,
425 field_put_Precision,
426 field_put_NumericScale,
427 field_put_Type,
428 field_put_DefinedSize,
429 field_put_Attributes,
430 field_get_Status
433 static inline struct field *field_from_ISupportErrorInfo( ISupportErrorInfo *iface )
435 return CONTAINING_RECORD( iface, struct field, ISupportErrorInfo_iface );
438 static HRESULT WINAPI field_supporterrorinfo_QueryInterface( ISupportErrorInfo *iface, REFIID riid, void **obj )
440 struct field *field = field_from_ISupportErrorInfo( iface );
441 return Field_QueryInterface( &field->Field_iface, riid, obj );
444 static ULONG WINAPI field_supporterrorinfo_AddRef( ISupportErrorInfo *iface )
446 struct field *field = field_from_ISupportErrorInfo( iface );
447 return Field_AddRef( &field->Field_iface );
450 static ULONG WINAPI field_supporterrorinfo_Release( ISupportErrorInfo *iface )
452 struct field *field = field_from_ISupportErrorInfo( iface );
453 return Field_Release( &field->Field_iface );
456 static HRESULT WINAPI field_supporterrorinfo_InterfaceSupportsErrorInfo( ISupportErrorInfo *iface, REFIID riid )
458 struct field *field = field_from_ISupportErrorInfo( iface );
459 FIXME( "%p, %s\n", field, debugstr_guid(riid) );
460 return S_FALSE;
463 static const ISupportErrorInfoVtbl field_supporterrorinfo_vtbl =
465 field_supporterrorinfo_QueryInterface,
466 field_supporterrorinfo_AddRef,
467 field_supporterrorinfo_Release,
468 field_supporterrorinfo_InterfaceSupportsErrorInfo
471 static HRESULT WINAPI field_props_QueryInterface(Properties *iface, REFIID riid, void **ppv)
473 struct field *field = impl_from_Properties( iface );
475 if (IsEqualGUID( riid, &IID_Properties) || IsEqualGUID( riid, &IID_IDispatch ) ||
476 IsEqualGUID( riid, &IID_IUnknown ))
478 *ppv = &field->Properties_iface;
480 else
482 FIXME( "interface %s not implemented\n", debugstr_guid(riid) );
483 return E_NOINTERFACE;
485 Field_AddRef(&field->Field_iface);
486 return S_OK;
489 static ULONG WINAPI field_props_AddRef(Properties *iface)
491 struct field *field = impl_from_Properties( iface );
492 return Field_AddRef(&field->Field_iface);
495 static ULONG WINAPI field_props_Release(Properties *iface)
497 struct field *field = impl_from_Properties( iface );
498 return Field_Release(&field->Field_iface);
501 static HRESULT WINAPI field_props_GetTypeInfoCount(Properties *iface, UINT *count)
503 struct field *field = impl_from_Properties( iface );
504 TRACE( "%p, %p\n", field, count );
505 *count = 1;
506 return S_OK;
509 static HRESULT WINAPI field_props_GetTypeInfo(Properties *iface, UINT index, LCID lcid, ITypeInfo **info)
511 struct field *field = impl_from_Properties( iface );
512 TRACE( "%p, %u, %lu, %p\n", field, index, lcid, info );
513 return get_typeinfo(Properties_tid, info);
516 static HRESULT WINAPI field_props_GetIDsOfNames(Properties *iface, REFIID riid, LPOLESTR *names, UINT count,
517 LCID lcid, DISPID *dispid )
519 struct field *field = impl_from_Properties( iface );
520 HRESULT hr;
521 ITypeInfo *typeinfo;
523 TRACE( "%p, %s, %p, %u, %lu, %p\n", field, debugstr_guid(riid), names, count, lcid, dispid );
525 hr = get_typeinfo(Properties_tid, &typeinfo);
526 if(SUCCEEDED(hr))
528 hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, dispid);
529 ITypeInfo_Release(typeinfo);
532 return hr;
535 static HRESULT WINAPI field_props_Invoke(Properties *iface, DISPID member, REFIID riid, LCID lcid, WORD flags,
536 DISPPARAMS *params, VARIANT *result, EXCEPINFO *excep_info, UINT *arg_err )
538 struct field *field = impl_from_Properties( iface );
539 HRESULT hr;
540 ITypeInfo *typeinfo;
542 TRACE( "%p, %ld, %s, %ld, %d, %p, %p, %p, %p\n", field, member, debugstr_guid(riid), lcid, flags, params,
543 result, excep_info, arg_err );
545 hr = get_typeinfo(Properties_tid, &typeinfo);
546 if(SUCCEEDED(hr))
548 hr = ITypeInfo_Invoke(typeinfo, &field->Field_iface, member, flags, params,
549 result, excep_info, arg_err);
550 ITypeInfo_Release(typeinfo);
553 return hr;
556 static HRESULT WINAPI field_props_get_Count(Properties *iface, LONG *count)
558 struct field *field = impl_from_Properties( iface );
559 FIXME( "%p, %p\n", field, count);
560 *count = 0;
561 return S_OK;
564 static HRESULT WINAPI field_props__NewEnum(Properties *iface, IUnknown **object)
566 struct field *field = impl_from_Properties( iface );
567 FIXME( "%p, %p\n", field, object);
568 return E_NOTIMPL;
571 static HRESULT WINAPI field_props_Refresh(Properties *iface)
573 struct field *field = impl_from_Properties( iface );
574 FIXME( "%p\n", field);
575 return E_NOTIMPL;
579 struct field_property
581 Property Property_iface;
582 LONG refs;
583 VARIANT *value;
586 static inline struct field_property *impl_from_Property( Property *iface )
588 return CONTAINING_RECORD( iface, struct field_property, Property_iface );
591 static ULONG WINAPI field_property_AddRef(Property *iface)
593 struct field_property *property = impl_from_Property( iface );
594 LONG refs = InterlockedIncrement( &property->refs );
595 TRACE( "%p new refcount %ld\n", property, refs );
596 return refs;
599 static ULONG WINAPI field_property_Release(Property *iface)
601 struct field_property *property = impl_from_Property( iface );
602 LONG refs = InterlockedDecrement( &property->refs );
603 TRACE( "%p new refcount %ld\n", property, refs );
604 if (!refs)
606 free( property );
608 return refs;
611 static HRESULT WINAPI field_property_QueryInterface(Property *iface, REFIID riid, void **obj)
613 struct field_property *property = impl_from_Property( iface );
614 TRACE( "%p, %s, %p\n", property, debugstr_guid(riid), obj );
616 if (IsEqualGUID( riid, &IID_Property )
617 || IsEqualGUID( riid, &IID_IDispatch )
618 || IsEqualGUID( riid, &IID_IUnknown ))
620 *obj = iface;
622 else
624 FIXME( "interface %s not implemented\n", debugstr_guid(riid) );
625 return E_NOINTERFACE;
627 field_property_AddRef( iface );
628 return S_OK;
631 static HRESULT WINAPI field_property_GetTypeInfoCount(Property *iface, UINT *count)
633 struct field_property *property = impl_from_Property( iface );
634 TRACE( "%p, %p\n", property, count );
635 *count = 1;
636 return S_OK;
639 static HRESULT WINAPI field_property_GetTypeInfo(Property *iface, UINT index, LCID lcid, ITypeInfo **info)
641 struct field_property *property = impl_from_Property( iface );
642 TRACE( "%p, %u, %lu, %p\n", property, index, lcid, info );
643 return get_typeinfo(Property_tid, info);
646 static HRESULT WINAPI field_property_GetIDsOfNames(Property *iface, REFIID riid, LPOLESTR *names, UINT count,
647 LCID lcid, DISPID *dispid)
649 struct field_property *property = impl_from_Property( iface );
650 HRESULT hr;
651 ITypeInfo *typeinfo;
653 TRACE( "%p, %s, %p, %u, %lu, %p\n", property, debugstr_guid(riid), names, count, lcid, dispid );
655 hr = get_typeinfo(Property_tid, &typeinfo);
656 if(SUCCEEDED(hr))
658 hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, dispid);
659 ITypeInfo_Release(typeinfo);
662 return hr;
665 static HRESULT WINAPI field_property_Invoke(Property *iface, DISPID member, REFIID riid, LCID lcid,
666 WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *excep_info, UINT *arg_err)
668 struct field_property *property = impl_from_Property( iface );
669 HRESULT hr;
670 ITypeInfo *typeinfo;
672 TRACE( "%p, %ld, %s, %ld, %d, %p, %p, %p, %p\n", property, member, debugstr_guid(riid), lcid, flags, params,
673 result, excep_info, arg_err );
675 hr = get_typeinfo(Property_tid, &typeinfo);
676 if(SUCCEEDED(hr))
678 hr = ITypeInfo_Invoke(typeinfo, &property->Property_iface, member, flags, params,
679 result, excep_info, arg_err);
680 ITypeInfo_Release(typeinfo);
683 return hr;
686 static HRESULT WINAPI field_property_get_Value(Property *iface, VARIANT *val)
688 struct field_property *property = impl_from_Property( iface );
689 TRACE("%p, %p\n", property, val);
690 VariantCopy(val, property->value);
691 return S_OK;
694 static HRESULT WINAPI field_property_put_Value(Property *iface, VARIANT val)
696 struct field_property *property = impl_from_Property( iface );
697 TRACE("%p, %s\n", property, debugstr_variant(&val));
698 VariantCopy(property->value, &val);
699 return S_OK;
702 static HRESULT WINAPI field_property_get_Name(Property *iface, BSTR *str)
704 FIXME("\n");
705 return E_NOTIMPL;
708 static HRESULT WINAPI field_property_get_Type(Property *iface, DataTypeEnum *type)
710 FIXME("\n");
711 return E_NOTIMPL;
714 static HRESULT WINAPI field_property_get_Attributes(Property *iface, LONG *attributes)
716 FIXME("\n");
717 return E_NOTIMPL;
720 static HRESULT WINAPI field_property_put_Attributes(Property *iface, LONG attributes)
722 FIXME("\n");
723 return E_NOTIMPL;
726 static struct PropertyVtbl field_property_vtbl =
728 field_property_QueryInterface,
729 field_property_AddRef,
730 field_property_Release,
731 field_property_GetTypeInfoCount,
732 field_property_GetTypeInfo,
733 field_property_GetIDsOfNames,
734 field_property_Invoke,
735 field_property_get_Value,
736 field_property_put_Value,
737 field_property_get_Name,
738 field_property_get_Type,
739 field_property_get_Attributes,
740 field_property_put_Attributes
743 static HRESULT WINAPI field_props_get_Item(Properties *iface, VARIANT index, Property **object)
745 struct field *field = impl_from_Properties( iface );
746 struct field_property *prop;
748 TRACE( "%p, %s, %p\n", field, debugstr_variant(&index), object);
750 if (V_VT(&index) == VT_BSTR)
752 if(!wcscmp(L"Optimize", V_BSTR(&index)))
754 prop = malloc (sizeof(struct field_property));
755 prop->Property_iface.lpVtbl = &field_property_vtbl;
756 prop->value = &field->optimize;
758 *object = &prop->Property_iface;
759 return S_OK;
763 FIXME("Unsupported property %s\n", debugstr_variant(&index));
765 return MAKE_ADO_HRESULT(adErrItemNotFound);
768 static struct PropertiesVtbl field_properties_vtbl =
770 field_props_QueryInterface,
771 field_props_AddRef,
772 field_props_Release,
773 field_props_GetTypeInfoCount,
774 field_props_GetTypeInfo,
775 field_props_GetIDsOfNames,
776 field_props_Invoke,
777 field_props_get_Count,
778 field_props__NewEnum,
779 field_props_Refresh,
780 field_props_get_Item
783 static HRESULT Field_create( const WCHAR *name, LONG index, struct recordset *recordset, Field **obj )
785 struct field *field;
787 if (!(field = calloc( 1, sizeof(*field) ))) return E_OUTOFMEMORY;
788 field->Field_iface.lpVtbl = &field_vtbl;
789 field->ISupportErrorInfo_iface.lpVtbl = &field_supporterrorinfo_vtbl;
790 field->Properties_iface.lpVtbl = &field_properties_vtbl;
791 field->refs = 1;
792 if (!(field->name = wcsdup( name )))
794 free( field );
795 return E_OUTOFMEMORY;
797 field->index = index;
798 field->recordset = recordset;
800 *obj = &field->Field_iface;
801 TRACE( "returning iface %p\n", *obj );
802 return S_OK;
805 static inline struct fields *impl_from_Fields( Fields *iface )
807 return CONTAINING_RECORD( iface, struct fields, Fields_iface );
810 static ULONG WINAPI fields_AddRef( Fields *iface )
812 struct fields *fields = impl_from_Fields( iface );
813 LONG refs = InterlockedIncrement( &fields->refs );
814 TRACE( "%p new refcount %ld\n", fields, refs );
815 return refs;
818 static ULONG WINAPI fields_Release( Fields *iface )
820 struct fields *fields = impl_from_Fields( iface );
821 LONG refs = InterlockedDecrement( &fields->refs );
822 TRACE( "%p new refcount %ld\n", fields, refs );
823 if (!refs)
825 if (fields->recordset) _Recordset_Release( &fields->recordset->Recordset_iface );
826 fields->recordset = NULL;
827 WARN( "not destroying %p\n", fields );
828 return InterlockedIncrement( &fields->refs );
830 return refs;
833 static HRESULT WINAPI fields_QueryInterface( Fields *iface, REFIID riid, void **obj )
835 struct fields *fields = impl_from_Fields( iface );
836 TRACE( "%p, %s, %p\n", iface, debugstr_guid(riid), obj );
838 if (IsEqualGUID( riid, &IID_Fields ) || IsEqualGUID( riid, &IID_IDispatch ) ||
839 IsEqualGUID( riid, &IID_IUnknown ))
841 *obj = iface;
843 else if (IsEqualGUID( riid, &IID_ISupportErrorInfo ))
845 *obj = &fields->ISupportErrorInfo_iface;
847 else
849 FIXME( "interface %s not implemented\n", debugstr_guid(riid) );
850 return E_NOINTERFACE;
852 fields_AddRef( iface );
853 return S_OK;
856 static HRESULT WINAPI fields_GetTypeInfoCount( Fields *iface, UINT *count )
858 struct fields *fields = impl_from_Fields( iface );
859 TRACE( "%p, %p\n", fields, count );
860 *count = 1;
861 return S_OK;
864 static HRESULT WINAPI fields_GetTypeInfo( Fields *iface, UINT index, LCID lcid, ITypeInfo **info )
866 struct fields *fields = impl_from_Fields( iface );
867 TRACE( "%p, %u, %lu, %p\n", fields, index, lcid, info );
868 return get_typeinfo(Fields_tid, info);
871 static HRESULT WINAPI fields_GetIDsOfNames( Fields *iface, REFIID riid, LPOLESTR *names, UINT count,
872 LCID lcid, DISPID *dispid )
874 struct fields *fields = impl_from_Fields( iface );
875 HRESULT hr;
876 ITypeInfo *typeinfo;
878 TRACE( "%p, %s, %p, %u, %lu, %p\n", fields, debugstr_guid(riid), names, count, lcid, dispid );
880 hr = get_typeinfo(Fields_tid, &typeinfo);
881 if(SUCCEEDED(hr))
883 hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, dispid);
884 ITypeInfo_Release(typeinfo);
887 return hr;
890 static HRESULT WINAPI fields_Invoke( Fields *iface, DISPID member, REFIID riid, LCID lcid, WORD flags,
891 DISPPARAMS *params, VARIANT *result, EXCEPINFO *excep_info, UINT *arg_err )
893 struct fields *fields = impl_from_Fields( iface );
894 HRESULT hr;
895 ITypeInfo *typeinfo;
897 TRACE( "%p, %ld, %s, %ld, %d, %p, %p, %p, %p\n", fields, member, debugstr_guid(riid), lcid, flags, params,
898 result, excep_info, arg_err );
900 hr = get_typeinfo(Fields_tid, &typeinfo);
901 if(SUCCEEDED(hr))
903 hr = ITypeInfo_Invoke(typeinfo, &fields->Fields_iface, member, flags, params,
904 result, excep_info, arg_err);
905 ITypeInfo_Release(typeinfo);
908 return hr;
911 static HRESULT WINAPI fields_get_Count( Fields *iface, LONG *count )
913 struct fields *fields = impl_from_Fields( iface );
915 TRACE( "%p, %p\n", fields, count );
917 *count = fields->count;
918 return S_OK;
921 static HRESULT WINAPI fields__NewEnum( Fields *iface, IUnknown **obj )
923 FIXME( "%p, %p\n", iface, obj );
924 return E_NOTIMPL;
927 static HRESULT WINAPI fields_Refresh( Fields *iface )
929 FIXME( "%p\n", iface );
930 return E_NOTIMPL;
933 static HRESULT map_index( struct fields *fields, VARIANT *index, ULONG *ret )
935 ULONG i;
937 if (V_VT( index ) != VT_BSTR)
939 VARIANT idx;
941 VariantInit(&idx);
942 if (VariantChangeType(&idx, index, 0, VT_UI4) == S_OK)
944 i = V_UI4 ( &idx );
945 if (i < fields->count)
947 *ret = i;
948 return S_OK;
952 return MAKE_ADO_HRESULT(adErrItemNotFound);
955 for (i = 0; i < fields->count; i++)
957 BSTR name;
958 BOOL match;
959 HRESULT hr;
961 if ((hr = Field_get_Name( fields->field[i], &name )) != S_OK) return hr;
962 match = !wcsicmp( V_BSTR( index ), name );
963 SysFreeString( name );
964 if (match)
966 *ret = i;
967 return S_OK;
971 return MAKE_ADO_HRESULT(adErrItemNotFound);
974 static inline WCHAR *heap_strdupAtoW(const char *str)
976 LPWSTR ret = NULL;
978 if(str) {
979 DWORD len;
981 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
982 ret = malloc(len*sizeof(WCHAR));
983 if(ret)
984 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
987 return ret;
990 static HRESULT WINAPI fields_get_Item( Fields *iface, VARIANT index, Field **obj )
992 struct fields *fields = impl_from_Fields( iface );
993 HRESULT hr;
994 ULONG i = 0;
996 TRACE( "%p, %s, %p\n", fields, debugstr_variant(&index), obj );
998 if ((hr = map_index( fields, &index, &i )) != S_OK) return hr;
1000 Field_AddRef( fields->field[i] );
1001 *obj = fields->field[i];
1002 return S_OK;
1005 static BOOL resize_fields( struct fields *fields, ULONG count )
1007 if (count > fields->allocated)
1009 Field **tmp;
1010 ULONG new_size = max( count, fields->allocated * 2 );
1011 if (!(tmp = realloc( fields->field, new_size * sizeof(*tmp) ))) return FALSE;
1012 fields->field = tmp;
1013 fields->allocated = new_size;
1016 fields->count = count;
1017 return TRUE;
1020 static HRESULT append_field( struct fields *fields, BSTR name, DataTypeEnum type, LONG size, FieldAttributeEnum attr,
1021 VARIANT *value )
1023 Field *field;
1024 HRESULT hr;
1026 if ((hr = Field_create( name, fields->count, fields->recordset, &field )) != S_OK) return hr;
1027 Field_put_Type( field, type );
1028 Field_put_DefinedSize( field, size );
1029 if (attr != adFldUnspecified) Field_put_Attributes( field, attr );
1030 if (value) FIXME( "ignoring value %s\n", debugstr_variant(value) );
1032 if (!(resize_fields( fields, fields->count + 1 )))
1034 Field_Release( field );
1035 return E_OUTOFMEMORY;
1038 fields->field[fields->count - 1] = field;
1039 return S_OK;
1042 static HRESULT WINAPI fields__Append( Fields *iface, BSTR name, DataTypeEnum type, ADO_LONGPTR size, FieldAttributeEnum attr )
1044 struct fields *fields = impl_from_Fields( iface );
1046 TRACE( "%p, %s, %u, %Id, %d\n", fields, debugstr_w(name), type, size, attr );
1048 return append_field( fields, name, type, size, attr, NULL );
1051 static HRESULT WINAPI fields_Delete( Fields *iface, VARIANT index )
1053 FIXME( "%p, %s\n", iface, debugstr_variant(&index) );
1054 return E_NOTIMPL;
1057 static HRESULT WINAPI fields_Append( Fields *iface, BSTR name, DataTypeEnum type, ADO_LONGPTR size, FieldAttributeEnum attr,
1058 VARIANT value )
1060 struct fields *fields = impl_from_Fields( iface );
1062 TRACE( "%p, %s, %u, %Id, %d, %s\n", fields, debugstr_w(name), type, size, attr, debugstr_variant(&value) );
1064 return append_field( fields, name, type, size, attr, &value );
1067 static HRESULT WINAPI fields_Update( Fields *iface )
1069 FIXME( "%p\n", iface );
1070 return E_NOTIMPL;
1073 static HRESULT WINAPI fields_Resync( Fields *iface, ResyncEnum resync_values )
1075 FIXME( "%p, %u\n", iface, resync_values );
1076 return E_NOTIMPL;
1079 static HRESULT WINAPI fields_CancelUpdate( Fields *iface )
1081 FIXME( "%p\n", iface );
1082 return E_NOTIMPL;
1085 static const struct FieldsVtbl fields_vtbl =
1087 fields_QueryInterface,
1088 fields_AddRef,
1089 fields_Release,
1090 fields_GetTypeInfoCount,
1091 fields_GetTypeInfo,
1092 fields_GetIDsOfNames,
1093 fields_Invoke,
1094 fields_get_Count,
1095 fields__NewEnum,
1096 fields_Refresh,
1097 fields_get_Item,
1098 fields__Append,
1099 fields_Delete,
1100 fields_Append,
1101 fields_Update,
1102 fields_Resync,
1103 fields_CancelUpdate
1106 static inline struct fields *fields_from_ISupportErrorInfo( ISupportErrorInfo *iface )
1108 return CONTAINING_RECORD( iface, struct fields, ISupportErrorInfo_iface );
1111 static HRESULT WINAPI fields_supporterrorinfo_QueryInterface( ISupportErrorInfo *iface, REFIID riid, void **obj )
1113 struct fields *fields = fields_from_ISupportErrorInfo( iface );
1114 return Fields_QueryInterface( &fields->Fields_iface, riid, obj );
1117 static ULONG WINAPI fields_supporterrorinfo_AddRef( ISupportErrorInfo *iface )
1119 struct fields *fields = fields_from_ISupportErrorInfo( iface );
1120 return Fields_AddRef( &fields->Fields_iface );
1123 static ULONG WINAPI fields_supporterrorinfo_Release( ISupportErrorInfo *iface )
1125 struct fields *fields = fields_from_ISupportErrorInfo( iface );
1126 return Fields_Release( &fields->Fields_iface );
1129 static HRESULT WINAPI fields_supporterrorinfo_InterfaceSupportsErrorInfo( ISupportErrorInfo *iface, REFIID riid )
1131 struct fields *fields = fields_from_ISupportErrorInfo( iface );
1132 FIXME( "%p, %s\n", fields, debugstr_guid(riid) );
1133 return S_FALSE;
1136 static const ISupportErrorInfoVtbl fields_supporterrorinfo_vtbl =
1138 fields_supporterrorinfo_QueryInterface,
1139 fields_supporterrorinfo_AddRef,
1140 fields_supporterrorinfo_Release,
1141 fields_supporterrorinfo_InterfaceSupportsErrorInfo
1144 static void map_rowset_fields(struct recordset *recordset, struct fields *fields)
1146 HRESULT hr;
1147 IColumnsInfo *columninfo;
1148 DBORDINAL columns, i;
1149 DBCOLUMNINFO *colinfo;
1150 OLECHAR *stringsbuffer;
1152 /* Not Finding the interface or GetColumnInfo failing just causes 0 Fields to be returned */
1153 hr = IRowset_QueryInterface(recordset->row_set, &IID_IColumnsInfo, (void**)&columninfo);
1154 if (FAILED(hr))
1155 return;
1157 hr = IColumnsInfo_GetColumnInfo(columninfo, &columns, &colinfo, &stringsbuffer);
1158 if (SUCCEEDED(hr))
1160 for (i=0; i < columns; i++)
1162 TRACE("Adding Column %Iu, pwszName: %s, pTypeInfo %p, iOrdinal %Iu, dwFlags 0x%08lx, "
1163 "ulColumnSize %Iu, wType %d, bPrecision %d, bScale %d\n",
1164 i, debugstr_w(colinfo[i].pwszName), colinfo[i].pTypeInfo, colinfo[i].iOrdinal,
1165 colinfo[i].dwFlags, colinfo[i].ulColumnSize, colinfo[i].wType,
1166 colinfo[i].bPrecision, colinfo[i].bScale);
1168 hr = append_field(fields, colinfo[i].pwszName, colinfo[i].wType, colinfo[i].ulColumnSize,
1169 colinfo[i].dwFlags, NULL);
1170 if (FAILED(hr))
1172 ERR("Failed to add Field name - 0x%08lx\n", hr);
1173 return;
1177 CoTaskMemFree(colinfo);
1178 CoTaskMemFree(stringsbuffer);
1181 IColumnsInfo_Release(columninfo);
1184 static HRESULT fields_create( struct recordset *recordset, struct fields **ret )
1186 struct fields *fields;
1188 if (!(fields = calloc( 1, sizeof(*fields) ))) return E_OUTOFMEMORY;
1189 fields->Fields_iface.lpVtbl = &fields_vtbl;
1190 fields->ISupportErrorInfo_iface.lpVtbl = &fields_supporterrorinfo_vtbl;
1191 fields->refs = 1;
1192 fields->recordset = recordset;
1193 _Recordset_AddRef( &fields->recordset->Recordset_iface );
1195 if ( recordset->row_set )
1196 map_rowset_fields(recordset, fields);
1198 *ret = fields;
1199 TRACE( "returning %p\n", *ret );
1200 return S_OK;
1203 static inline struct recordset *impl_from_Recordset( _Recordset *iface )
1205 return CONTAINING_RECORD( iface, struct recordset, Recordset_iface );
1208 static inline struct recordset *impl_from_ADORecordsetConstruction( ADORecordsetConstruction *iface )
1210 return CONTAINING_RECORD( iface, struct recordset, ADORecordsetConstruction_iface );
1213 static ULONG WINAPI recordset_AddRef( _Recordset *iface )
1215 struct recordset *recordset = impl_from_Recordset( iface );
1216 LONG refs = InterlockedIncrement( &recordset->refs );
1217 TRACE( "%p new refcount %ld\n", recordset, refs );
1218 return refs;
1221 static void close_recordset( struct recordset *recordset )
1223 ULONG row, col, col_count;
1224 ULONG i;
1225 IAccessor *accessor;
1227 if (recordset->haccessors)
1228 IRowset_QueryInterface(recordset->row_set, &IID_IAccessor, (void**)&accessor);
1230 if ( recordset->row_set ) IRowset_Release( recordset->row_set );
1231 recordset->row_set = NULL;
1233 VariantClear( &recordset->filter );
1235 if (!recordset->fields) return;
1236 col_count = get_column_count( recordset );
1238 free(recordset->columntypes);
1240 for (i = 0; i < col_count; i++)
1242 struct field *field = impl_from_Field( recordset->fields->field[i] );
1243 field->recordset = NULL;
1244 Field_Release(&field->Field_iface);
1246 if (recordset->haccessors)
1247 IAccessor_ReleaseAccessor(accessor, recordset->haccessors[i], NULL);
1250 if (recordset->haccessors)
1252 IAccessor_Release(accessor);
1253 free(recordset->haccessors);
1254 recordset->haccessors = NULL;
1256 recordset->fields->count = 0;
1257 Fields_Release( &recordset->fields->Fields_iface );
1258 recordset->fields = NULL;
1260 for (row = 0; row < recordset->count; row++)
1261 for (col = 0; col < col_count; col++) VariantClear( &recordset->data[row * col_count + col] );
1263 recordset->count = recordset->allocated = recordset->index = 0;
1264 free( recordset->data );
1265 recordset->data = NULL;
1268 static ULONG WINAPI recordset_Release( _Recordset *iface )
1270 struct recordset *recordset = impl_from_Recordset( iface );
1271 LONG refs = InterlockedDecrement( &recordset->refs );
1272 TRACE( "%p new refcount %ld\n", recordset, refs );
1273 if (!refs)
1275 TRACE( "destroying %p\n", recordset );
1276 close_recordset( recordset );
1277 free( recordset );
1279 return refs;
1282 static HRESULT WINAPI recordset_QueryInterface( _Recordset *iface, REFIID riid, void **obj )
1284 struct recordset *recordset = impl_from_Recordset( iface );
1285 TRACE( "%p, %s, %p\n", iface, debugstr_guid(riid), obj );
1287 *obj = NULL;
1289 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch) ||
1290 IsEqualIID(riid, &IID__ADO) || IsEqualIID(riid, &IID_Recordset15) ||
1291 IsEqualIID(riid, &IID_Recordset20) || IsEqualIID(riid, &IID_Recordset21) ||
1292 IsEqualIID(riid, &IID__Recordset))
1294 *obj = iface;
1296 else if (IsEqualGUID( riid, &IID_ISupportErrorInfo ))
1298 *obj = &recordset->ISupportErrorInfo_iface;
1300 else if (IsEqualGUID( riid, &IID_ADORecordsetConstruction ))
1302 *obj = &recordset->ADORecordsetConstruction_iface;
1304 else if (IsEqualGUID( riid, &IID_IRunnableObject ))
1306 TRACE("IID_IRunnableObject not supported returning NULL\n");
1307 return E_NOINTERFACE;
1309 else
1311 FIXME( "interface %s not implemented\n", debugstr_guid(riid) );
1312 return E_NOINTERFACE;
1314 recordset_AddRef( iface );
1315 return S_OK;
1318 static HRESULT WINAPI recordset_GetTypeInfoCount( _Recordset *iface, UINT *count )
1320 struct recordset *recordset = impl_from_Recordset( iface );
1321 TRACE( "%p, %p\n", recordset, count );
1322 *count = 1;
1323 return S_OK;
1326 static HRESULT WINAPI recordset_GetTypeInfo( _Recordset *iface, UINT index, LCID lcid, ITypeInfo **info )
1328 struct recordset *recordset = impl_from_Recordset( iface );
1329 TRACE( "%p, %u, %lu, %p\n", recordset, index, lcid, info );
1330 return get_typeinfo(Recordset_tid, info);
1333 static HRESULT WINAPI recordset_GetIDsOfNames( _Recordset *iface, REFIID riid, LPOLESTR *names, UINT count,
1334 LCID lcid, DISPID *dispid )
1336 struct recordset *recordset = impl_from_Recordset( iface );
1337 HRESULT hr;
1338 ITypeInfo *typeinfo;
1340 TRACE( "%p, %s, %p, %u, %lu, %p\n", recordset, debugstr_guid(riid), names, count, lcid, dispid );
1342 hr = get_typeinfo(Recordset_tid, &typeinfo);
1343 if(SUCCEEDED(hr))
1345 hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, dispid);
1346 ITypeInfo_Release(typeinfo);
1349 return hr;
1352 static HRESULT WINAPI recordset_Invoke( _Recordset *iface, DISPID member, REFIID riid, LCID lcid, WORD flags,
1353 DISPPARAMS *params, VARIANT *result, EXCEPINFO *excep_info, UINT *arg_err )
1355 struct recordset *recordset = impl_from_Recordset( iface );
1356 HRESULT hr;
1357 ITypeInfo *typeinfo;
1359 TRACE( "%p, %ld, %s, %ld, %d, %p, %p, %p, %p\n", recordset, member, debugstr_guid(riid), lcid, flags, params,
1360 result, excep_info, arg_err );
1362 hr = get_typeinfo(Recordset_tid, &typeinfo);
1363 if(SUCCEEDED(hr))
1365 hr = ITypeInfo_Invoke(typeinfo, &recordset->Recordset_iface, member, flags, params,
1366 result, excep_info, arg_err);
1367 ITypeInfo_Release(typeinfo);
1370 return hr;
1373 static HRESULT WINAPI recordset_get_Properties( _Recordset *iface, Properties **obj )
1375 FIXME( "%p, %p\n", iface, obj );
1376 return E_NOTIMPL;
1379 static HRESULT WINAPI recordset_get_AbsolutePosition( _Recordset *iface, PositionEnum_Param *pos )
1381 FIXME( "%p, %p\n", iface, pos );
1382 return E_NOTIMPL;
1385 static HRESULT WINAPI recordset_put_AbsolutePosition( _Recordset *iface, PositionEnum_Param pos )
1387 FIXME( "%p, %Id\n", iface, pos );
1388 return E_NOTIMPL;
1391 static HRESULT WINAPI recordset_putref_ActiveConnection( _Recordset *iface, IDispatch *connection )
1393 FIXME( "%p, %p\n", iface, connection );
1394 return E_NOTIMPL;
1397 static HRESULT WINAPI recordset_put_ActiveConnection( _Recordset *iface, VARIANT connection )
1399 FIXME( "%p, %s\n", iface, debugstr_variant(&connection) );
1400 return E_NOTIMPL;
1403 static HRESULT WINAPI recordset_get_ActiveConnection( _Recordset *iface, VARIANT *connection )
1405 struct recordset *recordset = impl_from_Recordset( iface );
1406 TRACE( "%p, %p\n", iface, connection );
1407 return VariantCopy(connection, &recordset->active_connection);
1410 static HRESULT WINAPI recordset_get_BOF( _Recordset *iface, VARIANT_BOOL *bof )
1412 struct recordset *recordset = impl_from_Recordset( iface );
1414 TRACE( "%p, %p\n", recordset, bof );
1416 *bof = (recordset->index < 0) ? VARIANT_TRUE : VARIANT_FALSE;
1417 return S_OK;
1420 static HRESULT WINAPI recordset_get_Bookmark( _Recordset *iface, VARIANT *bookmark )
1422 struct recordset *recordset = impl_from_Recordset( iface );
1423 TRACE( "%p, %p\n", iface, bookmark );
1425 if (recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed );
1426 if (recordset->index < 0) return MAKE_ADO_HRESULT( adErrNoCurrentRecord );
1428 V_VT(bookmark) = VT_I4;
1429 V_I4(bookmark) = recordset->index;
1430 return S_OK;
1433 static HRESULT WINAPI recordset_put_Bookmark( _Recordset *iface, VARIANT bookmark )
1435 struct recordset *recordset = impl_from_Recordset( iface );
1436 TRACE( "%p, %s\n", iface, debugstr_variant(&bookmark) );
1438 if (recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed );
1440 if (V_VT(&bookmark) != VT_I4) return MAKE_ADO_HRESULT( adErrInvalidArgument );
1442 recordset->index = V_I4(&bookmark);
1443 return S_OK;
1446 static HRESULT WINAPI recordset_get_CacheSize( _Recordset *iface, LONG *size )
1448 FIXME( "%p, %p\n", iface, size );
1449 return E_NOTIMPL;
1452 static HRESULT WINAPI recordset_put_CacheSize( _Recordset *iface, LONG size )
1454 FIXME( "%p, %ld\n", iface, size );
1455 return E_NOTIMPL;
1458 static HRESULT WINAPI recordset_get_CursorType( _Recordset *iface, CursorTypeEnum *cursor_type )
1460 struct recordset *recordset = impl_from_Recordset( iface );
1462 TRACE( "%p, %p\n", iface, cursor_type );
1464 *cursor_type = recordset->cursor_type;
1465 return S_OK;
1468 static HRESULT WINAPI recordset_put_CursorType( _Recordset *iface, CursorTypeEnum cursor_type )
1470 struct recordset *recordset = impl_from_Recordset( iface );
1472 TRACE( "%p, %d\n", iface, cursor_type );
1474 recordset->cursor_type = cursor_type;
1475 return S_OK;
1478 static HRESULT WINAPI recordset_get_EOF( _Recordset *iface, VARIANT_BOOL *eof )
1480 struct recordset *recordset = impl_from_Recordset( iface );
1482 TRACE( "%p, %p\n", recordset, eof );
1484 *eof = (!recordset->count || recordset->index >= recordset->count) ? VARIANT_TRUE : VARIANT_FALSE;
1485 return S_OK;
1488 static HRESULT WINAPI recordset_get_Fields( _Recordset *iface, Fields **obj )
1490 struct recordset *recordset = impl_from_Recordset( iface );
1491 HRESULT hr;
1493 TRACE( "%p, %p\n", recordset, obj );
1495 if (recordset->fields)
1497 /* yes, this adds a reference to the recordset instead of the fields object */
1498 _Recordset_AddRef( &recordset->Recordset_iface );
1499 recordset->fields->recordset = recordset;
1500 *obj = &recordset->fields->Fields_iface;
1501 return S_OK;
1504 if ((hr = fields_create( recordset, &recordset->fields )) != S_OK) return hr;
1506 *obj = &recordset->fields->Fields_iface;
1507 return S_OK;
1510 static HRESULT WINAPI recordset_get_LockType( _Recordset *iface, LockTypeEnum *lock_type )
1512 FIXME( "%p, %p\n", iface, lock_type );
1513 return E_NOTIMPL;
1516 static HRESULT WINAPI recordset_put_LockType( _Recordset *iface, LockTypeEnum lock_type )
1518 FIXME( "%p, %d\n", iface, lock_type );
1519 return E_NOTIMPL;
1522 static HRESULT WINAPI recordset_get_MaxRecords( _Recordset *iface, ADO_LONGPTR *max_records )
1524 FIXME( "%p, %p\n", iface, max_records );
1525 return E_NOTIMPL;
1528 static HRESULT WINAPI recordset_put_MaxRecords( _Recordset *iface, ADO_LONGPTR max_records )
1530 FIXME( "%p, %Id\n", iface, max_records );
1531 return E_NOTIMPL;
1534 static HRESULT WINAPI recordset_get_RecordCount( _Recordset *iface, ADO_LONGPTR *count )
1536 struct recordset *recordset = impl_from_Recordset( iface );
1538 TRACE( "%p, %p\n", recordset, count );
1540 *count = recordset->count;
1541 return S_OK;
1544 static HRESULT WINAPI recordset_putref_Source( _Recordset *iface, IDispatch *source )
1546 FIXME( "%p, %p\n", iface, source );
1547 return E_NOTIMPL;
1550 static HRESULT WINAPI recordset_put_Source( _Recordset *iface, BSTR source )
1552 FIXME( "%p, %s\n", iface, debugstr_w(source) );
1553 return E_NOTIMPL;
1556 static HRESULT WINAPI recordset_get_Source( _Recordset *iface, VARIANT *source )
1558 FIXME( "%p, %p\n", iface, source );
1559 return E_NOTIMPL;
1562 static BOOL resize_recordset( struct recordset *recordset, ULONG row_count )
1564 ULONG row_size = get_column_count( recordset ) * sizeof(*recordset->data);
1566 if (row_count > recordset->allocated)
1568 VARIANT *tmp;
1569 ULONG count = max( row_count, recordset->allocated * 2 );
1570 if (!(tmp = realloc( recordset->data, count * row_size ))) return FALSE;
1571 memset( tmp + recordset->allocated, 0, (count - recordset->allocated) * row_size );
1572 recordset->data = tmp;
1573 recordset->allocated = count;
1576 recordset->count = row_count;
1577 return TRUE;
1580 static HRESULT WINAPI recordset_AddNew( _Recordset *iface, VARIANT field_list, VARIANT values )
1582 struct recordset *recordset = impl_from_Recordset( iface );
1584 TRACE( "%p, %s, %s\n", recordset, debugstr_variant(&field_list), debugstr_variant(&values) );
1585 FIXME( "ignoring field list and values\n" );
1587 if (recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed );
1589 if (!resize_recordset( recordset, recordset->count + 1 )) return E_OUTOFMEMORY;
1590 recordset->index = recordset->count - 1;
1591 recordset->editmode = adEditAdd;
1592 return S_OK;
1595 static HRESULT WINAPI recordset_CancelUpdate( _Recordset *iface )
1597 struct recordset *recordset = impl_from_Recordset( iface );
1599 FIXME( "%p\n", iface );
1601 if (V_DISPATCH(&recordset->active_connection) == NULL)
1602 return S_OK;
1604 recordset->editmode = adEditNone;
1605 return E_NOTIMPL;
1608 static HRESULT WINAPI recordset_Close( _Recordset *iface )
1610 struct recordset *recordset = impl_from_Recordset( iface );
1612 TRACE( "%p\n", recordset );
1614 if (recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed );
1616 close_recordset( recordset );
1617 recordset->state = adStateClosed;
1618 return S_OK;
1621 static HRESULT WINAPI recordset_Delete( _Recordset *iface, AffectEnum affect_records )
1623 FIXME( "%p, %u\n", iface, affect_records );
1624 return E_NOTIMPL;
1627 static HRESULT WINAPI recordset_GetRows( _Recordset *iface, LONG rows, VARIANT start, VARIANT fields, VARIANT *var )
1629 FIXME( "%p, %ld, %s, %s, %p\n", iface, rows, debugstr_variant(&start), debugstr_variant(&fields), var );
1630 return E_NOTIMPL;
1633 static HRESULT WINAPI recordset_Move( _Recordset *iface, ADO_LONGPTR num_records, VARIANT start )
1635 FIXME( "%p, %Id, %s\n", iface, num_records, debugstr_variant(&start) );
1636 return E_NOTIMPL;
1639 static HRESULT WINAPI recordset_MoveNext( _Recordset *iface )
1641 struct recordset *recordset = impl_from_Recordset( iface );
1643 TRACE( "%p\n", recordset );
1645 if (recordset->index < recordset->count) recordset->index++;
1646 return S_OK;
1649 static HRESULT WINAPI recordset_MovePrevious( _Recordset *iface )
1651 struct recordset *recordset = impl_from_Recordset( iface );
1653 TRACE( "%p\n", recordset );
1655 if (recordset->index >= 0) recordset->index--;
1656 return S_OK;
1659 static HRESULT WINAPI recordset_MoveFirst( _Recordset *iface )
1661 struct recordset *recordset = impl_from_Recordset( iface );
1663 TRACE( "%p\n", recordset );
1665 recordset->index = 0;
1666 return S_OK;
1669 static HRESULT WINAPI recordset_MoveLast( _Recordset *iface )
1671 struct recordset *recordset = impl_from_Recordset( iface );
1673 TRACE( "%p\n", recordset );
1675 recordset->index = (recordset->count > 0) ? recordset->count - 1 : 0;
1676 return S_OK;
1679 static HRESULT create_command_text(IUnknown *session, BSTR command, ICommandText **cmd_text)
1681 HRESULT hr;
1682 IOpenRowset *openrowset;
1683 ICommandText *command_text;
1684 ICommand *cmd;
1685 IDBCreateCommand *create_command;
1687 hr = IUnknown_QueryInterface(session, &IID_IOpenRowset, (void**)&openrowset);
1688 if (FAILED(hr))
1689 return hr;
1691 hr = IOpenRowset_QueryInterface(openrowset, &IID_IDBCreateCommand, (void**)&create_command);
1692 IOpenRowset_Release(openrowset);
1693 if (FAILED(hr))
1694 return hr;
1696 hr = IDBCreateCommand_CreateCommand(create_command, NULL, &IID_IUnknown, (IUnknown **)&cmd);
1697 IDBCreateCommand_Release(create_command);
1698 if (FAILED(hr))
1699 return hr;
1701 hr = ICommand_QueryInterface(cmd, &IID_ICommandText, (void**)&command_text);
1702 ICommand_Release(cmd);
1703 if (FAILED(hr))
1705 FIXME("Currently only ICommandText interface is support\n");
1706 return hr;
1709 hr = ICommandText_SetCommandText(command_text, &DBGUID_DEFAULT, command);
1710 if (FAILED(hr))
1712 ICommandText_Release(command_text);
1713 return hr;
1716 *cmd_text = command_text;
1718 return S_OK;
1721 #define ROUND_SIZE(size) (((size) + sizeof(void *) - 1) & ~(sizeof(void *) - 1))
1723 DEFINE_GUID(DBPROPSET_ROWSET, 0xc8b522be, 0x5cf3, 0x11ce, 0xad, 0xe5, 0x00, 0xaa, 0x00, 0x44, 0x77, 0x3d);
1725 static HRESULT create_bindings(IUnknown *rowset, struct recordset *recordset, DBBINDING **bind, DBBYTEOFFSET *size)
1727 HRESULT hr;
1728 IColumnsInfo *columninfo;
1729 IAccessor *accessor;
1730 DBORDINAL columns;
1731 DBCOLUMNINFO *colinfo;
1732 OLECHAR *stringsbuffer;
1733 DBBINDING *bindings;
1734 DBBYTEOFFSET offset;
1736 *size = 0;
1738 hr = IUnknown_QueryInterface(rowset, &IID_IColumnsInfo, (void**)&columninfo);
1739 if (FAILED(hr))
1740 return hr;
1742 hr = IUnknown_QueryInterface(rowset, &IID_IAccessor, (void**)&accessor);
1743 if (FAILED(hr))
1745 IColumnsInfo_Release(columninfo);
1746 return hr;
1749 hr = IColumnsInfo_GetColumnInfo(columninfo, &columns, &colinfo, &stringsbuffer);
1750 if (SUCCEEDED(hr))
1752 ULONG i;
1753 DBOBJECT *dbobj;
1754 offset = 1;
1756 recordset->columntypes = malloc(sizeof(DBTYPE) * columns);
1757 recordset->haccessors = calloc(1, sizeof(HACCESSOR) * columns );
1759 /* Do one allocation for the bindings and append the DBOBJECTS to the end.
1760 * This is to save on multiple allocations vs a little bit of extra memory.
1762 bindings = CoTaskMemAlloc( (sizeof(DBBINDING) + sizeof(DBOBJECT)) * columns);
1763 dbobj = (DBOBJECT *)((char*)bindings + (sizeof(DBBINDING) * columns));
1765 for (i=0; i < columns; i++)
1767 TRACE("Column %lu, pwszName: %s, pTypeInfo %p, iOrdinal %Iu, dwFlags 0x%08lx, "
1768 "ulColumnSize %Iu, wType %d, bPrecision %d, bScale %d\n",
1769 i, debugstr_w(colinfo[i].pwszName), colinfo[i].pTypeInfo, colinfo[i].iOrdinal,
1770 colinfo[i].dwFlags, colinfo[i].ulColumnSize, colinfo[i].wType,
1771 colinfo[i].bPrecision, colinfo[i].bScale);
1773 hr = append_field(recordset->fields, colinfo[i].pwszName, colinfo[i].wType, colinfo[i].ulColumnSize,
1774 colinfo[i].dwFlags, NULL);
1776 bindings[i].iOrdinal = colinfo[i].iOrdinal;
1777 bindings[i].obValue = offset;
1778 bindings[i].pTypeInfo = NULL;
1779 /* Always assigned the pObject even if it's not used. */
1780 bindings[i].pObject = &dbobj[i];
1781 bindings[i].pObject->dwFlags = 0;
1782 bindings[i].pObject->iid = IID_ISequentialStream;
1783 bindings[i].pBindExt = NULL;
1784 bindings[i].dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;
1785 bindings[i].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
1786 bindings[i].eParamIO = 0;
1788 recordset->columntypes[i] = colinfo[i].wType;
1789 if (colinfo[i].dwFlags & DBCOLUMNFLAGS_ISLONG)
1791 colinfo[i].wType = DBTYPE_IUNKNOWN;
1793 bindings[i].cbMaxLen = (colinfo[i].ulColumnSize + 1) * sizeof(WCHAR);
1794 offset += sizeof(ISequentialStream*);
1796 else if(colinfo[i].wType == DBTYPE_WSTR)
1798 /* ulColumnSize is the number of characters in the string not the actual buffer size */
1799 bindings[i].cbMaxLen = colinfo[i].ulColumnSize * sizeof(WCHAR);
1800 offset += bindings[i].cbMaxLen;
1802 else
1804 bindings[i].cbMaxLen = colinfo[i].ulColumnSize;
1805 offset += bindings[i].cbMaxLen;
1808 bindings[i].dwFlags = 0;
1809 bindings[i].wType = colinfo[i].wType;
1810 bindings[i].bPrecision = colinfo[i].bPrecision;
1811 bindings[i].bScale = colinfo[i].bScale;
1814 offset = ROUND_SIZE(offset);
1815 for (i=0; i < columns; i++)
1817 bindings[i].obLength = offset;
1818 bindings[i].obStatus = offset + sizeof(DBBYTEOFFSET);
1820 offset += sizeof(DBBYTEOFFSET) + sizeof(DBBYTEOFFSET);
1822 hr = IAccessor_CreateAccessor(accessor, DBACCESSOR_ROWDATA, 1, &bindings[i], 0, &recordset->haccessors[i], NULL);
1823 if (FAILED(hr))
1824 FIXME("IAccessor_CreateAccessor Failed 0x%0lx\n", hr);
1827 *size = offset;
1828 *bind = bindings;
1830 CoTaskMemFree(colinfo);
1831 CoTaskMemFree(stringsbuffer);
1834 IAccessor_Release(accessor);
1836 IColumnsInfo_Release(columninfo);
1838 return hr;
1841 static HRESULT load_all_recordset_data(struct recordset *recordset, IUnknown *rowset, DBBINDING *bindings,
1842 DBBYTEOFFSET datasize)
1844 IRowset *rowset2;
1845 DBORDINAL columns;
1846 HRESULT hr;
1847 DBCOUNTITEM obtained;
1848 HROW *row = NULL;
1849 int datarow = 0, datacol;
1850 char *data;
1852 columns = get_column_count(recordset);
1854 /* Create the data array */
1855 if (!resize_recordset( recordset, recordset->count ))
1857 WARN("Failed to resize recordset\n");
1858 return E_OUTOFMEMORY;
1861 hr = IUnknown_QueryInterface(rowset, &IID_IRowset, (void**)&rowset2);
1862 if (FAILED(hr))
1864 WARN("Failed to get IRowset interface (0x%08lx)\n", hr);
1865 return hr;
1868 data = malloc (datasize);
1869 if (!data)
1871 ERR("Failed to allocate row data (%Iu)\n", datasize);
1872 IRowset_Release(rowset2);
1873 return E_OUTOFMEMORY;
1876 hr = IRowset_GetNextRows(rowset2, 0, 0, 1, &obtained, &row);
1877 while (hr == S_OK)
1879 VARIANT copy;
1881 for (datacol = 0; datacol < columns; datacol++)
1883 hr = IRowset_GetData(rowset2, *row, recordset->haccessors[datacol], data);
1884 if (FAILED(hr))
1886 ERR("GetData Failed on Column %d (0x%08lx), status %Id\n", datacol, hr,
1887 *(DBBYTEOFFSET*)(data + bindings[datacol].obStatus));
1888 break;
1891 VariantInit(&copy);
1893 if ( *(DBBYTEOFFSET*)(data + bindings[datacol].obStatus) == DBSTATUS_S_ISNULL)
1895 V_VT(&copy) = VT_NULL;
1896 goto writedata;
1899 /* For most cases DBTYPE_* = VT_* type */
1900 V_VT(&copy) = bindings[datacol].wType;
1901 switch(bindings[datacol].wType)
1903 case DBTYPE_IUNKNOWN:
1905 ISequentialStream *seq;
1906 char unkdata[2048];
1907 ULONG size = 4096, dataRead = 0, total = 0;
1908 char *buffer = malloc(size), *p = buffer;
1909 HRESULT hr2;
1912 * Cast directly to the object we specified in our bindings. As this object
1913 * is referenced counted in some case and will error in GetData if the object
1914 * hasn't been released.
1916 seq = *(ISequentialStream**)(data + bindings[datacol].obValue);
1917 TRACE("Reading DBTYPE_IUNKNOWN %p\n", seq);
1921 dataRead = 0;
1922 hr2 = ISequentialStream_Read(seq, unkdata, sizeof(unkdata), &dataRead);
1923 if (FAILED(hr2) || !dataRead) break;
1925 total += dataRead;
1926 memcpy(p, unkdata, dataRead);
1927 p += dataRead;
1928 if (total == size)
1930 size *= 2; /* Double buffer */
1931 buffer = realloc(buffer, size);
1932 p = buffer + total;
1934 } while(hr2 == S_OK);
1936 if (recordset->columntypes[datacol] == DBTYPE_WSTR)
1938 V_VT(&copy) = VT_BSTR;
1939 V_BSTR(&copy) = SysAllocStringLen( (WCHAR*)buffer, total / sizeof(WCHAR) );
1941 else if (recordset->columntypes[datacol] == DBTYPE_BYTES)
1943 SAFEARRAYBOUND sab;
1945 sab.lLbound = 0;
1946 sab.cElements = total;
1948 V_VT(&copy) = (VT_ARRAY|VT_UI1);
1949 V_ARRAY(&copy) = SafeArrayCreate(VT_UI1, 1, &sab);
1951 memcpy( (BYTE*)V_ARRAY(&copy)->pvData, buffer, total);
1953 else
1955 FIXME("Unsupported conversion (%d)\n", recordset->columntypes[datacol]);
1956 V_VT(&copy) = VT_NULL;
1959 free(buffer);
1960 ISequentialStream_Release(seq);
1962 break;
1964 case DBTYPE_R4:
1965 V_R4(&copy) = *(float*)(data + bindings[datacol].obValue);
1966 break;
1967 case DBTYPE_R8:
1968 V_R8(&copy) = *(DOUBLE*)(data + bindings[datacol].obValue);
1969 break;
1970 case DBTYPE_I8:
1971 V_VT(&copy) = VT_I8;
1972 V_I8(&copy) = *(LONGLONG*)(data + bindings[datacol].obValue);
1973 break;
1974 case DBTYPE_I4:
1975 V_I4(&copy) = *(LONG*)(data + bindings[datacol].obValue);
1976 break;
1977 case DBTYPE_STR:
1979 WCHAR *str = heap_strdupAtoW( (char*)(data + bindings[datacol].obValue) );
1981 V_VT(&copy) = VT_BSTR;
1982 V_BSTR(&copy) = SysAllocString(str);
1983 free(str);
1984 break;
1986 case DBTYPE_WSTR:
1988 V_VT(&copy) = VT_BSTR;
1989 V_BSTR(&copy) = SysAllocString( (WCHAR*)(data + bindings[datacol].obValue) );
1990 break;
1992 case DBTYPE_DBTIMESTAMP:
1994 SYSTEMTIME st;
1995 DBTIMESTAMP *ts = (DBTIMESTAMP *)(data + bindings[datacol].obValue);
1996 DATE d;
1998 V_VT(&copy) = VT_DATE;
2000 st.wYear = ts->year;
2001 st.wMonth = ts->month;
2002 st.wDay = ts->day;
2003 st.wHour = ts->hour;
2004 st.wMinute = ts->minute;
2005 st.wSecond = ts->second;
2006 st.wMilliseconds = ts->fraction/1000000;
2007 st.wDayOfWeek = 0;
2008 hr = (SystemTimeToVariantTime(&st, &d) ? S_OK : E_FAIL);
2010 V_DATE(&copy) = d;
2011 break;
2013 default:
2014 V_I2(&copy) = 0;
2015 FIXME("Unknown Type %d\n", bindings[datacol].wType);
2018 writedata:
2019 VariantInit( &recordset->data[datarow * columns + datacol] );
2020 if ((hr = VariantCopy( &recordset->data[datarow * columns + datacol] , &copy)) != S_OK)
2022 ERR("Column %d copy failed. Data %s\n", datacol, debugstr_variant(&copy));
2025 VariantClear(&copy);
2028 datarow++;
2030 hr = IRowset_ReleaseRows(rowset2, 1, row, NULL, NULL, NULL);
2031 if (FAILED(hr))
2032 ERR("Failed to ReleaseRows 0x%08lx\n", hr);
2034 hr = IRowset_GetNextRows(rowset2, 0, 0, 1, &obtained, &row);
2037 free(data);
2038 IRowset_Release(rowset2);
2040 return S_OK;
2043 static HRESULT WINAPI recordset_Open( _Recordset *iface, VARIANT source, VARIANT active_connection,
2044 CursorTypeEnum cursor_type, LockTypeEnum lock_type, LONG options )
2046 struct recordset *recordset = impl_from_Recordset( iface );
2047 ADOConnectionConstruction15 *construct;
2048 IUnknown *session;
2049 ICommandText *command_text;
2050 DBROWCOUNT affected;
2051 IUnknown *rowset;
2052 HRESULT hr;
2053 DBBINDING *bindings;
2054 DBBYTEOFFSET datasize;
2056 TRACE( "%p, %s, %s, %d, %d, %ld\n", recordset, debugstr_variant(&source), debugstr_variant(&active_connection),
2057 cursor_type, lock_type, options );
2059 if (recordset->state == adStateOpen) return MAKE_ADO_HRESULT( adErrObjectOpen );
2061 if (recordset->fields)
2063 recordset->state = adStateOpen;
2064 return S_OK;
2067 if (V_VT(&active_connection) != VT_DISPATCH)
2069 FIXME("Unsupported Active connection type %d\n", V_VT(&active_connection));
2070 return MAKE_ADO_HRESULT( adErrInvalidConnection );
2073 hr = IDispatch_QueryInterface(V_DISPATCH(&active_connection), &IID_ADOConnectionConstruction15, (void**)&construct);
2074 if (FAILED(hr))
2075 return E_FAIL;
2077 hr = ADOConnectionConstruction15_get_Session(construct, &session);
2078 ADOConnectionConstruction15_Release(construct);
2079 if (FAILED(hr))
2080 return E_FAIL;
2082 hr = VariantCopy(&recordset->active_connection, &active_connection);
2083 if (FAILED(hr))
2084 return E_FAIL;
2086 if (V_VT(&source) != VT_BSTR)
2088 FIXME("Unsupported source type!\n");
2089 IUnknown_Release(session);
2090 return E_FAIL;
2093 hr = create_command_text(session, V_BSTR(&source), &command_text);
2094 IUnknown_Release(session);
2095 if (FAILED(hr))
2096 return hr;
2098 hr = ICommandText_Execute(command_text, NULL, &IID_IUnknown, NULL, &affected, &rowset);
2099 ICommandText_Release(command_text);
2100 if (FAILED(hr) || !rowset)
2101 return hr;
2103 /* We want to create the field member variable without mapping the rowset fields, this will
2104 * save querying the fields twice. Fields will be added while we create the bindings.
2106 hr = fields_create( recordset, &recordset->fields );
2107 if (FAILED(hr))
2109 IUnknown_Release(rowset);
2110 return hr;
2113 hr = create_bindings(rowset, recordset, &bindings, &datasize);
2114 if (FAILED(hr))
2116 WARN("Failed to load bindings (%lx)\n", hr);
2117 IUnknown_Release(rowset);
2118 return hr;
2121 recordset->count = affected > 0 ? affected : 0;
2122 recordset->index = affected > 0 ? 0 : -1;
2125 * We can safely just return with an empty recordset here
2127 if (affected > 0)
2129 hr = load_all_recordset_data(recordset, rowset, bindings, datasize);
2130 if (FAILED(hr))
2132 WARN("Failed to load all recordset data (%lx)\n", hr);
2133 CoTaskMemFree(bindings);
2134 IUnknown_Release(rowset);
2135 return hr;
2139 CoTaskMemFree(bindings);
2141 ADORecordsetConstruction_put_Rowset(&recordset->ADORecordsetConstruction_iface, rowset);
2142 recordset->cursor_type = cursor_type;
2143 recordset->state = adStateOpen;
2145 IUnknown_Release(rowset);
2147 return hr;
2150 static HRESULT WINAPI recordset_Requery( _Recordset *iface, LONG options )
2152 FIXME( "%p, %ld\n", iface, options );
2153 return E_NOTIMPL;
2156 static HRESULT WINAPI recordset__xResync( _Recordset *iface, AffectEnum affect_records )
2158 FIXME( "%p, %u\n", iface, affect_records );
2159 return E_NOTIMPL;
2162 static HRESULT WINAPI recordset_Update( _Recordset *iface, VARIANT fields, VARIANT values )
2164 struct recordset *recordset = impl_from_Recordset( iface );
2166 FIXME( "%p, %s, %s\n", iface, debugstr_variant(&fields), debugstr_variant(&values) );
2168 if (V_DISPATCH(&recordset->active_connection) == NULL)
2169 return S_OK;
2171 recordset->editmode = adEditNone;
2172 return E_NOTIMPL;
2175 static HRESULT WINAPI recordset_get_AbsolutePage( _Recordset *iface, PositionEnum_Param *pos )
2177 FIXME( "%p, %p\n", iface, pos );
2178 return E_NOTIMPL;
2181 static HRESULT WINAPI recordset_put_AbsolutePage( _Recordset *iface, PositionEnum_Param pos )
2183 FIXME( "%p, %Id\n", iface, pos );
2184 return E_NOTIMPL;
2187 static HRESULT WINAPI recordset_get_EditMode( _Recordset *iface, EditModeEnum *mode )
2189 struct recordset *recordset = impl_from_Recordset( iface );
2190 TRACE( "%p, %p\n", iface, mode );
2192 if (recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed );
2193 if (recordset->index < 0) return MAKE_ADO_HRESULT( adErrNoCurrentRecord );
2195 *mode = recordset->editmode;
2196 return S_OK;
2199 static HRESULT WINAPI recordset_get_Filter( _Recordset *iface, VARIANT *criteria )
2201 struct recordset *recordset = impl_from_Recordset( iface );
2202 TRACE( "%p, %p\n", iface, criteria );
2204 if (!criteria) return MAKE_ADO_HRESULT( adErrInvalidArgument );
2206 VariantCopy(criteria, &recordset->filter);
2207 return S_OK;
2210 static HRESULT WINAPI recordset_put_Filter( _Recordset *iface, VARIANT criteria )
2212 struct recordset *recordset = impl_from_Recordset( iface );
2213 TRACE( "%p, %s\n", recordset, debugstr_variant(&criteria) );
2215 if (V_VT(&criteria) != VT_I2 && V_VT(&criteria) != VT_I4 && V_VT(&criteria) != VT_BSTR)
2216 return MAKE_ADO_HRESULT( adErrInvalidArgument );
2218 if (V_VT(&criteria) == VT_BSTR && recordset->state == adStateOpen)
2220 FIXME("No filter performed. Reporting no records found.\n");
2222 /* Set the index to signal we didn't find a record. */
2223 recordset->index = -1;
2225 else
2227 recordset->index = recordset->count ? 0 : -1; /* Reset */
2230 VariantCopy(&recordset->filter, &criteria);
2231 return S_OK;
2234 static HRESULT WINAPI recordset_get_PageCount( _Recordset *iface, ADO_LONGPTR *count )
2236 FIXME( "%p, %p\n", iface, count );
2237 return E_NOTIMPL;
2240 static HRESULT WINAPI recordset_get_PageSize( _Recordset *iface, LONG *size )
2242 FIXME( "%p, %p\n", iface, size );
2243 return E_NOTIMPL;
2246 static HRESULT WINAPI recordset_put_PageSize( _Recordset *iface, LONG size )
2248 FIXME( "%p, %ld\n", iface, size );
2249 return E_NOTIMPL;
2252 static HRESULT WINAPI recordset_get_Sort( _Recordset *iface, BSTR *criteria )
2254 FIXME( "%p, %p\n", iface, criteria );
2255 return E_NOTIMPL;
2258 static HRESULT WINAPI recordset_put_Sort( _Recordset *iface, BSTR criteria )
2260 FIXME( "%p, %s\n", iface, debugstr_w(criteria) );
2261 return E_NOTIMPL;
2264 static HRESULT WINAPI recordset_get_Status( _Recordset *iface, LONG *status )
2266 FIXME( "%p, %p\n", iface, status );
2267 return E_NOTIMPL;
2270 static HRESULT WINAPI recordset_get_State( _Recordset *iface, LONG *state )
2272 struct recordset *recordset = impl_from_Recordset( iface );
2274 TRACE( "%p, %p\n", recordset, state );
2276 *state = recordset->state;
2277 return S_OK;
2280 static HRESULT WINAPI recordset__xClone( _Recordset *iface, _Recordset **obj )
2282 FIXME( "%p, %p\n", iface, obj );
2283 return E_NOTIMPL;
2286 static HRESULT WINAPI recordset_UpdateBatch( _Recordset *iface, AffectEnum affect_records )
2288 struct recordset *recordset = impl_from_Recordset( iface );
2290 FIXME( "%p, %u\n", iface, affect_records );
2292 if (V_DISPATCH(&recordset->active_connection) == NULL)
2293 return S_OK;
2295 recordset->editmode = adEditNone;
2296 return E_NOTIMPL;
2299 static HRESULT WINAPI recordset_CancelBatch( _Recordset *iface, AffectEnum affect_records )
2301 struct recordset *recordset = impl_from_Recordset( iface );
2303 FIXME( "%p, %u\n", iface, affect_records );
2305 if (V_DISPATCH(&recordset->active_connection) == NULL)
2306 return S_OK;
2308 recordset->editmode = adEditNone;
2309 return E_NOTIMPL;
2312 static HRESULT WINAPI recordset_get_CursorLocation( _Recordset *iface, CursorLocationEnum *cursor_loc )
2314 struct recordset *recordset = impl_from_Recordset( iface );
2316 TRACE( "%p, %p\n", iface, cursor_loc );
2318 *cursor_loc = recordset->cursor_location;
2320 return S_OK;
2323 static HRESULT WINAPI recordset_put_CursorLocation( _Recordset *iface, CursorLocationEnum cursor_loc )
2325 struct recordset *recordset = impl_from_Recordset( iface );
2327 TRACE( "%p, %u\n", iface, cursor_loc );
2329 if (recordset->state == adStateOpen) return MAKE_ADO_HRESULT( adErrObjectOpen );
2331 recordset->cursor_location = cursor_loc;
2333 return S_OK;
2336 static HRESULT WINAPI recordset_NextRecordset( _Recordset *iface, VARIANT *records_affected, _Recordset **record_set )
2338 FIXME( "%p, %p, %p\n", iface, records_affected, record_set );
2339 return E_NOTIMPL;
2342 static HRESULT WINAPI recordset_Supports( _Recordset *iface, CursorOptionEnum cursor_options, VARIANT_BOOL *ret )
2344 FIXME( "%p, %08x, %p\n", iface, cursor_options, ret );
2345 return E_NOTIMPL;
2348 static HRESULT WINAPI recordset_get_Collect( _Recordset *iface, VARIANT index, VARIANT *var )
2350 FIXME( "%p, %s, %p\n", iface, debugstr_variant(&index), var );
2351 return E_NOTIMPL;
2354 static HRESULT WINAPI recordset_put_Collect( _Recordset *iface, VARIANT index, VARIANT var )
2356 FIXME( "%p, %s, %s\n", iface, debugstr_variant(&index), debugstr_variant(&var) );
2357 return E_NOTIMPL;
2360 static HRESULT WINAPI recordset_get_MarshalOptions( _Recordset *iface, MarshalOptionsEnum *options )
2362 FIXME( "%p, %p\n", iface, options );
2363 return E_NOTIMPL;
2366 static HRESULT WINAPI recordset_put_MarshalOptions( _Recordset *iface, MarshalOptionsEnum options )
2368 FIXME( "%p, %u\n", iface, options );
2369 return E_NOTIMPL;
2372 static HRESULT WINAPI recordset_Find( _Recordset *iface, BSTR criteria, LONG skip_records,
2373 SearchDirectionEnum search_direction, VARIANT start )
2375 FIXME( "%p, %s, %ld, %d, %s\n", iface, debugstr_w(criteria), skip_records, search_direction,
2376 debugstr_variant(&start) );
2377 return E_NOTIMPL;
2380 static HRESULT WINAPI recordset_Cancel( _Recordset *iface )
2382 struct recordset *recordset = impl_from_Recordset( iface );
2384 FIXME( "%p\n", iface );
2386 if (V_DISPATCH(&recordset->active_connection) == NULL)
2387 return S_OK;
2389 recordset->editmode = adEditNone;
2390 return E_NOTIMPL;
2393 static HRESULT WINAPI recordset_get_DataSource( _Recordset *iface, IUnknown **data_source )
2395 FIXME( "%p, %p\n", iface, data_source );
2396 return E_NOTIMPL;
2399 static HRESULT WINAPI recordset_putref_DataSource( _Recordset *iface, IUnknown *data_source )
2401 FIXME( "%p, %p\n", iface, data_source );
2402 return E_NOTIMPL;
2405 static HRESULT WINAPI recordset__xSave( _Recordset *iface, BSTR filename, PersistFormatEnum persist_format )
2407 FIXME( "%p, %s, %u\n", iface, debugstr_w(filename), persist_format );
2408 return E_NOTIMPL;
2411 static HRESULT WINAPI recordset_get_ActiveCommand( _Recordset *iface, IDispatch **cmd )
2413 FIXME( "%p, %p\n", iface, cmd );
2414 return E_NOTIMPL;
2417 static HRESULT WINAPI recordset_put_StayInSync( _Recordset *iface, VARIANT_BOOL stay_in_sync )
2419 FIXME( "%p, %d\n", iface, stay_in_sync );
2420 return E_NOTIMPL;
2423 static HRESULT WINAPI recordset_get_StayInSync( _Recordset *iface, VARIANT_BOOL *stay_in_sync )
2425 FIXME( "%p, %p\n", iface, stay_in_sync );
2426 return E_NOTIMPL;
2429 static HRESULT WINAPI recordset_GetString( _Recordset *iface, StringFormatEnum string_format, LONG num_rows,
2430 BSTR column_delimiter, BSTR row_delimiter, BSTR null_expr,
2431 BSTR *ret_string )
2433 FIXME( "%p, %u, %ld, %s, %s, %s, %p\n", iface, string_format, num_rows, debugstr_w(column_delimiter),
2434 debugstr_w(row_delimiter), debugstr_w(null_expr), ret_string );
2435 return E_NOTIMPL;
2438 static HRESULT WINAPI recordset_get_DataMember( _Recordset *iface, BSTR *data_member )
2440 FIXME( "%p, %p\n", iface, data_member );
2441 return E_NOTIMPL;
2444 static HRESULT WINAPI recordset_put_DataMember( _Recordset *iface, BSTR data_member )
2446 FIXME( "%p, %s\n", iface, debugstr_w(data_member) );
2447 return E_NOTIMPL;
2450 static HRESULT WINAPI recordset_CompareBookmarks( _Recordset *iface, VARIANT bookmark1, VARIANT bookmark2, CompareEnum *compare )
2452 FIXME( "%p, %s, %s, %p\n", iface, debugstr_variant(&bookmark1), debugstr_variant(&bookmark2), compare );
2453 return E_NOTIMPL;
2456 static HRESULT WINAPI recordset_Clone( _Recordset *iface, LockTypeEnum lock_type, _Recordset **obj )
2458 struct recordset *recordset = impl_from_Recordset( iface );
2459 FIXME( "%p, %d, %p\n", recordset, lock_type, obj );
2461 *obj = iface;
2462 recordset_AddRef( iface );
2463 return S_OK;
2466 static HRESULT WINAPI recordset_Resync( _Recordset *iface, AffectEnum affect_records, ResyncEnum resync_values )
2468 FIXME( "%p, %u, %u\n", iface, affect_records, resync_values );
2469 return E_NOTIMPL;
2472 static HRESULT WINAPI recordset_Seek( _Recordset *iface, VARIANT key_values, SeekEnum seek_option )
2474 FIXME( "%p, %s, %u\n", iface, debugstr_variant(&key_values), seek_option );
2475 return E_NOTIMPL;
2478 static HRESULT WINAPI recordset_put_Index( _Recordset *iface, BSTR index )
2480 FIXME( "%p, %s\n", iface, debugstr_w(index) );
2481 return E_NOTIMPL;
2484 static HRESULT WINAPI recordset_get_Index( _Recordset *iface, BSTR *index )
2486 FIXME( "%p, %p\n", iface, index );
2487 return E_NOTIMPL;
2490 static HRESULT WINAPI recordset_Save( _Recordset *iface, VARIANT destination, PersistFormatEnum persist_format )
2492 FIXME( "%p, %s, %u\n", iface, debugstr_variant(&destination), persist_format );
2493 return E_NOTIMPL;
2496 static const struct _RecordsetVtbl recordset_vtbl =
2498 recordset_QueryInterface,
2499 recordset_AddRef,
2500 recordset_Release,
2501 recordset_GetTypeInfoCount,
2502 recordset_GetTypeInfo,
2503 recordset_GetIDsOfNames,
2504 recordset_Invoke,
2505 recordset_get_Properties,
2506 recordset_get_AbsolutePosition,
2507 recordset_put_AbsolutePosition,
2508 recordset_putref_ActiveConnection,
2509 recordset_put_ActiveConnection,
2510 recordset_get_ActiveConnection,
2511 recordset_get_BOF,
2512 recordset_get_Bookmark,
2513 recordset_put_Bookmark,
2514 recordset_get_CacheSize,
2515 recordset_put_CacheSize,
2516 recordset_get_CursorType,
2517 recordset_put_CursorType,
2518 recordset_get_EOF,
2519 recordset_get_Fields,
2520 recordset_get_LockType,
2521 recordset_put_LockType,
2522 recordset_get_MaxRecords,
2523 recordset_put_MaxRecords,
2524 recordset_get_RecordCount,
2525 recordset_putref_Source,
2526 recordset_put_Source,
2527 recordset_get_Source,
2528 recordset_AddNew,
2529 recordset_CancelUpdate,
2530 recordset_Close,
2531 recordset_Delete,
2532 recordset_GetRows,
2533 recordset_Move,
2534 recordset_MoveNext,
2535 recordset_MovePrevious,
2536 recordset_MoveFirst,
2537 recordset_MoveLast,
2538 recordset_Open,
2539 recordset_Requery,
2540 recordset__xResync,
2541 recordset_Update,
2542 recordset_get_AbsolutePage,
2543 recordset_put_AbsolutePage,
2544 recordset_get_EditMode,
2545 recordset_get_Filter,
2546 recordset_put_Filter,
2547 recordset_get_PageCount,
2548 recordset_get_PageSize,
2549 recordset_put_PageSize,
2550 recordset_get_Sort,
2551 recordset_put_Sort,
2552 recordset_get_Status,
2553 recordset_get_State,
2554 recordset__xClone,
2555 recordset_UpdateBatch,
2556 recordset_CancelBatch,
2557 recordset_get_CursorLocation,
2558 recordset_put_CursorLocation,
2559 recordset_NextRecordset,
2560 recordset_Supports,
2561 recordset_get_Collect,
2562 recordset_put_Collect,
2563 recordset_get_MarshalOptions,
2564 recordset_put_MarshalOptions,
2565 recordset_Find,
2566 recordset_Cancel,
2567 recordset_get_DataSource,
2568 recordset_putref_DataSource,
2569 recordset__xSave,
2570 recordset_get_ActiveCommand,
2571 recordset_put_StayInSync,
2572 recordset_get_StayInSync,
2573 recordset_GetString,
2574 recordset_get_DataMember,
2575 recordset_put_DataMember,
2576 recordset_CompareBookmarks,
2577 recordset_Clone,
2578 recordset_Resync,
2579 recordset_Seek,
2580 recordset_put_Index,
2581 recordset_get_Index,
2582 recordset_Save
2585 static inline struct recordset *recordset_from_ISupportErrorInfo( ISupportErrorInfo *iface )
2587 return CONTAINING_RECORD( iface, struct recordset, ISupportErrorInfo_iface );
2590 static HRESULT WINAPI recordset_supporterrorinfo_QueryInterface( ISupportErrorInfo *iface, REFIID riid, void **obj )
2592 struct recordset *recordset = recordset_from_ISupportErrorInfo( iface );
2593 return _Recordset_QueryInterface( &recordset->Recordset_iface, riid, obj );
2596 static ULONG WINAPI recordset_supporterrorinfo_AddRef( ISupportErrorInfo *iface )
2598 struct recordset *recordset = recordset_from_ISupportErrorInfo( iface );
2599 return _Recordset_AddRef( &recordset->Recordset_iface );
2602 static ULONG WINAPI recordset_supporterrorinfo_Release( ISupportErrorInfo *iface )
2604 struct recordset *recordset = recordset_from_ISupportErrorInfo( iface );
2605 return _Recordset_Release( &recordset->Recordset_iface );
2608 static HRESULT WINAPI recordset_supporterrorinfo_InterfaceSupportsErrorInfo( ISupportErrorInfo *iface, REFIID riid )
2610 struct recordset *recordset = recordset_from_ISupportErrorInfo( iface );
2611 FIXME( "%p, %s\n", recordset, debugstr_guid(riid) );
2612 return S_FALSE;
2615 static const ISupportErrorInfoVtbl recordset_supporterrorinfo_vtbl =
2617 recordset_supporterrorinfo_QueryInterface,
2618 recordset_supporterrorinfo_AddRef,
2619 recordset_supporterrorinfo_Release,
2620 recordset_supporterrorinfo_InterfaceSupportsErrorInfo
2623 static HRESULT WINAPI rsconstruction_QueryInterface(ADORecordsetConstruction *iface,
2624 REFIID riid, void **obj)
2626 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2627 return _Recordset_QueryInterface( &recordset->Recordset_iface, riid, obj );
2630 static ULONG WINAPI rsconstruction_AddRef(ADORecordsetConstruction *iface)
2632 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2633 return _Recordset_AddRef( &recordset->Recordset_iface );
2636 static ULONG WINAPI rsconstruction_Release(ADORecordsetConstruction *iface)
2638 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2639 return _Recordset_Release( &recordset->Recordset_iface );
2642 static HRESULT WINAPI rsconstruction_GetTypeInfoCount(ADORecordsetConstruction *iface, UINT *pctinfo)
2644 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2645 TRACE( "%p, %p\n", recordset, pctinfo );
2646 *pctinfo = 1;
2647 return S_OK;
2650 static HRESULT WINAPI rsconstruction_GetTypeInfo(ADORecordsetConstruction *iface, UINT iTInfo,
2651 LCID lcid, ITypeInfo **ppTInfo)
2653 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2654 TRACE( "%p %u %lu %p\n", recordset, iTInfo, lcid, ppTInfo );
2655 return get_typeinfo(ADORecordsetConstruction_tid, ppTInfo);
2658 static HRESULT WINAPI rsconstruction_GetIDsOfNames(ADORecordsetConstruction *iface, REFIID riid,
2659 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
2661 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2662 HRESULT hr;
2663 ITypeInfo *typeinfo;
2665 TRACE( "%p %s %p %u %lu %p\n", recordset, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId );
2667 hr = get_typeinfo(ADORecordsetConstruction_tid, &typeinfo);
2668 if(SUCCEEDED(hr))
2670 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2671 ITypeInfo_Release(typeinfo);
2674 return hr;
2677 static HRESULT WINAPI rsconstruction_Invoke(ADORecordsetConstruction *iface, DISPID dispIdMember,
2678 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
2679 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2681 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2682 HRESULT hr;
2683 ITypeInfo *typeinfo;
2685 TRACE( "%p %ld %s %ld %d %p %p %p %p\n", recordset, dispIdMember, debugstr_guid(riid),
2686 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr );
2688 hr = get_typeinfo(ADORecordsetConstruction_tid, &typeinfo);
2689 if(SUCCEEDED(hr))
2691 hr = ITypeInfo_Invoke(typeinfo, &recordset->ADORecordsetConstruction_iface, dispIdMember, wFlags,
2692 pDispParams, pVarResult, pExcepInfo, puArgErr);
2693 ITypeInfo_Release(typeinfo);
2696 return hr;
2699 static HRESULT WINAPI rsconstruction_get_Rowset(ADORecordsetConstruction *iface, IUnknown **row_set)
2701 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2702 HRESULT hr;
2704 TRACE( "%p, %p\n", recordset, row_set );
2706 hr = IRowset_QueryInterface(recordset->row_set, &IID_IUnknown, (void**)row_set);
2707 if ( FAILED(hr) ) return E_FAIL;
2709 return S_OK;
2712 static HRESULT WINAPI rsconstruction_put_Rowset(ADORecordsetConstruction *iface, IUnknown *unk)
2714 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2715 HRESULT hr;
2716 IRowset *rowset;
2718 TRACE( "%p, %p\n", recordset, unk );
2720 hr = IUnknown_QueryInterface(unk, &IID_IRowset, (void**)&rowset);
2721 if ( FAILED(hr) ) return E_FAIL;
2723 if ( recordset->row_set ) IRowset_Release( recordset->row_set );
2724 recordset->row_set = rowset;
2726 return S_OK;
2729 static HRESULT WINAPI rsconstruction_get_Chapter(ADORecordsetConstruction *iface, ADO_LONGPTR *chapter)
2731 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2732 FIXME( "%p, %p\n", recordset, chapter );
2733 return E_NOTIMPL;
2736 static HRESULT WINAPI rsconstruction_put_Chapter(ADORecordsetConstruction *iface, ADO_LONGPTR chapter)
2738 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2739 FIXME( "%p, %Id\n", recordset, chapter );
2740 return E_NOTIMPL;
2743 static HRESULT WINAPI rsconstruction_get_RowPosition(ADORecordsetConstruction *iface, IUnknown **row_pos)
2745 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2746 FIXME( "%p, %p\n", recordset, row_pos );
2747 return E_NOTIMPL;
2750 static HRESULT WINAPI rsconstruction_put_RowPosition(ADORecordsetConstruction *iface, IUnknown *row_pos)
2752 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2753 FIXME( "%p, %p\n", recordset, row_pos );
2754 return E_NOTIMPL;
2757 static const ADORecordsetConstructionVtbl rsconstruction_vtbl =
2759 rsconstruction_QueryInterface,
2760 rsconstruction_AddRef,
2761 rsconstruction_Release,
2762 rsconstruction_GetTypeInfoCount,
2763 rsconstruction_GetTypeInfo,
2764 rsconstruction_GetIDsOfNames,
2765 rsconstruction_Invoke,
2766 rsconstruction_get_Rowset,
2767 rsconstruction_put_Rowset,
2768 rsconstruction_get_Chapter,
2769 rsconstruction_put_Chapter,
2770 rsconstruction_get_RowPosition,
2771 rsconstruction_put_RowPosition
2774 HRESULT Recordset_create( void **obj )
2776 struct recordset *recordset;
2778 if (!(recordset = calloc( 1, sizeof(*recordset) ))) return E_OUTOFMEMORY;
2779 recordset->Recordset_iface.lpVtbl = &recordset_vtbl;
2780 recordset->ISupportErrorInfo_iface.lpVtbl = &recordset_supporterrorinfo_vtbl;
2781 recordset->ADORecordsetConstruction_iface.lpVtbl = &rsconstruction_vtbl;
2782 V_VT(&recordset->active_connection) = VT_DISPATCH;
2783 V_DISPATCH(&recordset->active_connection) = NULL;
2784 recordset->refs = 1;
2785 recordset->index = -1;
2786 recordset->cursor_location = adUseServer;
2787 recordset->cursor_type = adOpenForwardOnly;
2788 recordset->row_set = NULL;
2789 recordset->editmode = adEditNone;
2790 VariantInit( &recordset->filter );
2791 recordset->columntypes = NULL;
2792 recordset->haccessors = NULL;
2794 *obj = &recordset->Recordset_iface;
2795 TRACE( "returning iface %p\n", *obj );
2796 return S_OK;