cmd: DIR command outputs free space for the path.
[wine.git] / dlls / msado15 / recordset.c
blob84db7fc581df46effe275e2c2568c52571dd25a0
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 LONG state;
43 struct fields *fields;
44 LONG count;
45 LONG allocated;
46 LONG index;
47 VARIANT *data;
48 CursorLocationEnum cursor_location;
49 CursorTypeEnum cursor_type;
50 IRowset *row_set;
51 EditModeEnum editmode;
52 VARIANT filter;
54 DBTYPE *columntypes;
55 HACCESSOR *haccessors;
58 struct fields
60 Fields Fields_iface;
61 ISupportErrorInfo ISupportErrorInfo_iface;
62 LONG refs;
63 Field **field;
64 ULONG count;
65 ULONG allocated;
66 struct recordset *recordset;
69 struct field
71 Field Field_iface;
72 ISupportErrorInfo ISupportErrorInfo_iface;
73 Properties Properties_iface;
74 LONG refs;
75 WCHAR *name;
76 DataTypeEnum type;
77 LONG defined_size;
78 LONG attrs;
79 LONG index;
80 struct recordset *recordset;
82 /* Field Properties */
83 VARIANT optimize;
86 static inline struct field *impl_from_Field( Field *iface )
88 return CONTAINING_RECORD( iface, struct field, Field_iface );
91 static inline struct field *impl_from_Properties( Properties *iface )
93 return CONTAINING_RECORD( iface, struct field, Properties_iface );
96 static ULONG WINAPI field_AddRef( Field *iface )
98 struct field *field = impl_from_Field( iface );
99 LONG refs = InterlockedIncrement( &field->refs );
100 TRACE( "%p new refcount %ld\n", field, refs );
101 return refs;
104 static ULONG WINAPI field_Release( Field *iface )
106 struct field *field = impl_from_Field( iface );
107 LONG refs = InterlockedDecrement( &field->refs );
108 TRACE( "%p new refcount %ld\n", field, refs );
109 if (!refs)
111 TRACE( "destroying %p\n", field );
112 free( field->name );
113 free( field );
115 return refs;
118 static HRESULT WINAPI field_QueryInterface( Field *iface, REFIID riid, void **obj )
120 struct field *field = impl_from_Field( iface );
121 TRACE( "%p, %s, %p\n", iface, debugstr_guid(riid), obj );
123 if (IsEqualGUID( riid, &IID_Field ) || IsEqualGUID( riid, &IID_IDispatch ) ||
124 IsEqualGUID( riid, &IID_IUnknown ))
126 *obj = iface;
128 else if (IsEqualGUID( riid, &IID_ISupportErrorInfo ))
130 *obj = &field->ISupportErrorInfo_iface;
132 else
134 FIXME( "interface %s not implemented\n", debugstr_guid(riid) );
135 return E_NOINTERFACE;
137 field_AddRef( iface );
138 return S_OK;
141 static HRESULT WINAPI field_GetTypeInfoCount( Field *iface, UINT *count )
143 struct field *field = impl_from_Field( iface );
144 TRACE( "%p, %p\n", field, count );
145 *count = 1;
146 return S_OK;
149 static HRESULT WINAPI field_GetTypeInfo( Field *iface, UINT index, LCID lcid, ITypeInfo **info )
151 struct field *field = impl_from_Field( iface );
152 TRACE( "%p, %u, %lu, %p\n", field, index, lcid, info );
153 return get_typeinfo(Field_tid, info);
156 static HRESULT WINAPI field_GetIDsOfNames( Field *iface, REFIID riid, LPOLESTR *names, UINT count,
157 LCID lcid, DISPID *dispid )
159 struct field *field = impl_from_Field( iface );
160 HRESULT hr;
161 ITypeInfo *typeinfo;
163 TRACE( "%p, %s, %p, %u, %lu, %p\n", field, debugstr_guid(riid), names, count, lcid, dispid );
165 hr = get_typeinfo(Field_tid, &typeinfo);
166 if(SUCCEEDED(hr))
168 hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, dispid);
169 ITypeInfo_Release(typeinfo);
172 return hr;
175 static HRESULT WINAPI field_Invoke( Field *iface, DISPID member, REFIID riid, LCID lcid, WORD flags,
176 DISPPARAMS *params, VARIANT *result, EXCEPINFO *excep_info, UINT *arg_err )
178 struct field *field = impl_from_Field( iface );
179 HRESULT hr;
180 ITypeInfo *typeinfo;
182 TRACE( "%p, %ld, %s, %ld, %d, %p, %p, %p, %p\n", field, member, debugstr_guid(riid), lcid, flags, params,
183 result, excep_info, arg_err );
185 hr = get_typeinfo(Field_tid, &typeinfo);
186 if(SUCCEEDED(hr))
188 hr = ITypeInfo_Invoke(typeinfo, &field->Field_iface, member, flags, params,
189 result, excep_info, arg_err);
190 ITypeInfo_Release(typeinfo);
193 return hr;
196 static HRESULT WINAPI field_get_Properties( Field *iface, Properties **obj )
198 struct field *field = impl_from_Field( iface );
199 TRACE( "%p, %p\n", iface, obj );
201 *obj = &field->Properties_iface;
202 Properties_AddRef(&field->Properties_iface);
203 return S_OK;
206 static HRESULT WINAPI field_get_ActualSize( Field *iface, ADO_LONGPTR *size )
208 struct field *field = impl_from_Field( iface );
209 FIXME( "%p, %p\n", field, size );
210 *size = 0;
211 return S_OK;
214 static HRESULT WINAPI field_get_Attributes( Field *iface, LONG *attrs )
216 struct field *field = impl_from_Field( iface );
218 TRACE( "%p, %p\n", field, attrs );
220 *attrs = field->attrs;
221 return S_OK;
224 static HRESULT WINAPI field_get_DefinedSize( Field *iface, ADO_LONGPTR *size )
226 struct field *field = impl_from_Field( iface );
228 TRACE( "%p, %p\n", field, size );
230 *size = field->defined_size;
231 return S_OK;
234 static HRESULT WINAPI field_get_Name( Field *iface, BSTR *str )
236 struct field *field = impl_from_Field( iface );
237 BSTR name;
239 TRACE( "%p, %p\n", field, str );
241 if (!(name = SysAllocString( field->name ))) return E_OUTOFMEMORY;
242 *str = name;
243 return S_OK;
246 static HRESULT WINAPI field_get_Type( Field *iface, DataTypeEnum *type )
248 struct field *field = impl_from_Field( iface );
250 TRACE( "%p, %p\n", field, type );
252 *type = field->type;
253 return S_OK;
256 static LONG get_column_count( struct recordset *recordset )
258 return recordset->fields->count;
261 static HRESULT WINAPI field_get_Value( Field *iface, VARIANT *val )
263 struct field *field = impl_from_Field( iface );
264 ULONG row = field->recordset->index, col = field->index, col_count;
265 VARIANT copy;
266 HRESULT hr;
268 TRACE( "%p, %p\n", field, val );
270 if (field->recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed );
271 if (field->recordset->index < 0) return MAKE_ADO_HRESULT( adErrNoCurrentRecord );
273 col_count = get_column_count( field->recordset );
275 VariantInit( &copy );
276 if ((hr = VariantCopy( &copy, &field->recordset->data[row * col_count + col] )) != S_OK) return hr;
278 *val = copy;
279 return S_OK;
282 static HRESULT WINAPI field_put_Value( Field *iface, VARIANT val )
284 struct field *field = impl_from_Field( iface );
285 ULONG row = field->recordset->index, col = field->index, col_count;
286 VARIANT copy;
287 HRESULT hr;
289 TRACE( "%p, %s\n", field, debugstr_variant(&val) );
291 if (field->recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed );
292 if (field->recordset->index < 0) return MAKE_ADO_HRESULT( adErrNoCurrentRecord );
294 col_count = get_column_count( field->recordset );
296 VariantInit( &copy );
297 if ((hr = VariantCopy( &copy, &val )) != S_OK) return hr;
299 field->recordset->data[row * col_count + col] = copy;
300 return S_OK;
303 static HRESULT WINAPI field_get_Precision( Field *iface, unsigned char *precision )
305 FIXME( "%p, %p\n", iface, precision );
306 return E_NOTIMPL;
309 static HRESULT WINAPI field_get_NumericScale( Field *iface, unsigned char *scale )
311 FIXME( "%p, %p\n", iface, scale );
312 return E_NOTIMPL;
315 static HRESULT WINAPI field_AppendChunk( Field *iface, VARIANT data )
317 FIXME( "%p, %s\n", iface, debugstr_variant(&data) );
318 return E_NOTIMPL;
321 static HRESULT WINAPI field_GetChunk( Field *iface, LONG length, VARIANT *var )
323 FIXME( "%p, %ld, %p\n", iface, length, var );
324 return E_NOTIMPL;
327 static HRESULT WINAPI field_get_OriginalValue( Field *iface, VARIANT *val )
329 FIXME( "%p, %p\n", iface, val );
330 return E_NOTIMPL;
333 static HRESULT WINAPI field_get_UnderlyingValue( Field *iface, VARIANT *val )
335 FIXME( "%p, %p\n", iface, val );
336 return E_NOTIMPL;
339 static HRESULT WINAPI field_get_DataFormat( Field *iface, IUnknown **format )
341 FIXME( "%p, %p\n", iface, format );
342 return E_NOTIMPL;
345 static HRESULT WINAPI field_putref_DataFormat( Field *iface, IUnknown *format )
347 FIXME( "%p, %p\n", iface, format );
348 return E_NOTIMPL;
351 static HRESULT WINAPI field_put_Precision( Field *iface, unsigned char precision )
353 FIXME( "%p, %c\n", iface, precision );
354 return E_NOTIMPL;
357 static HRESULT WINAPI field_put_NumericScale( Field *iface, unsigned char scale )
359 FIXME( "%p, %c\n", iface, scale );
360 return E_NOTIMPL;
363 static HRESULT WINAPI field_put_Type( Field *iface, DataTypeEnum type )
365 struct field *field = impl_from_Field( iface );
367 TRACE( "%p, %u\n", field, type );
369 field->type = type;
370 return S_OK;
373 static HRESULT WINAPI field_put_DefinedSize( Field *iface, ADO_LONGPTR size )
375 struct field *field = impl_from_Field( iface );
377 TRACE( "%p, %Id\n", field, size );
379 field->defined_size = size;
380 return S_OK;
383 static HRESULT WINAPI field_put_Attributes( Field *iface, LONG attrs )
385 struct field *field = impl_from_Field( iface );
387 TRACE( "%p, %ld\n", field, attrs );
389 field->attrs = attrs;
390 return S_OK;
393 static HRESULT WINAPI field_get_Status( Field *iface, LONG *status )
395 FIXME( "%p, %p\n", iface, status );
396 return E_NOTIMPL;
399 static const struct FieldVtbl field_vtbl =
401 field_QueryInterface,
402 field_AddRef,
403 field_Release,
404 field_GetTypeInfoCount,
405 field_GetTypeInfo,
406 field_GetIDsOfNames,
407 field_Invoke,
408 field_get_Properties,
409 field_get_ActualSize,
410 field_get_Attributes,
411 field_get_DefinedSize,
412 field_get_Name,
413 field_get_Type,
414 field_get_Value,
415 field_put_Value,
416 field_get_Precision,
417 field_get_NumericScale,
418 field_AppendChunk,
419 field_GetChunk,
420 field_get_OriginalValue,
421 field_get_UnderlyingValue,
422 field_get_DataFormat,
423 field_putref_DataFormat,
424 field_put_Precision,
425 field_put_NumericScale,
426 field_put_Type,
427 field_put_DefinedSize,
428 field_put_Attributes,
429 field_get_Status
432 static inline struct field *field_from_ISupportErrorInfo( ISupportErrorInfo *iface )
434 return CONTAINING_RECORD( iface, struct field, ISupportErrorInfo_iface );
437 static HRESULT WINAPI field_supporterrorinfo_QueryInterface( ISupportErrorInfo *iface, REFIID riid, void **obj )
439 struct field *field = field_from_ISupportErrorInfo( iface );
440 return Field_QueryInterface( &field->Field_iface, riid, obj );
443 static ULONG WINAPI field_supporterrorinfo_AddRef( ISupportErrorInfo *iface )
445 struct field *field = field_from_ISupportErrorInfo( iface );
446 return Field_AddRef( &field->Field_iface );
449 static ULONG WINAPI field_supporterrorinfo_Release( ISupportErrorInfo *iface )
451 struct field *field = field_from_ISupportErrorInfo( iface );
452 return Field_Release( &field->Field_iface );
455 static HRESULT WINAPI field_supporterrorinfo_InterfaceSupportsErrorInfo( ISupportErrorInfo *iface, REFIID riid )
457 struct field *field = field_from_ISupportErrorInfo( iface );
458 FIXME( "%p, %s\n", field, debugstr_guid(riid) );
459 return S_FALSE;
462 static const ISupportErrorInfoVtbl field_supporterrorinfo_vtbl =
464 field_supporterrorinfo_QueryInterface,
465 field_supporterrorinfo_AddRef,
466 field_supporterrorinfo_Release,
467 field_supporterrorinfo_InterfaceSupportsErrorInfo
470 static HRESULT WINAPI field_props_QueryInterface(Properties *iface, REFIID riid, void **ppv)
472 struct field *field = impl_from_Properties( iface );
474 if (IsEqualGUID( riid, &IID_Properties) || IsEqualGUID( riid, &IID_IDispatch ) ||
475 IsEqualGUID( riid, &IID_IUnknown ))
477 *ppv = &field->Properties_iface;
479 else
481 FIXME( "interface %s not implemented\n", debugstr_guid(riid) );
482 return E_NOINTERFACE;
484 Field_AddRef(&field->Field_iface);
485 return S_OK;
488 static ULONG WINAPI field_props_AddRef(Properties *iface)
490 struct field *field = impl_from_Properties( iface );
491 return Field_AddRef(&field->Field_iface);
494 static ULONG WINAPI field_props_Release(Properties *iface)
496 struct field *field = impl_from_Properties( iface );
497 return Field_Release(&field->Field_iface);
500 static HRESULT WINAPI field_props_GetTypeInfoCount(Properties *iface, UINT *count)
502 struct field *field = impl_from_Properties( iface );
503 TRACE( "%p, %p\n", field, count );
504 *count = 1;
505 return S_OK;
508 static HRESULT WINAPI field_props_GetTypeInfo(Properties *iface, UINT index, LCID lcid, ITypeInfo **info)
510 struct field *field = impl_from_Properties( iface );
511 TRACE( "%p, %u, %lu, %p\n", field, index, lcid, info );
512 return get_typeinfo(Properties_tid, info);
515 static HRESULT WINAPI field_props_GetIDsOfNames(Properties *iface, REFIID riid, LPOLESTR *names, UINT count,
516 LCID lcid, DISPID *dispid )
518 struct field *field = impl_from_Properties( iface );
519 HRESULT hr;
520 ITypeInfo *typeinfo;
522 TRACE( "%p, %s, %p, %u, %lu, %p\n", field, debugstr_guid(riid), names, count, lcid, dispid );
524 hr = get_typeinfo(Properties_tid, &typeinfo);
525 if(SUCCEEDED(hr))
527 hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, dispid);
528 ITypeInfo_Release(typeinfo);
531 return hr;
534 static HRESULT WINAPI field_props_Invoke(Properties *iface, DISPID member, REFIID riid, LCID lcid, WORD flags,
535 DISPPARAMS *params, VARIANT *result, EXCEPINFO *excep_info, UINT *arg_err )
537 struct field *field = impl_from_Properties( iface );
538 HRESULT hr;
539 ITypeInfo *typeinfo;
541 TRACE( "%p, %ld, %s, %ld, %d, %p, %p, %p, %p\n", field, member, debugstr_guid(riid), lcid, flags, params,
542 result, excep_info, arg_err );
544 hr = get_typeinfo(Properties_tid, &typeinfo);
545 if(SUCCEEDED(hr))
547 hr = ITypeInfo_Invoke(typeinfo, &field->Field_iface, member, flags, params,
548 result, excep_info, arg_err);
549 ITypeInfo_Release(typeinfo);
552 return hr;
555 static HRESULT WINAPI field_props_get_Count(Properties *iface, LONG *count)
557 struct field *field = impl_from_Properties( iface );
558 FIXME( "%p, %p\n", field, count);
559 *count = 0;
560 return S_OK;
563 static HRESULT WINAPI field_props__NewEnum(Properties *iface, IUnknown **object)
565 struct field *field = impl_from_Properties( iface );
566 FIXME( "%p, %p\n", field, object);
567 return E_NOTIMPL;
570 static HRESULT WINAPI field_props_Refresh(Properties *iface)
572 struct field *field = impl_from_Properties( iface );
573 FIXME( "%p\n", field);
574 return E_NOTIMPL;
578 struct field_property
580 Property Property_iface;
581 LONG refs;
582 VARIANT *value;
585 static inline struct field_property *impl_from_Property( Property *iface )
587 return CONTAINING_RECORD( iface, struct field_property, Property_iface );
590 static ULONG WINAPI field_property_AddRef(Property *iface)
592 struct field_property *property = impl_from_Property( iface );
593 LONG refs = InterlockedIncrement( &property->refs );
594 TRACE( "%p new refcount %ld\n", property, refs );
595 return refs;
598 static ULONG WINAPI field_property_Release(Property *iface)
600 struct field_property *property = impl_from_Property( iface );
601 LONG refs = InterlockedDecrement( &property->refs );
602 TRACE( "%p new refcount %ld\n", property, refs );
603 if (!refs)
605 free( property );
607 return refs;
610 static HRESULT WINAPI field_property_QueryInterface(Property *iface, REFIID riid, void **obj)
612 struct field_property *property = impl_from_Property( iface );
613 TRACE( "%p, %s, %p\n", property, debugstr_guid(riid), obj );
615 if (IsEqualGUID( riid, &IID_Property )
616 || IsEqualGUID( riid, &IID_IDispatch )
617 || IsEqualGUID( riid, &IID_IUnknown ))
619 *obj = iface;
621 else
623 FIXME( "interface %s not implemented\n", debugstr_guid(riid) );
624 return E_NOINTERFACE;
626 field_property_AddRef( iface );
627 return S_OK;
630 static HRESULT WINAPI field_property_GetTypeInfoCount(Property *iface, UINT *count)
632 struct field_property *property = impl_from_Property( iface );
633 TRACE( "%p, %p\n", property, count );
634 *count = 1;
635 return S_OK;
638 static HRESULT WINAPI field_property_GetTypeInfo(Property *iface, UINT index, LCID lcid, ITypeInfo **info)
640 struct field_property *property = impl_from_Property( iface );
641 TRACE( "%p, %u, %lu, %p\n", property, index, lcid, info );
642 return get_typeinfo(Property_tid, info);
645 static HRESULT WINAPI field_property_GetIDsOfNames(Property *iface, REFIID riid, LPOLESTR *names, UINT count,
646 LCID lcid, DISPID *dispid)
648 struct field_property *property = impl_from_Property( iface );
649 HRESULT hr;
650 ITypeInfo *typeinfo;
652 TRACE( "%p, %s, %p, %u, %lu, %p\n", property, debugstr_guid(riid), names, count, lcid, dispid );
654 hr = get_typeinfo(Property_tid, &typeinfo);
655 if(SUCCEEDED(hr))
657 hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, dispid);
658 ITypeInfo_Release(typeinfo);
661 return hr;
664 static HRESULT WINAPI field_property_Invoke(Property *iface, DISPID member, REFIID riid, LCID lcid,
665 WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *excep_info, UINT *arg_err)
667 struct field_property *property = impl_from_Property( iface );
668 HRESULT hr;
669 ITypeInfo *typeinfo;
671 TRACE( "%p, %ld, %s, %ld, %d, %p, %p, %p, %p\n", property, member, debugstr_guid(riid), lcid, flags, params,
672 result, excep_info, arg_err );
674 hr = get_typeinfo(Property_tid, &typeinfo);
675 if(SUCCEEDED(hr))
677 hr = ITypeInfo_Invoke(typeinfo, &property->Property_iface, member, flags, params,
678 result, excep_info, arg_err);
679 ITypeInfo_Release(typeinfo);
682 return hr;
685 static HRESULT WINAPI field_property_get_Value(Property *iface, VARIANT *val)
687 struct field_property *property = impl_from_Property( iface );
688 TRACE("%p, %p\n", property, val);
689 VariantCopy(val, property->value);
690 return S_OK;
693 static HRESULT WINAPI field_property_put_Value(Property *iface, VARIANT val)
695 struct field_property *property = impl_from_Property( iface );
696 TRACE("%p, %s\n", property, debugstr_variant(&val));
697 VariantCopy(property->value, &val);
698 return S_OK;
701 static HRESULT WINAPI field_property_get_Name(Property *iface, BSTR *str)
703 FIXME("\n");
704 return E_NOTIMPL;
707 static HRESULT WINAPI field_property_get_Type(Property *iface, DataTypeEnum *type)
709 FIXME("\n");
710 return E_NOTIMPL;
713 static HRESULT WINAPI field_property_get_Attributes(Property *iface, LONG *attributes)
715 FIXME("\n");
716 return E_NOTIMPL;
719 static HRESULT WINAPI field_property_put_Attributes(Property *iface, LONG attributes)
721 FIXME("\n");
722 return E_NOTIMPL;
725 static struct PropertyVtbl field_property_vtbl =
727 field_property_QueryInterface,
728 field_property_AddRef,
729 field_property_Release,
730 field_property_GetTypeInfoCount,
731 field_property_GetTypeInfo,
732 field_property_GetIDsOfNames,
733 field_property_Invoke,
734 field_property_get_Value,
735 field_property_put_Value,
736 field_property_get_Name,
737 field_property_get_Type,
738 field_property_get_Attributes,
739 field_property_put_Attributes
742 static HRESULT WINAPI field_props_get_Item(Properties *iface, VARIANT index, Property **object)
744 struct field *field = impl_from_Properties( iface );
745 struct field_property *prop;
747 TRACE( "%p, %s, %p\n", field, debugstr_variant(&index), object);
749 if (V_VT(&index) == VT_BSTR)
751 if(!wcscmp(L"Optimize", V_BSTR(&index)))
753 prop = malloc (sizeof(struct field_property));
754 prop->Property_iface.lpVtbl = &field_property_vtbl;
755 prop->value = &field->optimize;
757 *object = &prop->Property_iface;
758 return S_OK;
762 FIXME("Unsupported property %s\n", debugstr_variant(&index));
764 return MAKE_ADO_HRESULT(adErrItemNotFound);
767 static struct PropertiesVtbl field_properties_vtbl =
769 field_props_QueryInterface,
770 field_props_AddRef,
771 field_props_Release,
772 field_props_GetTypeInfoCount,
773 field_props_GetTypeInfo,
774 field_props_GetIDsOfNames,
775 field_props_Invoke,
776 field_props_get_Count,
777 field_props__NewEnum,
778 field_props_Refresh,
779 field_props_get_Item
782 static HRESULT Field_create( const WCHAR *name, LONG index, struct recordset *recordset, Field **obj )
784 struct field *field;
786 if (!(field = calloc( 1, sizeof(*field) ))) return E_OUTOFMEMORY;
787 field->Field_iface.lpVtbl = &field_vtbl;
788 field->ISupportErrorInfo_iface.lpVtbl = &field_supporterrorinfo_vtbl;
789 field->Properties_iface.lpVtbl = &field_properties_vtbl;
790 field->refs = 1;
791 if (!(field->name = wcsdup( name )))
793 free( field );
794 return E_OUTOFMEMORY;
796 field->index = index;
797 field->recordset = recordset;
799 *obj = &field->Field_iface;
800 TRACE( "returning iface %p\n", *obj );
801 return S_OK;
804 static inline struct fields *impl_from_Fields( Fields *iface )
806 return CONTAINING_RECORD( iface, struct fields, Fields_iface );
809 static ULONG WINAPI fields_AddRef( Fields *iface )
811 struct fields *fields = impl_from_Fields( iface );
812 LONG refs = InterlockedIncrement( &fields->refs );
813 TRACE( "%p new refcount %ld\n", fields, refs );
814 return refs;
817 static ULONG WINAPI fields_Release( Fields *iface )
819 struct fields *fields = impl_from_Fields( iface );
820 LONG refs = InterlockedDecrement( &fields->refs );
821 TRACE( "%p new refcount %ld\n", fields, refs );
822 if (!refs)
824 if (fields->recordset) _Recordset_Release( &fields->recordset->Recordset_iface );
825 fields->recordset = NULL;
826 WARN( "not destroying %p\n", fields );
827 return InterlockedIncrement( &fields->refs );
829 return refs;
832 static HRESULT WINAPI fields_QueryInterface( Fields *iface, REFIID riid, void **obj )
834 struct fields *fields = impl_from_Fields( iface );
835 TRACE( "%p, %s, %p\n", iface, debugstr_guid(riid), obj );
837 if (IsEqualGUID( riid, &IID_Fields ) || IsEqualGUID( riid, &IID_IDispatch ) ||
838 IsEqualGUID( riid, &IID_IUnknown ))
840 *obj = iface;
842 else if (IsEqualGUID( riid, &IID_ISupportErrorInfo ))
844 *obj = &fields->ISupportErrorInfo_iface;
846 else
848 FIXME( "interface %s not implemented\n", debugstr_guid(riid) );
849 return E_NOINTERFACE;
851 fields_AddRef( iface );
852 return S_OK;
855 static HRESULT WINAPI fields_GetTypeInfoCount( Fields *iface, UINT *count )
857 struct fields *fields = impl_from_Fields( iface );
858 TRACE( "%p, %p\n", fields, count );
859 *count = 1;
860 return S_OK;
863 static HRESULT WINAPI fields_GetTypeInfo( Fields *iface, UINT index, LCID lcid, ITypeInfo **info )
865 struct fields *fields = impl_from_Fields( iface );
866 TRACE( "%p, %u, %lu, %p\n", fields, index, lcid, info );
867 return get_typeinfo(Fields_tid, info);
870 static HRESULT WINAPI fields_GetIDsOfNames( Fields *iface, REFIID riid, LPOLESTR *names, UINT count,
871 LCID lcid, DISPID *dispid )
873 struct fields *fields = impl_from_Fields( iface );
874 HRESULT hr;
875 ITypeInfo *typeinfo;
877 TRACE( "%p, %s, %p, %u, %lu, %p\n", fields, debugstr_guid(riid), names, count, lcid, dispid );
879 hr = get_typeinfo(Fields_tid, &typeinfo);
880 if(SUCCEEDED(hr))
882 hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, dispid);
883 ITypeInfo_Release(typeinfo);
886 return hr;
889 static HRESULT WINAPI fields_Invoke( Fields *iface, DISPID member, REFIID riid, LCID lcid, WORD flags,
890 DISPPARAMS *params, VARIANT *result, EXCEPINFO *excep_info, UINT *arg_err )
892 struct fields *fields = impl_from_Fields( iface );
893 HRESULT hr;
894 ITypeInfo *typeinfo;
896 TRACE( "%p, %ld, %s, %ld, %d, %p, %p, %p, %p\n", fields, member, debugstr_guid(riid), lcid, flags, params,
897 result, excep_info, arg_err );
899 hr = get_typeinfo(Fields_tid, &typeinfo);
900 if(SUCCEEDED(hr))
902 hr = ITypeInfo_Invoke(typeinfo, &fields->Fields_iface, member, flags, params,
903 result, excep_info, arg_err);
904 ITypeInfo_Release(typeinfo);
907 return hr;
910 static HRESULT WINAPI fields_get_Count( Fields *iface, LONG *count )
912 struct fields *fields = impl_from_Fields( iface );
914 TRACE( "%p, %p\n", fields, count );
916 *count = fields->count;
917 return S_OK;
920 static HRESULT WINAPI fields__NewEnum( Fields *iface, IUnknown **obj )
922 FIXME( "%p, %p\n", iface, obj );
923 return E_NOTIMPL;
926 static HRESULT WINAPI fields_Refresh( Fields *iface )
928 FIXME( "%p\n", iface );
929 return E_NOTIMPL;
932 static HRESULT map_index( struct fields *fields, VARIANT *index, ULONG *ret )
934 ULONG i;
936 if (V_VT( index ) != VT_BSTR)
938 VARIANT idx;
940 VariantInit(&idx);
941 if (VariantChangeType(&idx, index, 0, VT_UI4) == S_OK)
943 i = V_UI4 ( &idx );
944 if (i < fields->count)
946 *ret = i;
947 return S_OK;
951 return MAKE_ADO_HRESULT(adErrItemNotFound);
954 for (i = 0; i < fields->count; i++)
956 BSTR name;
957 BOOL match;
958 HRESULT hr;
960 if ((hr = Field_get_Name( fields->field[i], &name )) != S_OK) return hr;
961 match = !wcsicmp( V_BSTR( index ), name );
962 SysFreeString( name );
963 if (match)
965 *ret = i;
966 return S_OK;
970 return MAKE_ADO_HRESULT(adErrItemNotFound);
973 static inline WCHAR *heap_strdupAtoW(const char *str)
975 LPWSTR ret = NULL;
977 if(str) {
978 DWORD len;
980 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
981 ret = malloc(len*sizeof(WCHAR));
982 if(ret)
983 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
986 return ret;
989 static HRESULT WINAPI fields_get_Item( Fields *iface, VARIANT index, Field **obj )
991 struct fields *fields = impl_from_Fields( iface );
992 HRESULT hr;
993 ULONG i = 0;
995 TRACE( "%p, %s, %p\n", fields, debugstr_variant(&index), obj );
997 if ((hr = map_index( fields, &index, &i )) != S_OK) return hr;
999 Field_AddRef( fields->field[i] );
1000 *obj = fields->field[i];
1001 return S_OK;
1004 static BOOL resize_fields( struct fields *fields, ULONG count )
1006 if (count > fields->allocated)
1008 Field **tmp;
1009 ULONG new_size = max( count, fields->allocated * 2 );
1010 if (!(tmp = realloc( fields->field, new_size * sizeof(*tmp) ))) return FALSE;
1011 fields->field = tmp;
1012 fields->allocated = new_size;
1015 fields->count = count;
1016 return TRUE;
1019 static HRESULT append_field( struct fields *fields, BSTR name, DataTypeEnum type, LONG size, FieldAttributeEnum attr,
1020 VARIANT *value )
1022 Field *field;
1023 HRESULT hr;
1025 if ((hr = Field_create( name, fields->count, fields->recordset, &field )) != S_OK) return hr;
1026 Field_put_Type( field, type );
1027 Field_put_DefinedSize( field, size );
1028 if (attr != adFldUnspecified) Field_put_Attributes( field, attr );
1029 if (value) FIXME( "ignoring value %s\n", debugstr_variant(value) );
1031 if (!(resize_fields( fields, fields->count + 1 )))
1033 Field_Release( field );
1034 return E_OUTOFMEMORY;
1037 fields->field[fields->count - 1] = field;
1038 return S_OK;
1041 static HRESULT WINAPI fields__Append( Fields *iface, BSTR name, DataTypeEnum type, ADO_LONGPTR size, FieldAttributeEnum attr )
1043 struct fields *fields = impl_from_Fields( iface );
1045 TRACE( "%p, %s, %u, %Id, %d\n", fields, debugstr_w(name), type, size, attr );
1047 return append_field( fields, name, type, size, attr, NULL );
1050 static HRESULT WINAPI fields_Delete( Fields *iface, VARIANT index )
1052 FIXME( "%p, %s\n", iface, debugstr_variant(&index) );
1053 return E_NOTIMPL;
1056 static HRESULT WINAPI fields_Append( Fields *iface, BSTR name, DataTypeEnum type, ADO_LONGPTR size, FieldAttributeEnum attr,
1057 VARIANT value )
1059 struct fields *fields = impl_from_Fields( iface );
1061 TRACE( "%p, %s, %u, %Id, %d, %s\n", fields, debugstr_w(name), type, size, attr, debugstr_variant(&value) );
1063 return append_field( fields, name, type, size, attr, &value );
1066 static HRESULT WINAPI fields_Update( Fields *iface )
1068 FIXME( "%p\n", iface );
1069 return E_NOTIMPL;
1072 static HRESULT WINAPI fields_Resync( Fields *iface, ResyncEnum resync_values )
1074 FIXME( "%p, %u\n", iface, resync_values );
1075 return E_NOTIMPL;
1078 static HRESULT WINAPI fields_CancelUpdate( Fields *iface )
1080 FIXME( "%p\n", iface );
1081 return E_NOTIMPL;
1084 static const struct FieldsVtbl fields_vtbl =
1086 fields_QueryInterface,
1087 fields_AddRef,
1088 fields_Release,
1089 fields_GetTypeInfoCount,
1090 fields_GetTypeInfo,
1091 fields_GetIDsOfNames,
1092 fields_Invoke,
1093 fields_get_Count,
1094 fields__NewEnum,
1095 fields_Refresh,
1096 fields_get_Item,
1097 fields__Append,
1098 fields_Delete,
1099 fields_Append,
1100 fields_Update,
1101 fields_Resync,
1102 fields_CancelUpdate
1105 static inline struct fields *fields_from_ISupportErrorInfo( ISupportErrorInfo *iface )
1107 return CONTAINING_RECORD( iface, struct fields, ISupportErrorInfo_iface );
1110 static HRESULT WINAPI fields_supporterrorinfo_QueryInterface( ISupportErrorInfo *iface, REFIID riid, void **obj )
1112 struct fields *fields = fields_from_ISupportErrorInfo( iface );
1113 return Fields_QueryInterface( &fields->Fields_iface, riid, obj );
1116 static ULONG WINAPI fields_supporterrorinfo_AddRef( ISupportErrorInfo *iface )
1118 struct fields *fields = fields_from_ISupportErrorInfo( iface );
1119 return Fields_AddRef( &fields->Fields_iface );
1122 static ULONG WINAPI fields_supporterrorinfo_Release( ISupportErrorInfo *iface )
1124 struct fields *fields = fields_from_ISupportErrorInfo( iface );
1125 return Fields_Release( &fields->Fields_iface );
1128 static HRESULT WINAPI fields_supporterrorinfo_InterfaceSupportsErrorInfo( ISupportErrorInfo *iface, REFIID riid )
1130 struct fields *fields = fields_from_ISupportErrorInfo( iface );
1131 FIXME( "%p, %s\n", fields, debugstr_guid(riid) );
1132 return S_FALSE;
1135 static const ISupportErrorInfoVtbl fields_supporterrorinfo_vtbl =
1137 fields_supporterrorinfo_QueryInterface,
1138 fields_supporterrorinfo_AddRef,
1139 fields_supporterrorinfo_Release,
1140 fields_supporterrorinfo_InterfaceSupportsErrorInfo
1143 static void map_rowset_fields(struct recordset *recordset, struct fields *fields)
1145 HRESULT hr;
1146 IColumnsInfo *columninfo;
1147 DBORDINAL columns, i;
1148 DBCOLUMNINFO *colinfo;
1149 OLECHAR *stringsbuffer;
1151 /* Not Finding the interface or GetColumnInfo failing just causes 0 Fields to be returned */
1152 hr = IRowset_QueryInterface(recordset->row_set, &IID_IColumnsInfo, (void**)&columninfo);
1153 if (FAILED(hr))
1154 return;
1156 hr = IColumnsInfo_GetColumnInfo(columninfo, &columns, &colinfo, &stringsbuffer);
1157 if (SUCCEEDED(hr))
1159 for (i=0; i < columns; i++)
1161 TRACE("Adding Column %Iu, pwszName: %s, pTypeInfo %p, iOrdinal %Iu, dwFlags 0x%08lx, "
1162 "ulColumnSize %Iu, wType %d, bPrecision %d, bScale %d\n",
1163 i, debugstr_w(colinfo[i].pwszName), colinfo[i].pTypeInfo, colinfo[i].iOrdinal,
1164 colinfo[i].dwFlags, colinfo[i].ulColumnSize, colinfo[i].wType,
1165 colinfo[i].bPrecision, colinfo[i].bScale);
1167 hr = append_field(fields, colinfo[i].pwszName, colinfo[i].wType, colinfo[i].ulColumnSize,
1168 colinfo[i].dwFlags, NULL);
1169 if (FAILED(hr))
1171 ERR("Failed to add Field name - 0x%08lx\n", hr);
1172 return;
1176 CoTaskMemFree(colinfo);
1177 CoTaskMemFree(stringsbuffer);
1180 IColumnsInfo_Release(columninfo);
1183 static HRESULT fields_create( struct recordset *recordset, struct fields **ret )
1185 struct fields *fields;
1187 if (!(fields = calloc( 1, sizeof(*fields) ))) return E_OUTOFMEMORY;
1188 fields->Fields_iface.lpVtbl = &fields_vtbl;
1189 fields->ISupportErrorInfo_iface.lpVtbl = &fields_supporterrorinfo_vtbl;
1190 fields->refs = 1;
1191 fields->recordset = recordset;
1192 _Recordset_AddRef( &fields->recordset->Recordset_iface );
1194 if ( recordset->row_set )
1195 map_rowset_fields(recordset, fields);
1197 *ret = fields;
1198 TRACE( "returning %p\n", *ret );
1199 return S_OK;
1202 static inline struct recordset *impl_from_Recordset( _Recordset *iface )
1204 return CONTAINING_RECORD( iface, struct recordset, Recordset_iface );
1207 static inline struct recordset *impl_from_ADORecordsetConstruction( ADORecordsetConstruction *iface )
1209 return CONTAINING_RECORD( iface, struct recordset, ADORecordsetConstruction_iface );
1212 static ULONG WINAPI recordset_AddRef( _Recordset *iface )
1214 struct recordset *recordset = impl_from_Recordset( iface );
1215 LONG refs = InterlockedIncrement( &recordset->refs );
1216 TRACE( "%p new refcount %ld\n", recordset, refs );
1217 return refs;
1220 static void close_recordset( struct recordset *recordset )
1222 ULONG row, col, col_count;
1223 ULONG i;
1224 IAccessor *accessor;
1226 if (recordset->haccessors)
1227 IRowset_QueryInterface(recordset->row_set, &IID_IAccessor, (void**)&accessor);
1229 if ( recordset->row_set ) IRowset_Release( recordset->row_set );
1230 recordset->row_set = NULL;
1232 VariantClear( &recordset->filter );
1234 if (!recordset->fields) return;
1235 col_count = get_column_count( recordset );
1237 free(recordset->columntypes);
1239 for (i = 0; i < col_count; i++)
1241 struct field *field = impl_from_Field( recordset->fields->field[i] );
1242 field->recordset = NULL;
1243 Field_Release(&field->Field_iface);
1245 if (recordset->haccessors)
1246 IAccessor_ReleaseAccessor(accessor, recordset->haccessors[i], NULL);
1249 if (recordset->haccessors)
1251 IAccessor_Release(accessor);
1252 free(recordset->haccessors);
1253 recordset->haccessors = NULL;
1255 recordset->fields->count = 0;
1256 Fields_Release( &recordset->fields->Fields_iface );
1257 recordset->fields = NULL;
1259 for (row = 0; row < recordset->count; row++)
1260 for (col = 0; col < col_count; col++) VariantClear( &recordset->data[row * col_count + col] );
1262 recordset->count = recordset->allocated = recordset->index = 0;
1263 free( recordset->data );
1264 recordset->data = NULL;
1267 static ULONG WINAPI recordset_Release( _Recordset *iface )
1269 struct recordset *recordset = impl_from_Recordset( iface );
1270 LONG refs = InterlockedDecrement( &recordset->refs );
1271 TRACE( "%p new refcount %ld\n", recordset, refs );
1272 if (!refs)
1274 TRACE( "destroying %p\n", recordset );
1275 close_recordset( recordset );
1276 free( recordset );
1278 return refs;
1281 static HRESULT WINAPI recordset_QueryInterface( _Recordset *iface, REFIID riid, void **obj )
1283 struct recordset *recordset = impl_from_Recordset( iface );
1284 TRACE( "%p, %s, %p\n", iface, debugstr_guid(riid), obj );
1286 *obj = NULL;
1288 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch) ||
1289 IsEqualIID(riid, &IID__ADO) || IsEqualIID(riid, &IID_Recordset15) ||
1290 IsEqualIID(riid, &IID_Recordset20) || IsEqualIID(riid, &IID_Recordset21) ||
1291 IsEqualIID(riid, &IID__Recordset))
1293 *obj = iface;
1295 else if (IsEqualGUID( riid, &IID_ISupportErrorInfo ))
1297 *obj = &recordset->ISupportErrorInfo_iface;
1299 else if (IsEqualGUID( riid, &IID_ADORecordsetConstruction ))
1301 *obj = &recordset->ADORecordsetConstruction_iface;
1303 else if (IsEqualGUID( riid, &IID_IRunnableObject ))
1305 TRACE("IID_IRunnableObject not supported returning NULL\n");
1306 return E_NOINTERFACE;
1308 else
1310 FIXME( "interface %s not implemented\n", debugstr_guid(riid) );
1311 return E_NOINTERFACE;
1313 recordset_AddRef( iface );
1314 return S_OK;
1317 static HRESULT WINAPI recordset_GetTypeInfoCount( _Recordset *iface, UINT *count )
1319 struct recordset *recordset = impl_from_Recordset( iface );
1320 TRACE( "%p, %p\n", recordset, count );
1321 *count = 1;
1322 return S_OK;
1325 static HRESULT WINAPI recordset_GetTypeInfo( _Recordset *iface, UINT index, LCID lcid, ITypeInfo **info )
1327 struct recordset *recordset = impl_from_Recordset( iface );
1328 TRACE( "%p, %u, %lu, %p\n", recordset, index, lcid, info );
1329 return get_typeinfo(Recordset_tid, info);
1332 static HRESULT WINAPI recordset_GetIDsOfNames( _Recordset *iface, REFIID riid, LPOLESTR *names, UINT count,
1333 LCID lcid, DISPID *dispid )
1335 struct recordset *recordset = impl_from_Recordset( iface );
1336 HRESULT hr;
1337 ITypeInfo *typeinfo;
1339 TRACE( "%p, %s, %p, %u, %lu, %p\n", recordset, debugstr_guid(riid), names, count, lcid, dispid );
1341 hr = get_typeinfo(Recordset_tid, &typeinfo);
1342 if(SUCCEEDED(hr))
1344 hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, dispid);
1345 ITypeInfo_Release(typeinfo);
1348 return hr;
1351 static HRESULT WINAPI recordset_Invoke( _Recordset *iface, DISPID member, REFIID riid, LCID lcid, WORD flags,
1352 DISPPARAMS *params, VARIANT *result, EXCEPINFO *excep_info, UINT *arg_err )
1354 struct recordset *recordset = impl_from_Recordset( iface );
1355 HRESULT hr;
1356 ITypeInfo *typeinfo;
1358 TRACE( "%p, %ld, %s, %ld, %d, %p, %p, %p, %p\n", recordset, member, debugstr_guid(riid), lcid, flags, params,
1359 result, excep_info, arg_err );
1361 hr = get_typeinfo(Recordset_tid, &typeinfo);
1362 if(SUCCEEDED(hr))
1364 hr = ITypeInfo_Invoke(typeinfo, &recordset->Recordset_iface, member, flags, params,
1365 result, excep_info, arg_err);
1366 ITypeInfo_Release(typeinfo);
1369 return hr;
1372 static HRESULT WINAPI recordset_get_Properties( _Recordset *iface, Properties **obj )
1374 FIXME( "%p, %p\n", iface, obj );
1375 return E_NOTIMPL;
1378 static HRESULT WINAPI recordset_get_AbsolutePosition( _Recordset *iface, PositionEnum_Param *pos )
1380 FIXME( "%p, %p\n", iface, pos );
1381 return E_NOTIMPL;
1384 static HRESULT WINAPI recordset_put_AbsolutePosition( _Recordset *iface, PositionEnum_Param pos )
1386 FIXME( "%p, %Id\n", iface, pos );
1387 return E_NOTIMPL;
1390 static HRESULT WINAPI recordset_putref_ActiveConnection( _Recordset *iface, IDispatch *connection )
1392 FIXME( "%p, %p\n", iface, connection );
1393 return E_NOTIMPL;
1396 static HRESULT WINAPI recordset_put_ActiveConnection( _Recordset *iface, VARIANT connection )
1398 FIXME( "%p, %s\n", iface, debugstr_variant(&connection) );
1399 return E_NOTIMPL;
1402 static HRESULT WINAPI recordset_get_ActiveConnection( _Recordset *iface, VARIANT *connection )
1404 FIXME( "%p, %p\n", iface, connection );
1405 return E_NOTIMPL;
1408 static HRESULT WINAPI recordset_get_BOF( _Recordset *iface, VARIANT_BOOL *bof )
1410 struct recordset *recordset = impl_from_Recordset( iface );
1412 TRACE( "%p, %p\n", recordset, bof );
1414 *bof = (recordset->index < 0) ? VARIANT_TRUE : VARIANT_FALSE;
1415 return S_OK;
1418 static HRESULT WINAPI recordset_get_Bookmark( _Recordset *iface, VARIANT *bookmark )
1420 struct recordset *recordset = impl_from_Recordset( iface );
1421 TRACE( "%p, %p\n", iface, bookmark );
1423 if (recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed );
1424 if (recordset->index < 0) return MAKE_ADO_HRESULT( adErrNoCurrentRecord );
1426 V_VT(bookmark) = VT_I4;
1427 V_I4(bookmark) = recordset->index;
1428 return S_OK;
1431 static HRESULT WINAPI recordset_put_Bookmark( _Recordset *iface, VARIANT bookmark )
1433 struct recordset *recordset = impl_from_Recordset( iface );
1434 TRACE( "%p, %s\n", iface, debugstr_variant(&bookmark) );
1436 if (recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed );
1438 if (V_VT(&bookmark) != VT_I4) return MAKE_ADO_HRESULT( adErrInvalidArgument );
1440 recordset->index = V_I4(&bookmark);
1441 return S_OK;
1444 static HRESULT WINAPI recordset_get_CacheSize( _Recordset *iface, LONG *size )
1446 FIXME( "%p, %p\n", iface, size );
1447 return E_NOTIMPL;
1450 static HRESULT WINAPI recordset_put_CacheSize( _Recordset *iface, LONG size )
1452 FIXME( "%p, %ld\n", iface, size );
1453 return E_NOTIMPL;
1456 static HRESULT WINAPI recordset_get_CursorType( _Recordset *iface, CursorTypeEnum *cursor_type )
1458 struct recordset *recordset = impl_from_Recordset( iface );
1460 TRACE( "%p, %p\n", iface, cursor_type );
1462 *cursor_type = recordset->cursor_type;
1463 return S_OK;
1466 static HRESULT WINAPI recordset_put_CursorType( _Recordset *iface, CursorTypeEnum cursor_type )
1468 struct recordset *recordset = impl_from_Recordset( iface );
1470 TRACE( "%p, %d\n", iface, cursor_type );
1472 recordset->cursor_type = cursor_type;
1473 return S_OK;
1476 static HRESULT WINAPI recordset_get_EOF( _Recordset *iface, VARIANT_BOOL *eof )
1478 struct recordset *recordset = impl_from_Recordset( iface );
1480 TRACE( "%p, %p\n", recordset, eof );
1482 *eof = (!recordset->count || recordset->index >= recordset->count) ? VARIANT_TRUE : VARIANT_FALSE;
1483 return S_OK;
1486 static HRESULT WINAPI recordset_get_Fields( _Recordset *iface, Fields **obj )
1488 struct recordset *recordset = impl_from_Recordset( iface );
1489 HRESULT hr;
1491 TRACE( "%p, %p\n", recordset, obj );
1493 if (recordset->fields)
1495 /* yes, this adds a reference to the recordset instead of the fields object */
1496 _Recordset_AddRef( &recordset->Recordset_iface );
1497 recordset->fields->recordset = recordset;
1498 *obj = &recordset->fields->Fields_iface;
1499 return S_OK;
1502 if ((hr = fields_create( recordset, &recordset->fields )) != S_OK) return hr;
1504 *obj = &recordset->fields->Fields_iface;
1505 return S_OK;
1508 static HRESULT WINAPI recordset_get_LockType( _Recordset *iface, LockTypeEnum *lock_type )
1510 FIXME( "%p, %p\n", iface, lock_type );
1511 return E_NOTIMPL;
1514 static HRESULT WINAPI recordset_put_LockType( _Recordset *iface, LockTypeEnum lock_type )
1516 FIXME( "%p, %d\n", iface, lock_type );
1517 return E_NOTIMPL;
1520 static HRESULT WINAPI recordset_get_MaxRecords( _Recordset *iface, ADO_LONGPTR *max_records )
1522 FIXME( "%p, %p\n", iface, max_records );
1523 return E_NOTIMPL;
1526 static HRESULT WINAPI recordset_put_MaxRecords( _Recordset *iface, ADO_LONGPTR max_records )
1528 FIXME( "%p, %Id\n", iface, max_records );
1529 return E_NOTIMPL;
1532 static HRESULT WINAPI recordset_get_RecordCount( _Recordset *iface, ADO_LONGPTR *count )
1534 struct recordset *recordset = impl_from_Recordset( iface );
1536 TRACE( "%p, %p\n", recordset, count );
1538 *count = recordset->count;
1539 return S_OK;
1542 static HRESULT WINAPI recordset_putref_Source( _Recordset *iface, IDispatch *source )
1544 FIXME( "%p, %p\n", iface, source );
1545 return E_NOTIMPL;
1548 static HRESULT WINAPI recordset_put_Source( _Recordset *iface, BSTR source )
1550 FIXME( "%p, %s\n", iface, debugstr_w(source) );
1551 return E_NOTIMPL;
1554 static HRESULT WINAPI recordset_get_Source( _Recordset *iface, VARIANT *source )
1556 FIXME( "%p, %p\n", iface, source );
1557 return E_NOTIMPL;
1560 static BOOL resize_recordset( struct recordset *recordset, ULONG row_count )
1562 ULONG row_size = get_column_count( recordset ) * sizeof(*recordset->data);
1564 if (row_count > recordset->allocated)
1566 VARIANT *tmp;
1567 ULONG count = max( row_count, recordset->allocated * 2 );
1568 if (!(tmp = realloc( recordset->data, count * row_size ))) return FALSE;
1569 memset( tmp + recordset->allocated, 0, (count - recordset->allocated) * row_size );
1570 recordset->data = tmp;
1571 recordset->allocated = count;
1574 recordset->count = row_count;
1575 return TRUE;
1578 static HRESULT WINAPI recordset_AddNew( _Recordset *iface, VARIANT field_list, VARIANT values )
1580 struct recordset *recordset = impl_from_Recordset( iface );
1582 TRACE( "%p, %s, %s\n", recordset, debugstr_variant(&field_list), debugstr_variant(&values) );
1583 FIXME( "ignoring field list and values\n" );
1585 if (recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed );
1587 if (!resize_recordset( recordset, recordset->count + 1 )) return E_OUTOFMEMORY;
1588 recordset->index++;
1589 return S_OK;
1592 static HRESULT WINAPI recordset_CancelUpdate( _Recordset *iface )
1594 FIXME( "%p\n", iface );
1595 return E_NOTIMPL;
1598 static HRESULT WINAPI recordset_Close( _Recordset *iface )
1600 struct recordset *recordset = impl_from_Recordset( iface );
1602 TRACE( "%p\n", recordset );
1604 if (recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed );
1606 close_recordset( recordset );
1607 recordset->state = adStateClosed;
1608 return S_OK;
1611 static HRESULT WINAPI recordset_Delete( _Recordset *iface, AffectEnum affect_records )
1613 FIXME( "%p, %u\n", iface, affect_records );
1614 return E_NOTIMPL;
1617 static HRESULT WINAPI recordset_GetRows( _Recordset *iface, LONG rows, VARIANT start, VARIANT fields, VARIANT *var )
1619 FIXME( "%p, %ld, %s, %s, %p\n", iface, rows, debugstr_variant(&start), debugstr_variant(&fields), var );
1620 return E_NOTIMPL;
1623 static HRESULT WINAPI recordset_Move( _Recordset *iface, ADO_LONGPTR num_records, VARIANT start )
1625 FIXME( "%p, %Id, %s\n", iface, num_records, debugstr_variant(&start) );
1626 return E_NOTIMPL;
1629 static HRESULT WINAPI recordset_MoveNext( _Recordset *iface )
1631 struct recordset *recordset = impl_from_Recordset( iface );
1633 TRACE( "%p\n", recordset );
1635 if (recordset->index < recordset->count) recordset->index++;
1636 return S_OK;
1639 static HRESULT WINAPI recordset_MovePrevious( _Recordset *iface )
1641 struct recordset *recordset = impl_from_Recordset( iface );
1643 TRACE( "%p\n", recordset );
1645 if (recordset->index >= 0) recordset->index--;
1646 return S_OK;
1649 static HRESULT WINAPI recordset_MoveFirst( _Recordset *iface )
1651 struct recordset *recordset = impl_from_Recordset( iface );
1653 TRACE( "%p\n", recordset );
1655 recordset->index = 0;
1656 return S_OK;
1659 static HRESULT WINAPI recordset_MoveLast( _Recordset *iface )
1661 struct recordset *recordset = impl_from_Recordset( iface );
1663 TRACE( "%p\n", recordset );
1665 recordset->index = (recordset->count > 0) ? recordset->count - 1 : 0;
1666 return S_OK;
1669 static HRESULT create_command_text(IUnknown *session, BSTR command, ICommandText **cmd_text)
1671 HRESULT hr;
1672 IOpenRowset *openrowset;
1673 ICommandText *command_text;
1674 ICommand *cmd;
1675 IDBCreateCommand *create_command;
1677 hr = IUnknown_QueryInterface(session, &IID_IOpenRowset, (void**)&openrowset);
1678 if (FAILED(hr))
1679 return hr;
1681 hr = IOpenRowset_QueryInterface(openrowset, &IID_IDBCreateCommand, (void**)&create_command);
1682 IOpenRowset_Release(openrowset);
1683 if (FAILED(hr))
1684 return hr;
1686 hr = IDBCreateCommand_CreateCommand(create_command, NULL, &IID_IUnknown, (IUnknown **)&cmd);
1687 IDBCreateCommand_Release(create_command);
1688 if (FAILED(hr))
1689 return hr;
1691 hr = ICommand_QueryInterface(cmd, &IID_ICommandText, (void**)&command_text);
1692 ICommand_Release(cmd);
1693 if (FAILED(hr))
1695 FIXME("Currently only ICommandText interface is support\n");
1696 return hr;
1699 hr = ICommandText_SetCommandText(command_text, &DBGUID_DEFAULT, command);
1700 if (FAILED(hr))
1702 ICommandText_Release(command_text);
1703 return hr;
1706 *cmd_text = command_text;
1708 return S_OK;
1711 #define ROUND_SIZE(size) (((size) + sizeof(void *) - 1) & ~(sizeof(void *) - 1))
1713 DEFINE_GUID(DBPROPSET_ROWSET, 0xc8b522be, 0x5cf3, 0x11ce, 0xad, 0xe5, 0x00, 0xaa, 0x00, 0x44, 0x77, 0x3d);
1715 static HRESULT create_bindings(IUnknown *rowset, struct recordset *recordset, DBBINDING **bind, DBBYTEOFFSET *size)
1717 HRESULT hr;
1718 IColumnsInfo *columninfo;
1719 IAccessor *accessor;
1720 DBORDINAL columns;
1721 DBCOLUMNINFO *colinfo;
1722 OLECHAR *stringsbuffer;
1723 DBBINDING *bindings;
1724 DBBYTEOFFSET offset;
1726 *size = 0;
1728 hr = IUnknown_QueryInterface(rowset, &IID_IColumnsInfo, (void**)&columninfo);
1729 if (FAILED(hr))
1730 return hr;
1732 hr = IUnknown_QueryInterface(rowset, &IID_IAccessor, (void**)&accessor);
1733 if (FAILED(hr))
1735 IColumnsInfo_Release(columninfo);
1736 return hr;
1739 hr = IColumnsInfo_GetColumnInfo(columninfo, &columns, &colinfo, &stringsbuffer);
1740 if (SUCCEEDED(hr))
1742 ULONG i;
1743 DBOBJECT *dbobj;
1744 offset = 1;
1746 recordset->columntypes = malloc(sizeof(DBTYPE) * columns);
1747 recordset->haccessors = calloc(1, sizeof(HACCESSOR) * columns );
1749 /* Do one allocation for the bindings and append the DBOBJECTS to the end.
1750 * This is to save on multiple allocations vs a little bit of extra memory.
1752 bindings = CoTaskMemAlloc( (sizeof(DBBINDING) + sizeof(DBOBJECT)) * columns);
1753 dbobj = (DBOBJECT *)((char*)bindings + (sizeof(DBBINDING) * columns));
1755 for (i=0; i < columns; i++)
1757 TRACE("Column %lu, pwszName: %s, pTypeInfo %p, iOrdinal %Iu, dwFlags 0x%08lx, "
1758 "ulColumnSize %Iu, wType %d, bPrecision %d, bScale %d\n",
1759 i, debugstr_w(colinfo[i].pwszName), colinfo[i].pTypeInfo, colinfo[i].iOrdinal,
1760 colinfo[i].dwFlags, colinfo[i].ulColumnSize, colinfo[i].wType,
1761 colinfo[i].bPrecision, colinfo[i].bScale);
1763 hr = append_field(recordset->fields, colinfo[i].pwszName, colinfo[i].wType, colinfo[i].ulColumnSize,
1764 colinfo[i].dwFlags, NULL);
1766 bindings[i].iOrdinal = colinfo[i].iOrdinal;
1767 bindings[i].obValue = offset;
1768 bindings[i].pTypeInfo = NULL;
1769 /* Always assigned the pObject even if it's not used. */
1770 bindings[i].pObject = &dbobj[i];
1771 bindings[i].pObject->dwFlags = 0;
1772 bindings[i].pObject->iid = IID_ISequentialStream;
1773 bindings[i].pBindExt = NULL;
1774 bindings[i].dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;
1775 bindings[i].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
1776 bindings[i].eParamIO = 0;
1778 recordset->columntypes[i] = colinfo[i].wType;
1779 if (colinfo[i].dwFlags & DBCOLUMNFLAGS_ISLONG)
1781 colinfo[i].wType = DBTYPE_IUNKNOWN;
1783 bindings[i].cbMaxLen = (colinfo[i].ulColumnSize + 1) * sizeof(WCHAR);
1784 offset += sizeof(ISequentialStream*);
1786 else if(colinfo[i].wType == DBTYPE_WSTR)
1788 /* ulColumnSize is the number of characters in the string not the actual buffer size */
1789 bindings[i].cbMaxLen = colinfo[i].ulColumnSize * sizeof(WCHAR);
1790 offset += bindings[i].cbMaxLen;
1792 else
1794 bindings[i].cbMaxLen = colinfo[i].ulColumnSize;
1795 offset += bindings[i].cbMaxLen;
1798 bindings[i].dwFlags = 0;
1799 bindings[i].wType = colinfo[i].wType;
1800 bindings[i].bPrecision = colinfo[i].bPrecision;
1801 bindings[i].bScale = colinfo[i].bScale;
1804 offset = ROUND_SIZE(offset);
1805 for (i=0; i < columns; i++)
1807 bindings[i].obLength = offset;
1808 bindings[i].obStatus = offset + sizeof(DBBYTEOFFSET);
1810 offset += sizeof(DBBYTEOFFSET) + sizeof(DBBYTEOFFSET);
1812 hr = IAccessor_CreateAccessor(accessor, DBACCESSOR_ROWDATA, 1, &bindings[i], 0, &recordset->haccessors[i], NULL);
1813 if (FAILED(hr))
1814 FIXME("IAccessor_CreateAccessor Failed 0x%0lx\n", hr);
1817 *size = offset;
1818 *bind = bindings;
1820 CoTaskMemFree(colinfo);
1821 CoTaskMemFree(stringsbuffer);
1824 IAccessor_Release(accessor);
1826 IColumnsInfo_Release(columninfo);
1828 return hr;
1831 static HRESULT load_all_recordset_data(struct recordset *recordset, IUnknown *rowset, DBBINDING *bindings,
1832 DBBYTEOFFSET datasize)
1834 IRowset *rowset2;
1835 DBORDINAL columns;
1836 HRESULT hr;
1837 DBCOUNTITEM obtained;
1838 HROW *row = NULL;
1839 int datarow = 0, datacol;
1840 char *data;
1842 columns = get_column_count(recordset);
1844 /* Create the data array */
1845 if (!resize_recordset( recordset, recordset->count ))
1847 WARN("Failed to resize recordset\n");
1848 return E_OUTOFMEMORY;
1851 hr = IUnknown_QueryInterface(rowset, &IID_IRowset, (void**)&rowset2);
1852 if (FAILED(hr))
1854 WARN("Failed to get IRowset interface (0x%08lx)\n", hr);
1855 return hr;
1858 data = malloc (datasize);
1859 if (!data)
1861 ERR("Failed to allocate row data (%Iu)\n", datasize);
1862 IRowset_Release(rowset2);
1863 return E_OUTOFMEMORY;
1866 hr = IRowset_GetNextRows(rowset2, 0, 0, 1, &obtained, &row);
1867 while (hr == S_OK)
1869 VARIANT copy;
1871 for (datacol = 0; datacol < columns; datacol++)
1873 hr = IRowset_GetData(rowset2, *row, recordset->haccessors[datacol], data);
1874 if (FAILED(hr))
1876 ERR("GetData Failed on Column %d (0x%08lx), status %Id\n", datacol, hr,
1877 *(DBBYTEOFFSET*)(data + bindings[datacol].obStatus));
1878 break;
1881 VariantInit(&copy);
1883 if ( *(DBBYTEOFFSET*)(data + bindings[datacol].obStatus) == DBSTATUS_S_ISNULL)
1885 V_VT(&copy) = VT_NULL;
1886 goto writedata;
1889 /* For most cases DBTYPE_* = VT_* type */
1890 V_VT(&copy) = bindings[datacol].wType;
1891 switch(bindings[datacol].wType)
1893 case DBTYPE_IUNKNOWN:
1895 ISequentialStream *seq;
1896 char unkdata[2048];
1897 ULONG size = 4096, dataRead = 0, total = 0;
1898 char *buffer = malloc(size), *p = buffer;
1899 HRESULT hr2;
1902 * Cast directly to the object we specified in our bindings. As this object
1903 * is referenced counted in some case and will error in GetData if the object
1904 * hasn't been released.
1906 seq = *(ISequentialStream**)(data + bindings[datacol].obValue);
1907 TRACE("Reading DBTYPE_IUNKNOWN %p\n", seq);
1911 dataRead = 0;
1912 hr2 = ISequentialStream_Read(seq, unkdata, sizeof(unkdata), &dataRead);
1913 if (FAILED(hr2) || !dataRead) break;
1915 total += dataRead;
1916 memcpy(p, unkdata, dataRead);
1917 p += dataRead;
1918 if (total == size)
1920 size *= 2; /* Double buffer */
1921 buffer = realloc(buffer, size);
1922 p = buffer + total;
1924 } while(hr2 == S_OK);
1926 if (recordset->columntypes[datacol] == DBTYPE_WSTR)
1928 V_VT(&copy) = VT_BSTR;
1929 V_BSTR(&copy) = SysAllocStringLen( (WCHAR*)buffer, total / sizeof(WCHAR) );
1931 else if (recordset->columntypes[datacol] == DBTYPE_BYTES)
1933 SAFEARRAYBOUND sab;
1935 sab.lLbound = 0;
1936 sab.cElements = total;
1938 V_VT(&copy) = (VT_ARRAY|VT_UI1);
1939 V_ARRAY(&copy) = SafeArrayCreate(VT_UI1, 1, &sab);
1941 memcpy( (BYTE*)V_ARRAY(&copy)->pvData, buffer, total);
1943 else
1945 FIXME("Unsupported conversion (%d)\n", recordset->columntypes[datacol]);
1946 V_VT(&copy) = VT_NULL;
1949 free(buffer);
1950 ISequentialStream_Release(seq);
1952 break;
1954 case DBTYPE_R4:
1955 V_R4(&copy) = *(float*)(data + bindings[datacol].obValue);
1956 break;
1957 case DBTYPE_R8:
1958 V_R8(&copy) = *(DOUBLE*)(data + bindings[datacol].obValue);
1959 break;
1960 case DBTYPE_I8:
1961 V_VT(&copy) = VT_I8;
1962 V_I8(&copy) = *(LONGLONG*)(data + bindings[datacol].obValue);
1963 break;
1964 case DBTYPE_I4:
1965 V_I4(&copy) = *(LONG*)(data + bindings[datacol].obValue);
1966 break;
1967 case DBTYPE_STR:
1969 WCHAR *str = heap_strdupAtoW( (char*)(data + bindings[datacol].obValue) );
1971 V_VT(&copy) = VT_BSTR;
1972 V_BSTR(&copy) = SysAllocString(str);
1973 free(str);
1974 break;
1976 case DBTYPE_WSTR:
1978 V_VT(&copy) = VT_BSTR;
1979 V_BSTR(&copy) = SysAllocString( (WCHAR*)(data + bindings[datacol].obValue) );
1980 break;
1982 case DBTYPE_DBTIMESTAMP:
1984 SYSTEMTIME st;
1985 DBTIMESTAMP *ts = (DBTIMESTAMP *)(data + bindings[datacol].obValue);
1986 DATE d;
1988 V_VT(&copy) = VT_DATE;
1990 st.wYear = ts->year;
1991 st.wMonth = ts->month;
1992 st.wDay = ts->day;
1993 st.wHour = ts->hour;
1994 st.wMinute = ts->minute;
1995 st.wSecond = ts->second;
1996 st.wMilliseconds = ts->fraction/1000000;
1997 st.wDayOfWeek = 0;
1998 hr = (SystemTimeToVariantTime(&st, &d) ? S_OK : E_FAIL);
2000 V_DATE(&copy) = d;
2001 break;
2003 default:
2004 V_I2(&copy) = 0;
2005 FIXME("Unknown Type %d\n", bindings[datacol].wType);
2008 writedata:
2009 VariantInit( &recordset->data[datarow * columns + datacol] );
2010 if ((hr = VariantCopy( &recordset->data[datarow * columns + datacol] , &copy)) != S_OK)
2012 ERR("Column %d copy failed. Data %s\n", datacol, debugstr_variant(&copy));
2015 VariantClear(&copy);
2018 datarow++;
2020 hr = IRowset_ReleaseRows(rowset2, 1, row, NULL, NULL, NULL);
2021 if (FAILED(hr))
2022 ERR("Failed to ReleaseRows 0x%08lx\n", hr);
2024 hr = IRowset_GetNextRows(rowset2, 0, 0, 1, &obtained, &row);
2027 free(data);
2028 IRowset_Release(rowset2);
2030 return S_OK;
2033 static HRESULT WINAPI recordset_Open( _Recordset *iface, VARIANT source, VARIANT active_connection,
2034 CursorTypeEnum cursor_type, LockTypeEnum lock_type, LONG options )
2036 struct recordset *recordset = impl_from_Recordset( iface );
2037 ADOConnectionConstruction15 *construct;
2038 IUnknown *session;
2039 ICommandText *command_text;
2040 DBROWCOUNT affected;
2041 IUnknown *rowset;
2042 HRESULT hr;
2043 DBBINDING *bindings;
2044 DBBYTEOFFSET datasize;
2046 TRACE( "%p, %s, %s, %d, %d, %ld\n", recordset, debugstr_variant(&source), debugstr_variant(&active_connection),
2047 cursor_type, lock_type, options );
2049 if (recordset->state == adStateOpen) return MAKE_ADO_HRESULT( adErrObjectOpen );
2051 if (recordset->fields)
2053 recordset->state = adStateOpen;
2054 return S_OK;
2057 if (V_VT(&active_connection) != VT_DISPATCH)
2059 FIXME("Unsupported Active connection type %d\n", V_VT(&active_connection));
2060 return MAKE_ADO_HRESULT( adErrInvalidConnection );
2063 hr = IDispatch_QueryInterface(V_DISPATCH(&active_connection), &IID_ADOConnectionConstruction15, (void**)&construct);
2064 if (FAILED(hr))
2065 return E_FAIL;
2067 hr = ADOConnectionConstruction15_get_Session(construct, &session);
2068 ADOConnectionConstruction15_Release(construct);
2069 if (FAILED(hr))
2070 return E_FAIL;
2072 if (V_VT(&source) != VT_BSTR)
2074 FIXME("Unsupported source type!\n");
2075 IUnknown_Release(session);
2076 return E_FAIL;
2079 hr = create_command_text(session, V_BSTR(&source), &command_text);
2080 IUnknown_Release(session);
2081 if (FAILED(hr))
2082 return hr;
2084 hr = ICommandText_Execute(command_text, NULL, &IID_IUnknown, NULL, &affected, &rowset);
2085 ICommandText_Release(command_text);
2086 if (FAILED(hr) || !rowset)
2087 return hr;
2089 /* We want to create the field member variable without mapping the rowset fields, this will
2090 * save querying the fields twice. Fields will be added while we create the bindings.
2092 hr = fields_create( recordset, &recordset->fields );
2093 if (FAILED(hr))
2095 IUnknown_Release(rowset);
2096 return hr;
2099 hr = create_bindings(rowset, recordset, &bindings, &datasize);
2100 if (FAILED(hr))
2102 WARN("Failed to load bindings (%lx)\n", hr);
2103 IUnknown_Release(rowset);
2104 return hr;
2107 recordset->count = affected;
2108 recordset->index = affected ? 0 : -1;
2111 * We can safely just return with an empty recordset here
2113 if (affected > 0)
2115 hr = load_all_recordset_data(recordset, rowset, bindings, datasize);
2116 if (FAILED(hr))
2118 WARN("Failed to load all recordset data (%lx)\n", hr);
2119 CoTaskMemFree(bindings);
2120 IUnknown_Release(rowset);
2121 return hr;
2125 CoTaskMemFree(bindings);
2127 ADORecordsetConstruction_put_Rowset(&recordset->ADORecordsetConstruction_iface, rowset);
2128 recordset->cursor_type = cursor_type;
2129 recordset->state = adStateOpen;
2131 IUnknown_Release(rowset);
2133 return hr;
2136 static HRESULT WINAPI recordset_Requery( _Recordset *iface, LONG options )
2138 FIXME( "%p, %ld\n", iface, options );
2139 return E_NOTIMPL;
2142 static HRESULT WINAPI recordset__xResync( _Recordset *iface, AffectEnum affect_records )
2144 FIXME( "%p, %u\n", iface, affect_records );
2145 return E_NOTIMPL;
2148 static HRESULT WINAPI recordset_Update( _Recordset *iface, VARIANT fields, VARIANT values )
2150 FIXME( "%p, %s, %s\n", iface, debugstr_variant(&fields), debugstr_variant(&values) );
2151 return E_NOTIMPL;
2154 static HRESULT WINAPI recordset_get_AbsolutePage( _Recordset *iface, PositionEnum_Param *pos )
2156 FIXME( "%p, %p\n", iface, pos );
2157 return E_NOTIMPL;
2160 static HRESULT WINAPI recordset_put_AbsolutePage( _Recordset *iface, PositionEnum_Param pos )
2162 FIXME( "%p, %Id\n", iface, pos );
2163 return E_NOTIMPL;
2166 static HRESULT WINAPI recordset_get_EditMode( _Recordset *iface, EditModeEnum *mode )
2168 struct recordset *recordset = impl_from_Recordset( iface );
2169 TRACE( "%p, %p\n", iface, mode );
2171 if (recordset->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed );
2172 if (recordset->index < 0) return MAKE_ADO_HRESULT( adErrNoCurrentRecord );
2174 *mode = recordset->editmode;
2175 return S_OK;
2178 static HRESULT WINAPI recordset_get_Filter( _Recordset *iface, VARIANT *criteria )
2180 struct recordset *recordset = impl_from_Recordset( iface );
2181 TRACE( "%p, %p\n", iface, criteria );
2183 if (!criteria) return MAKE_ADO_HRESULT( adErrInvalidArgument );
2185 VariantCopy(criteria, &recordset->filter);
2186 return S_OK;
2189 static HRESULT WINAPI recordset_put_Filter( _Recordset *iface, VARIANT criteria )
2191 struct recordset *recordset = impl_from_Recordset( iface );
2192 TRACE( "%p, %s\n", recordset, debugstr_variant(&criteria) );
2194 if (V_VT(&criteria) != VT_I2 && V_VT(&criteria) != VT_I4 && V_VT(&criteria) != VT_BSTR)
2195 return MAKE_ADO_HRESULT( adErrInvalidArgument );
2197 if (V_VT(&criteria) == VT_BSTR && recordset->state == adStateOpen)
2199 FIXME("Validating fields not performed\n");
2202 VariantCopy(&recordset->filter, &criteria);
2203 return S_OK;
2206 static HRESULT WINAPI recordset_get_PageCount( _Recordset *iface, ADO_LONGPTR *count )
2208 FIXME( "%p, %p\n", iface, count );
2209 return E_NOTIMPL;
2212 static HRESULT WINAPI recordset_get_PageSize( _Recordset *iface, LONG *size )
2214 FIXME( "%p, %p\n", iface, size );
2215 return E_NOTIMPL;
2218 static HRESULT WINAPI recordset_put_PageSize( _Recordset *iface, LONG size )
2220 FIXME( "%p, %ld\n", iface, size );
2221 return E_NOTIMPL;
2224 static HRESULT WINAPI recordset_get_Sort( _Recordset *iface, BSTR *criteria )
2226 FIXME( "%p, %p\n", iface, criteria );
2227 return E_NOTIMPL;
2230 static HRESULT WINAPI recordset_put_Sort( _Recordset *iface, BSTR criteria )
2232 FIXME( "%p, %s\n", iface, debugstr_w(criteria) );
2233 return E_NOTIMPL;
2236 static HRESULT WINAPI recordset_get_Status( _Recordset *iface, LONG *status )
2238 FIXME( "%p, %p\n", iface, status );
2239 return E_NOTIMPL;
2242 static HRESULT WINAPI recordset_get_State( _Recordset *iface, LONG *state )
2244 struct recordset *recordset = impl_from_Recordset( iface );
2246 TRACE( "%p, %p\n", recordset, state );
2248 *state = recordset->state;
2249 return S_OK;
2252 static HRESULT WINAPI recordset__xClone( _Recordset *iface, _Recordset **obj )
2254 FIXME( "%p, %p\n", iface, obj );
2255 return E_NOTIMPL;
2258 static HRESULT WINAPI recordset_UpdateBatch( _Recordset *iface, AffectEnum affect_records )
2260 FIXME( "%p, %u\n", iface, affect_records );
2261 return E_NOTIMPL;
2264 static HRESULT WINAPI recordset_CancelBatch( _Recordset *iface, AffectEnum affect_records )
2266 FIXME( "%p, %u\n", iface, affect_records );
2267 return E_NOTIMPL;
2270 static HRESULT WINAPI recordset_get_CursorLocation( _Recordset *iface, CursorLocationEnum *cursor_loc )
2272 struct recordset *recordset = impl_from_Recordset( iface );
2274 TRACE( "%p, %p\n", iface, cursor_loc );
2276 *cursor_loc = recordset->cursor_location;
2278 return S_OK;
2281 static HRESULT WINAPI recordset_put_CursorLocation( _Recordset *iface, CursorLocationEnum cursor_loc )
2283 struct recordset *recordset = impl_from_Recordset( iface );
2285 TRACE( "%p, %u\n", iface, cursor_loc );
2287 if (recordset->state == adStateOpen) return MAKE_ADO_HRESULT( adErrObjectOpen );
2289 recordset->cursor_location = cursor_loc;
2291 return S_OK;
2294 static HRESULT WINAPI recordset_NextRecordset( _Recordset *iface, VARIANT *records_affected, _Recordset **record_set )
2296 FIXME( "%p, %p, %p\n", iface, records_affected, record_set );
2297 return E_NOTIMPL;
2300 static HRESULT WINAPI recordset_Supports( _Recordset *iface, CursorOptionEnum cursor_options, VARIANT_BOOL *ret )
2302 FIXME( "%p, %08x, %p\n", iface, cursor_options, ret );
2303 return E_NOTIMPL;
2306 static HRESULT WINAPI recordset_get_Collect( _Recordset *iface, VARIANT index, VARIANT *var )
2308 FIXME( "%p, %s, %p\n", iface, debugstr_variant(&index), var );
2309 return E_NOTIMPL;
2312 static HRESULT WINAPI recordset_put_Collect( _Recordset *iface, VARIANT index, VARIANT var )
2314 FIXME( "%p, %s, %s\n", iface, debugstr_variant(&index), debugstr_variant(&var) );
2315 return E_NOTIMPL;
2318 static HRESULT WINAPI recordset_get_MarshalOptions( _Recordset *iface, MarshalOptionsEnum *options )
2320 FIXME( "%p, %p\n", iface, options );
2321 return E_NOTIMPL;
2324 static HRESULT WINAPI recordset_put_MarshalOptions( _Recordset *iface, MarshalOptionsEnum options )
2326 FIXME( "%p, %u\n", iface, options );
2327 return E_NOTIMPL;
2330 static HRESULT WINAPI recordset_Find( _Recordset *iface, BSTR criteria, LONG skip_records,
2331 SearchDirectionEnum search_direction, VARIANT start )
2333 FIXME( "%p, %s, %ld, %d, %s\n", iface, debugstr_w(criteria), skip_records, search_direction,
2334 debugstr_variant(&start) );
2335 return E_NOTIMPL;
2338 static HRESULT WINAPI recordset_Cancel( _Recordset *iface )
2340 FIXME( "%p\n", iface );
2341 return E_NOTIMPL;
2344 static HRESULT WINAPI recordset_get_DataSource( _Recordset *iface, IUnknown **data_source )
2346 FIXME( "%p, %p\n", iface, data_source );
2347 return E_NOTIMPL;
2350 static HRESULT WINAPI recordset_putref_DataSource( _Recordset *iface, IUnknown *data_source )
2352 FIXME( "%p, %p\n", iface, data_source );
2353 return E_NOTIMPL;
2356 static HRESULT WINAPI recordset__xSave( _Recordset *iface, BSTR filename, PersistFormatEnum persist_format )
2358 FIXME( "%p, %s, %u\n", iface, debugstr_w(filename), persist_format );
2359 return E_NOTIMPL;
2362 static HRESULT WINAPI recordset_get_ActiveCommand( _Recordset *iface, IDispatch **cmd )
2364 FIXME( "%p, %p\n", iface, cmd );
2365 return E_NOTIMPL;
2368 static HRESULT WINAPI recordset_put_StayInSync( _Recordset *iface, VARIANT_BOOL stay_in_sync )
2370 FIXME( "%p, %d\n", iface, stay_in_sync );
2371 return E_NOTIMPL;
2374 static HRESULT WINAPI recordset_get_StayInSync( _Recordset *iface, VARIANT_BOOL *stay_in_sync )
2376 FIXME( "%p, %p\n", iface, stay_in_sync );
2377 return E_NOTIMPL;
2380 static HRESULT WINAPI recordset_GetString( _Recordset *iface, StringFormatEnum string_format, LONG num_rows,
2381 BSTR column_delimiter, BSTR row_delimiter, BSTR null_expr,
2382 BSTR *ret_string )
2384 FIXME( "%p, %u, %ld, %s, %s, %s, %p\n", iface, string_format, num_rows, debugstr_w(column_delimiter),
2385 debugstr_w(row_delimiter), debugstr_w(null_expr), ret_string );
2386 return E_NOTIMPL;
2389 static HRESULT WINAPI recordset_get_DataMember( _Recordset *iface, BSTR *data_member )
2391 FIXME( "%p, %p\n", iface, data_member );
2392 return E_NOTIMPL;
2395 static HRESULT WINAPI recordset_put_DataMember( _Recordset *iface, BSTR data_member )
2397 FIXME( "%p, %s\n", iface, debugstr_w(data_member) );
2398 return E_NOTIMPL;
2401 static HRESULT WINAPI recordset_CompareBookmarks( _Recordset *iface, VARIANT bookmark1, VARIANT bookmark2, CompareEnum *compare )
2403 FIXME( "%p, %s, %s, %p\n", iface, debugstr_variant(&bookmark1), debugstr_variant(&bookmark2), compare );
2404 return E_NOTIMPL;
2407 static HRESULT WINAPI recordset_Clone( _Recordset *iface, LockTypeEnum lock_type, _Recordset **obj )
2409 struct recordset *recordset = impl_from_Recordset( iface );
2410 FIXME( "%p, %d, %p\n", recordset, lock_type, obj );
2412 *obj = iface;
2413 recordset_AddRef( iface );
2414 return S_OK;
2417 static HRESULT WINAPI recordset_Resync( _Recordset *iface, AffectEnum affect_records, ResyncEnum resync_values )
2419 FIXME( "%p, %u, %u\n", iface, affect_records, resync_values );
2420 return E_NOTIMPL;
2423 static HRESULT WINAPI recordset_Seek( _Recordset *iface, VARIANT key_values, SeekEnum seek_option )
2425 FIXME( "%p, %s, %u\n", iface, debugstr_variant(&key_values), seek_option );
2426 return E_NOTIMPL;
2429 static HRESULT WINAPI recordset_put_Index( _Recordset *iface, BSTR index )
2431 FIXME( "%p, %s\n", iface, debugstr_w(index) );
2432 return E_NOTIMPL;
2435 static HRESULT WINAPI recordset_get_Index( _Recordset *iface, BSTR *index )
2437 FIXME( "%p, %p\n", iface, index );
2438 return E_NOTIMPL;
2441 static HRESULT WINAPI recordset_Save( _Recordset *iface, VARIANT destination, PersistFormatEnum persist_format )
2443 FIXME( "%p, %s, %u\n", iface, debugstr_variant(&destination), persist_format );
2444 return E_NOTIMPL;
2447 static const struct _RecordsetVtbl recordset_vtbl =
2449 recordset_QueryInterface,
2450 recordset_AddRef,
2451 recordset_Release,
2452 recordset_GetTypeInfoCount,
2453 recordset_GetTypeInfo,
2454 recordset_GetIDsOfNames,
2455 recordset_Invoke,
2456 recordset_get_Properties,
2457 recordset_get_AbsolutePosition,
2458 recordset_put_AbsolutePosition,
2459 recordset_putref_ActiveConnection,
2460 recordset_put_ActiveConnection,
2461 recordset_get_ActiveConnection,
2462 recordset_get_BOF,
2463 recordset_get_Bookmark,
2464 recordset_put_Bookmark,
2465 recordset_get_CacheSize,
2466 recordset_put_CacheSize,
2467 recordset_get_CursorType,
2468 recordset_put_CursorType,
2469 recordset_get_EOF,
2470 recordset_get_Fields,
2471 recordset_get_LockType,
2472 recordset_put_LockType,
2473 recordset_get_MaxRecords,
2474 recordset_put_MaxRecords,
2475 recordset_get_RecordCount,
2476 recordset_putref_Source,
2477 recordset_put_Source,
2478 recordset_get_Source,
2479 recordset_AddNew,
2480 recordset_CancelUpdate,
2481 recordset_Close,
2482 recordset_Delete,
2483 recordset_GetRows,
2484 recordset_Move,
2485 recordset_MoveNext,
2486 recordset_MovePrevious,
2487 recordset_MoveFirst,
2488 recordset_MoveLast,
2489 recordset_Open,
2490 recordset_Requery,
2491 recordset__xResync,
2492 recordset_Update,
2493 recordset_get_AbsolutePage,
2494 recordset_put_AbsolutePage,
2495 recordset_get_EditMode,
2496 recordset_get_Filter,
2497 recordset_put_Filter,
2498 recordset_get_PageCount,
2499 recordset_get_PageSize,
2500 recordset_put_PageSize,
2501 recordset_get_Sort,
2502 recordset_put_Sort,
2503 recordset_get_Status,
2504 recordset_get_State,
2505 recordset__xClone,
2506 recordset_UpdateBatch,
2507 recordset_CancelBatch,
2508 recordset_get_CursorLocation,
2509 recordset_put_CursorLocation,
2510 recordset_NextRecordset,
2511 recordset_Supports,
2512 recordset_get_Collect,
2513 recordset_put_Collect,
2514 recordset_get_MarshalOptions,
2515 recordset_put_MarshalOptions,
2516 recordset_Find,
2517 recordset_Cancel,
2518 recordset_get_DataSource,
2519 recordset_putref_DataSource,
2520 recordset__xSave,
2521 recordset_get_ActiveCommand,
2522 recordset_put_StayInSync,
2523 recordset_get_StayInSync,
2524 recordset_GetString,
2525 recordset_get_DataMember,
2526 recordset_put_DataMember,
2527 recordset_CompareBookmarks,
2528 recordset_Clone,
2529 recordset_Resync,
2530 recordset_Seek,
2531 recordset_put_Index,
2532 recordset_get_Index,
2533 recordset_Save
2536 static inline struct recordset *recordset_from_ISupportErrorInfo( ISupportErrorInfo *iface )
2538 return CONTAINING_RECORD( iface, struct recordset, ISupportErrorInfo_iface );
2541 static HRESULT WINAPI recordset_supporterrorinfo_QueryInterface( ISupportErrorInfo *iface, REFIID riid, void **obj )
2543 struct recordset *recordset = recordset_from_ISupportErrorInfo( iface );
2544 return _Recordset_QueryInterface( &recordset->Recordset_iface, riid, obj );
2547 static ULONG WINAPI recordset_supporterrorinfo_AddRef( ISupportErrorInfo *iface )
2549 struct recordset *recordset = recordset_from_ISupportErrorInfo( iface );
2550 return _Recordset_AddRef( &recordset->Recordset_iface );
2553 static ULONG WINAPI recordset_supporterrorinfo_Release( ISupportErrorInfo *iface )
2555 struct recordset *recordset = recordset_from_ISupportErrorInfo( iface );
2556 return _Recordset_Release( &recordset->Recordset_iface );
2559 static HRESULT WINAPI recordset_supporterrorinfo_InterfaceSupportsErrorInfo( ISupportErrorInfo *iface, REFIID riid )
2561 struct recordset *recordset = recordset_from_ISupportErrorInfo( iface );
2562 FIXME( "%p, %s\n", recordset, debugstr_guid(riid) );
2563 return S_FALSE;
2566 static const ISupportErrorInfoVtbl recordset_supporterrorinfo_vtbl =
2568 recordset_supporterrorinfo_QueryInterface,
2569 recordset_supporterrorinfo_AddRef,
2570 recordset_supporterrorinfo_Release,
2571 recordset_supporterrorinfo_InterfaceSupportsErrorInfo
2574 static HRESULT WINAPI rsconstruction_QueryInterface(ADORecordsetConstruction *iface,
2575 REFIID riid, void **obj)
2577 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2578 return _Recordset_QueryInterface( &recordset->Recordset_iface, riid, obj );
2581 static ULONG WINAPI rsconstruction_AddRef(ADORecordsetConstruction *iface)
2583 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2584 return _Recordset_AddRef( &recordset->Recordset_iface );
2587 static ULONG WINAPI rsconstruction_Release(ADORecordsetConstruction *iface)
2589 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2590 return _Recordset_Release( &recordset->Recordset_iface );
2593 static HRESULT WINAPI rsconstruction_GetTypeInfoCount(ADORecordsetConstruction *iface, UINT *pctinfo)
2595 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2596 TRACE( "%p, %p\n", recordset, pctinfo );
2597 *pctinfo = 1;
2598 return S_OK;
2601 static HRESULT WINAPI rsconstruction_GetTypeInfo(ADORecordsetConstruction *iface, UINT iTInfo,
2602 LCID lcid, ITypeInfo **ppTInfo)
2604 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2605 TRACE( "%p %u %lu %p\n", recordset, iTInfo, lcid, ppTInfo );
2606 return get_typeinfo(ADORecordsetConstruction_tid, ppTInfo);
2609 static HRESULT WINAPI rsconstruction_GetIDsOfNames(ADORecordsetConstruction *iface, REFIID riid,
2610 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
2612 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2613 HRESULT hr;
2614 ITypeInfo *typeinfo;
2616 TRACE( "%p %s %p %u %lu %p\n", recordset, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId );
2618 hr = get_typeinfo(ADORecordsetConstruction_tid, &typeinfo);
2619 if(SUCCEEDED(hr))
2621 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2622 ITypeInfo_Release(typeinfo);
2625 return hr;
2628 static HRESULT WINAPI rsconstruction_Invoke(ADORecordsetConstruction *iface, DISPID dispIdMember,
2629 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
2630 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2632 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2633 HRESULT hr;
2634 ITypeInfo *typeinfo;
2636 TRACE( "%p %ld %s %ld %d %p %p %p %p\n", recordset, dispIdMember, debugstr_guid(riid),
2637 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr );
2639 hr = get_typeinfo(ADORecordsetConstruction_tid, &typeinfo);
2640 if(SUCCEEDED(hr))
2642 hr = ITypeInfo_Invoke(typeinfo, &recordset->ADORecordsetConstruction_iface, dispIdMember, wFlags,
2643 pDispParams, pVarResult, pExcepInfo, puArgErr);
2644 ITypeInfo_Release(typeinfo);
2647 return hr;
2650 static HRESULT WINAPI rsconstruction_get_Rowset(ADORecordsetConstruction *iface, IUnknown **row_set)
2652 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2653 HRESULT hr;
2655 TRACE( "%p, %p\n", recordset, row_set );
2657 hr = IRowset_QueryInterface(recordset->row_set, &IID_IUnknown, (void**)row_set);
2658 if ( FAILED(hr) ) return E_FAIL;
2660 return S_OK;
2663 static HRESULT WINAPI rsconstruction_put_Rowset(ADORecordsetConstruction *iface, IUnknown *unk)
2665 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2666 HRESULT hr;
2667 IRowset *rowset;
2669 TRACE( "%p, %p\n", recordset, unk );
2671 hr = IUnknown_QueryInterface(unk, &IID_IRowset, (void**)&rowset);
2672 if ( FAILED(hr) ) return E_FAIL;
2674 if ( recordset->row_set ) IRowset_Release( recordset->row_set );
2675 recordset->row_set = rowset;
2677 return S_OK;
2680 static HRESULT WINAPI rsconstruction_get_Chapter(ADORecordsetConstruction *iface, ADO_LONGPTR *chapter)
2682 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2683 FIXME( "%p, %p\n", recordset, chapter );
2684 return E_NOTIMPL;
2687 static HRESULT WINAPI rsconstruction_put_Chapter(ADORecordsetConstruction *iface, ADO_LONGPTR chapter)
2689 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2690 FIXME( "%p, %Id\n", recordset, chapter );
2691 return E_NOTIMPL;
2694 static HRESULT WINAPI rsconstruction_get_RowPosition(ADORecordsetConstruction *iface, IUnknown **row_pos)
2696 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2697 FIXME( "%p, %p\n", recordset, row_pos );
2698 return E_NOTIMPL;
2701 static HRESULT WINAPI rsconstruction_put_RowPosition(ADORecordsetConstruction *iface, IUnknown *row_pos)
2703 struct recordset *recordset = impl_from_ADORecordsetConstruction( iface );
2704 FIXME( "%p, %p\n", recordset, row_pos );
2705 return E_NOTIMPL;
2708 static const ADORecordsetConstructionVtbl rsconstruction_vtbl =
2710 rsconstruction_QueryInterface,
2711 rsconstruction_AddRef,
2712 rsconstruction_Release,
2713 rsconstruction_GetTypeInfoCount,
2714 rsconstruction_GetTypeInfo,
2715 rsconstruction_GetIDsOfNames,
2716 rsconstruction_Invoke,
2717 rsconstruction_get_Rowset,
2718 rsconstruction_put_Rowset,
2719 rsconstruction_get_Chapter,
2720 rsconstruction_put_Chapter,
2721 rsconstruction_get_RowPosition,
2722 rsconstruction_put_RowPosition
2725 HRESULT Recordset_create( void **obj )
2727 struct recordset *recordset;
2729 if (!(recordset = calloc( 1, sizeof(*recordset) ))) return E_OUTOFMEMORY;
2730 recordset->Recordset_iface.lpVtbl = &recordset_vtbl;
2731 recordset->ISupportErrorInfo_iface.lpVtbl = &recordset_supporterrorinfo_vtbl;
2732 recordset->ADORecordsetConstruction_iface.lpVtbl = &rsconstruction_vtbl;
2733 recordset->refs = 1;
2734 recordset->index = -1;
2735 recordset->cursor_location = adUseServer;
2736 recordset->cursor_type = adOpenForwardOnly;
2737 recordset->row_set = NULL;
2738 recordset->editmode = adEditNone;
2739 VariantInit( &recordset->filter );
2740 recordset->columntypes = NULL;
2741 recordset->haccessors = NULL;
2743 *obj = &recordset->Recordset_iface;
2744 TRACE( "returning iface %p\n", *obj );
2745 return S_OK;