Commit 795845ff authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

oledb32: Support provider-specific properties in GetDataSource().

parent 0036b8bf
......@@ -29,6 +29,7 @@
#include "oledb_private.h"
#include "wine/debug.h"
#include "wine/list.h"
#include "wine/unicode.h"
WINE_DEFAULT_DEBUG_CHANNEL(oledb);
......@@ -346,12 +347,99 @@ static const struct dbproperty dbproperties[] = {
#endif
};
struct dbprop_pair
{
struct list entry;
BSTR name;
BSTR value;
};
struct dbprops
{
struct list props;
unsigned int count;
};
static HRESULT set_dbpropset(BSTR name, BSTR value, DBPROPSET **propset)
/* name/value strings are reused, so they shouldn't be freed after this call */
static HRESULT add_dbprop_to_list(struct dbprops *props, BSTR name, BSTR value)
{
struct dbprop_pair *pair;
pair = heap_alloc(sizeof(*pair));
if (!pair)
return E_OUTOFMEMORY;
pair->name = name;
pair->value = value;
list_add_tail(&props->props, &pair->entry);
props->count++;
return S_OK;
}
static void free_dbprop_list(struct dbprops *props)
{
struct dbprop_pair *p, *p2;
LIST_FOR_EACH_ENTRY_SAFE(p, p2, &props->props, struct dbprop_pair, entry)
{
list_remove(&p->entry);
SysFreeString(p->name);
SysFreeString(p->value);
heap_free(p);
}
}
static HRESULT parse_init_string(const WCHAR *initstring, struct dbprops *props)
{
const WCHAR *start;
WCHAR *eq;
HRESULT hr = S_OK;
list_init(&props->props);
props->count = 0;
start = initstring;
while (start && (eq = strchrW(start, '=')))
{
static const WCHAR providerW[] = {'P','r','o','v','i','d','e','r',0};
WCHAR *scol = strchrW(eq+1, ';');
BSTR value, name;
name = SysAllocStringLen(start, eq - start);
/* skip equal sign to get value */
eq++;
value = SysAllocStringLen(eq, scol ? scol - eq : -1);
/* skip semicolon if present */
if (scol) scol++;
start = scol;
if (!strcmpW(name, providerW))
{
SysFreeString(name);
SysFreeString(value);
continue;
}
TRACE("property (name=%s, value=%s)\n", debugstr_w(name), debugstr_w(value));
hr = add_dbprop_to_list(props, name, value);
if (FAILED(hr))
{
SysFreeString(name);
SysFreeString(value);
break;
}
}
if (FAILED(hr))
free_dbprop_list(props);
return hr;
}
static const struct dbproperty *get_known_dprop_descr(BSTR name)
{
VARIANT src, dest;
int min, max, n;
HRESULT hr;
min = 0;
max = sizeof(dbproperties)/sizeof(struct dbproperty) - 1;
......@@ -372,52 +460,92 @@ static HRESULT set_dbpropset(BSTR name, BSTR value, DBPROPSET **propset)
max = n-1;
}
if (min > max)
{
*propset = NULL;
FIXME("unsupported property %s\n", debugstr_w(name));
return E_FAIL;
}
VariantInit(&dest);
V_VT(&src) = VT_BSTR;
V_BSTR(&src) = value;
return (min <= max) ? &dbproperties[n] : NULL;
}
hr = VariantChangeType(&dest, &src, 0, dbproperties[n].type);
if (FAILED(hr))
{
ERR("failed to init property %s value as type %d\n", debugstr_w(name), dbproperties[n].type);
return hr;
}
static HRESULT get_dbpropset_from_proplist(struct dbprops *props, DBPROPSET **propset)
{
struct dbprop_pair *pair;
int i = 0;
HRESULT hr;
*propset = CoTaskMemAlloc(sizeof(DBPROPSET));
if (!*propset)
{
VariantClear(&dest);
return E_OUTOFMEMORY;
}
(*propset)->rgProperties = CoTaskMemAlloc(sizeof(DBPROP));
(*propset)->rgProperties = CoTaskMemAlloc(props->count*sizeof(DBPROP));
if (!(*propset)->rgProperties)
{
VariantClear(&dest);
CoTaskMemFree(*propset);
*propset = NULL;
return E_OUTOFMEMORY;
}
(*propset)->cProperties = 1;
(*propset)->cProperties = 0;
LIST_FOR_EACH_ENTRY(pair, &props->props, struct dbprop_pair, entry)
{
const struct dbproperty *descr = get_known_dprop_descr(pair->name);
VARIANT dest, src;
if (!descr)
{
static const WCHAR eqW[] = {'=',0};
BSTR str;
int len;
/* provider specific property is always VT_BSTR */
len = SysStringLen(pair->name) + SysStringLen(pair->value) + 1 /* for '=' */;
str = SysAllocStringLen(NULL, len);
strcpyW(str, pair->name);
strcatW(str, eqW);
strcatW(str, pair->value);
(*propset)->cProperties++;
(*propset)->guidPropertySet = DBPROPSET_DBINIT;
(*propset)->rgProperties[i].dwPropertyID = DBPROP_INIT_PROVIDERSTRING;
(*propset)->rgProperties[i].dwOptions = DBPROPOPTIONS_REQUIRED;
(*propset)->rgProperties[i].dwStatus = 0;
memset(&(*propset)->rgProperties[i].colid, 0, sizeof(DBID));
V_VT(&(*propset)->rgProperties[i].vValue) = VT_BSTR;
V_BSTR(&(*propset)->rgProperties[i].vValue) = str;
i++;
continue;
}
V_VT(&src) = VT_BSTR;
V_BSTR(&src) = pair->value;
VariantInit(&dest);
hr = VariantChangeType(&dest, &src, 0, descr->type);
if (FAILED(hr))
{
ERR("failed to init property %s value as type %d\n", debugstr_w(pair->name), descr->type);
return hr;
}
(*propset)->cProperties++;
(*propset)->guidPropertySet = DBPROPSET_DBINIT;
(*propset)->rgProperties[0].dwPropertyID = dbproperties[n].id;
(*propset)->rgProperties[0].dwOptions = dbproperties[n].options;
(*propset)->rgProperties[0].dwStatus = 0;
memset(&(*propset)->rgProperties[0].colid, 0, sizeof(DBID));
(*propset)->rgProperties[0].vValue = dest;
(*propset)->rgProperties[i].dwPropertyID = descr->id;
(*propset)->rgProperties[i].dwOptions = descr->options;
(*propset)->rgProperties[i].dwStatus = 0;
memset(&(*propset)->rgProperties[i].colid, 0, sizeof(DBID));
(*propset)->rgProperties[i].vValue = dest;
i++;
}
return S_OK;
}
/*** IDataInitialize methods ***/
static void datasource_release(BOOL created, IUnknown **datasource)
{
if (!created)
return;
IUnknown_Release(*datasource);
*datasource = NULL;
}
static HRESULT WINAPI datainit_GetDataSource(IDataInitialize *iface, IUnknown *outer, DWORD clsctx,
LPWSTR initstring, REFIID riid, IUnknown **datasource)
{
......@@ -519,65 +647,40 @@ static HRESULT WINAPI datainit_GetDataSource(IDataInitialize *iface, IUnknown *o
/* now set properties */
if (initstring)
{
WCHAR *eq, *start;
struct dbprops props;
hr = IUnknown_QueryInterface(*datasource, &IID_IDBProperties, (void**)&dbprops);
if (FAILED(hr))
{
ERR("provider doesn't support IDBProperties\n");
if (datasource_created)
{
IUnknown_Release(*datasource);
*datasource = NULL;
}
datasource_release(datasource_created, datasource);
return hr;
}
start = initstring;
while (start && (eq = strchrW(start, '=')))
hr = parse_init_string(initstring, &props);
if (FAILED(hr))
{
static const WCHAR providerW[] = {'P','r','o','v','i','d','e','r',0};
WCHAR *scol = strchrW(eq+1, ';');
BSTR value, name;
name = SysAllocStringLen(start, eq - start);
/* skip equal sign to get value */
eq++;
value = SysAllocStringLen(eq, scol ? scol - eq : -1);
/* skip semicolon if present */
if (scol) scol++;
start = scol;
datasource_release(datasource_created, datasource);
return hr;
}
if (!strcmpW(name, providerW))
hr = get_dbpropset_from_proplist(&props, &propset);
free_dbprop_list(&props);
if (FAILED(hr))
{
SysFreeString(name);
SysFreeString(value);
continue;
datasource_release(datasource_created, datasource);
return hr;
}
TRACE("property (name=%s, value=%s)\n", debugstr_w(name), debugstr_w(value));
hr = set_dbpropset(name, value, &propset);
SysFreeString(name);
SysFreeString(value);
if (FAILED(hr)) break;
hr = IDBProperties_SetProperties(dbprops, 1, propset);
IDBProperties_Release(dbprops);
free_dbpropset(1, propset);
if (FAILED(hr))
{
ERR("failed to set property, 0x%08x\n", hr);
if (datasource_created)
{
IUnknown_Release(*datasource);
*datasource = NULL;
}
break;
}
ERR("SetProperties failed, 0x%08x\n", hr);
datasource_release(datasource_created, datasource);
return hr;
}
IDBProperties_Release(dbprops);
}
return hr;
......
......@@ -148,7 +148,6 @@ static HRESULT WINAPI dbprops_SetProperties(IDBProperties *iface, ULONG set_coun
ok(set_count == 1, "got %u\n", set_count);
ok(IsEqualIID(&propsets->guidPropertySet, &DBPROPSET_DBINIT), "set guid %s\n", wine_dbgstr_guid(&propsets->guidPropertySet));
todo_wine
ok(propsets->cProperties == 2, "got propcount %u\n", propsets->cProperties);
if (propsets->cProperties == 2) {
......@@ -278,7 +277,6 @@ static void test_GetDataSource2(WCHAR *initstring)
dbinit = &dbinittest;
hr = IDataInitialize_GetDataSource(datainit, NULL, CLSCTX_INPROC_SERVER, initstring, &IID_IDBInitialize, (IUnknown**)&dbinit);
todo_wine
ok(hr == S_OK, "got %08x\n", hr);
IDataInitialize_Release(datainit);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment