oledb32: Support provider-specific properties in GetDataSource().
This commit is contained in:
parent
0036b8bf2e
commit
795845ff3d
|
@ -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
|
||||
};
|
||||
|
||||
|
||||
static HRESULT set_dbpropset(BSTR name, BSTR value, DBPROPSET **propset)
|
||||
struct dbprop_pair
|
||||
{
|
||||
struct list entry;
|
||||
BSTR name;
|
||||
BSTR value;
|
||||
};
|
||||
|
||||
struct dbprops
|
||||
{
|
||||
struct list props;
|
||||
unsigned int count;
|
||||
};
|
||||
|
||||
/* 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;
|
||||
return (min <= max) ? &dbproperties[n] : NULL;
|
||||
}
|
||||
|
||||
VariantInit(&dest);
|
||||
|
||||
V_VT(&src) = VT_BSTR;
|
||||
V_BSTR(&src) = value;
|
||||
|
||||
hr = VariantChangeType(&dest, &src, 0, dbproperties[n].type);
|
||||
if (FAILED(hr))
|
||||
static HRESULT get_dbpropset_from_proplist(struct dbprops *props, DBPROPSET **propset)
|
||||
{
|
||||
ERR("failed to init property %s value as type %d\n", debugstr_w(name), dbproperties[n].type);
|
||||
return hr;
|
||||
}
|
||||
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[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 = 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[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;
|
||||
|
||||
if (!strcmpW(name, providerW))
|
||||
{
|
||||
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 = get_dbpropset_from_proplist(&props, &propset);
|
||||
free_dbprop_list(&props);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
datasource_release(datasource_created, datasource);
|
||||
return hr;
|
||||
}
|
||||
|
||||
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;
|
||||
ERR("SetProperties failed, 0x%08x\n", hr);
|
||||
datasource_release(datasource_created, datasource);
|
||||
return hr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue