From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/msado15_private.h | 2 +- dlls/msado15/recordset.c | 35 ++++++++- dlls/msado15/rowset.c | 125 ++++++++++++++++++++++++++++++++- 3 files changed, 158 insertions(+), 4 deletions(-)
diff --git a/dlls/msado15/msado15_private.h b/dlls/msado15/msado15_private.h index f91e83bda38..a15c185adc0 100644 --- a/dlls/msado15/msado15_private.h +++ b/dlls/msado15/msado15_private.h @@ -26,7 +26,7 @@ HRESULT Connection_create( void ** ); HRESULT Recordset_create( void ** ); HRESULT Stream_create( void ** );
-HRESULT create_mem_rowset( IUnknown ** ); +HRESULT create_mem_rowset( int, const DBCOLUMNINFO *, IUnknown ** );
typedef enum tid_t { ADORecordsetConstruction_tid, diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index d74593ba956..a41023e03ef 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -2178,15 +2178,48 @@ static HRESULT WINAPI recordset_Open( _Recordset *iface, VARIANT source, VARIANT
if (get_column_count(recordset)) { + DBCOLUMNINFO *info; + int i; + if (recordset->active_connection) { FIXME("adding new table\n"); return E_NOTIMPL; }
- hr = create_mem_rowset(&rowset); + info = calloc(recordset->fields.count + 1, sizeof(*info)); + if (!info) + return E_OUTOFMEMORY; + + info[0].dwFlags = DBCOLUMNFLAGS_ISBOOKMARK | DBCOLUMNFLAGS_ISFIXEDLENGTH; + info[0].ulColumnSize = sizeof(unsigned int); + info[0].wType = DBTYPE_UI4; + info[0].bPrecision = 10; + info[0].bScale = 255; + info[0].columnid.eKind = DBKIND_GUID_PROPID; + info[0].columnid.uGuid.guid = DBCOL_SPECIALCOL; + info[0].columnid.uName.ulPropid = 2 /* PROPID_DBBMK_BOOKMARK */; + + for (i = 1; i <= recordset->fields.count; i++) + { + struct field *field = recordset->fields.field[i - 1]; + + info[i].pwszName = field->name; + info[i].iOrdinal = i; + info[i].dwFlags = field->attrs; + info[i].ulColumnSize = field->defined_size; + info[i].wType = field->type; + info[i].bPrecision = field->prec; + info[i].bScale = field->scale; + info[i].columnid.eKind = DBKIND_NAME; + info[i].columnid.uName.pwszName = field->name; + } + + hr = create_mem_rowset(recordset->fields.count + 1, info, &rowset); + free(info); if (FAILED(hr)) return hr; + hr = ADORecordsetConstruction_put_Rowset(&recordset->ADORecordsetConstruction_iface, rowset); IUnknown_Release(rowset); return hr; diff --git a/dlls/msado15/rowset.c b/dlls/msado15/rowset.c index 1193cc88326..030d5c64742 100644 --- a/dlls/msado15/rowset.c +++ b/dlls/msado15/rowset.c @@ -27,7 +27,12 @@ WINE_DEFAULT_DEBUG_CHANNEL(msado15); struct rowset { IRowset IRowset_iface; + IColumnsInfo IColumnsInfo_iface; LONG refs; + + int columns_cnt; + DBCOLUMNINFO *columns; + OLECHAR *columns_buf; };
static inline struct rowset *impl_from_IRowset(IRowset *iface) @@ -35,6 +40,11 @@ static inline struct rowset *impl_from_IRowset(IRowset *iface) return CONTAINING_RECORD(iface, struct rowset, IRowset_iface); }
+static inline struct rowset *impl_from_IColumnsInfo(IColumnsInfo *iface) +{ + return CONTAINING_RECORD(iface, struct rowset, IColumnsInfo_iface); +} + static HRESULT WINAPI rowset_QueryInterface(IRowset *iface, REFIID riid, void **ppv) { struct rowset *rowset = impl_from_IRowset(iface); @@ -47,6 +57,10 @@ static HRESULT WINAPI rowset_QueryInterface(IRowset *iface, REFIID riid, void ** { *ppv = &rowset->IRowset_iface; } + else if(IsEqualGUID(&IID_IColumnsInfo, riid)) + { + *ppv = &rowset->IColumnsInfo_iface; + }
if(*ppv) { @@ -79,6 +93,8 @@ static ULONG WINAPI rowset_Release(IRowset *iface) { TRACE("destroying %p\n", rowset);
+ CoTaskMemFree(rowset->columns); + CoTaskMemFree(rowset->columns_buf); free(rowset); } return refs; @@ -139,16 +155,121 @@ static const struct IRowsetVtbl rowset_vtbl = rowset_RestartPosition };
-HRESULT create_mem_rowset(IUnknown **ret) +static HRESULT WINAPI columns_info_QueryInterface(IColumnsInfo *iface, REFIID riid, void **out) +{ + struct rowset *rowset = impl_from_IColumnsInfo(iface); + return IRowset_QueryInterface(&rowset->IRowset_iface, riid, out); +} + +static ULONG WINAPI columns_info_AddRef(IColumnsInfo *iface) +{ + struct rowset *rowset = impl_from_IColumnsInfo(iface); + return IRowset_AddRef(&rowset->IRowset_iface); +} + +static ULONG WINAPI columns_info_Release(IColumnsInfo *iface) +{ + struct rowset *rowset = impl_from_IColumnsInfo(iface); + return IRowset_Release(&rowset->IRowset_iface); +} + +static HRESULT copy_column_info(DBCOLUMNINFO **dest, const DBCOLUMNINFO *src, int count, OLECHAR **buf) +{ + size_t len; + int i; + + *dest = CoTaskMemAlloc(sizeof(**dest) * count); + if (!*dest) + return E_OUTOFMEMORY; + memcpy(*dest, src, sizeof(**dest) * count); + + len = 0; + for (i = 0; i < count; i++) + { + if (src[i].pwszName) len += wcslen(src[i].pwszName) + 1; + if (src[i].columnid.eKind == DBKIND_GUID_NAME || src[i].columnid.eKind == DBKIND_NAME || + src[i].columnid.eKind == DBKIND_PGUID_NAME) + len += wcslen(src[i].columnid.uName.pwszName) + 1; + } + *buf = CoTaskMemAlloc(sizeof(**buf) * len); + if (!*buf) + { + CoTaskMemFree(*dest); + *dest = NULL; + return E_OUTOFMEMORY; + } + len = 0; + for (i = 0; i < count; i++) + { + if (src[i].pwszName) + { + wcscpy(*buf + len, src[i].pwszName); + (*dest)[i].pwszName = *buf + len; + len += wcslen(src[i].pwszName) + 1; + } + if (src[i].columnid.eKind == DBKIND_GUID_NAME || src[i].columnid.eKind == DBKIND_NAME || + src[i].columnid.eKind == DBKIND_PGUID_NAME) + { + wcscpy(*buf + len, src[i].columnid.uName.pwszName); + (*dest)[i].columnid.uName.pwszName = *buf + len; + len += wcslen(src[i].columnid.uName.pwszName) + 1; + } + } + return S_OK; +} + +static HRESULT WINAPI columns_info_GetColumnInfo(IColumnsInfo *iface, + DBORDINAL *columns, DBCOLUMNINFO **colinfo, OLECHAR **strbuf) +{ + struct rowset *rowset = impl_from_IColumnsInfo(iface); + + TRACE("%p, %p, %p, %p\n", rowset, columns, colinfo, strbuf); + + if (!columns || !colinfo || !strbuf) + return E_INVALIDARG; + + *columns = rowset->columns_cnt; + return copy_column_info(colinfo, rowset->columns, rowset->columns_cnt, strbuf); +} + +static HRESULT WINAPI columns_info_MapColumnIDs(IColumnsInfo *iface, + DBORDINAL column_ids, const DBID *dbids, DBORDINAL *columns) +{ + struct rowset *rowset = impl_from_IColumnsInfo(iface); + + FIXME("%p, %Iu, %p, %p\n", rowset, column_ids, dbids, columns); + return E_NOTIMPL; +} + +static struct IColumnsInfoVtbl columns_info_vtbl = +{ + columns_info_QueryInterface, + columns_info_AddRef, + columns_info_Release, + columns_info_GetColumnInfo, + columns_info_MapColumnIDs +}; + +HRESULT create_mem_rowset(int count, const DBCOLUMNINFO *info, IUnknown **ret) { struct rowset *rowset; + HRESULT hr;
- rowset = malloc(sizeof(*rowset)); + rowset = calloc(1, sizeof(*rowset)); if (!rowset) return E_OUTOFMEMORY;
rowset->IRowset_iface.lpVtbl = &rowset_vtbl; + rowset->IColumnsInfo_iface.lpVtbl = &columns_info_vtbl; rowset->refs = 1;
+ rowset->columns_cnt = count; + hr = copy_column_info(&rowset->columns, info, count, &rowset->columns_buf); + if (FAILED(hr)) + { + IRowset_Release(&rowset->IRowset_iface); + return E_OUTOFMEMORY; + } + *ret = (IUnknown *)&rowset->IRowset_iface; return S_OK; }