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 @@ ...@@ -29,6 +29,7 @@
#include "oledb_private.h" #include "oledb_private.h"
#include "wine/debug.h" #include "wine/debug.h"
#include "wine/list.h"
#include "wine/unicode.h" #include "wine/unicode.h"
WINE_DEFAULT_DEBUG_CHANNEL(oledb); WINE_DEFAULT_DEBUG_CHANNEL(oledb);
...@@ -346,12 +347,99 @@ static const struct dbproperty dbproperties[] = { ...@@ -346,12 +347,99 @@ static const struct dbproperty dbproperties[] = {
#endif #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; int min, max, n;
HRESULT hr;
min = 0; min = 0;
max = sizeof(dbproperties)/sizeof(struct dbproperty) - 1; max = sizeof(dbproperties)/sizeof(struct dbproperty) - 1;
...@@ -372,52 +460,92 @@ static HRESULT set_dbpropset(BSTR name, BSTR value, DBPROPSET **propset) ...@@ -372,52 +460,92 @@ static HRESULT set_dbpropset(BSTR name, BSTR value, DBPROPSET **propset)
max = n-1; max = n-1;
} }
if (min > max) return (min <= max) ? &dbproperties[n] : NULL;
{ }
*propset = NULL;
FIXME("unsupported property %s\n", debugstr_w(name));
return E_FAIL;
}
VariantInit(&dest);
V_VT(&src) = VT_BSTR;
V_BSTR(&src) = value;
hr = VariantChangeType(&dest, &src, 0, dbproperties[n].type); static HRESULT get_dbpropset_from_proplist(struct dbprops *props, DBPROPSET **propset)
if (FAILED(hr)) {
{ struct dbprop_pair *pair;
ERR("failed to init property %s value as type %d\n", debugstr_w(name), dbproperties[n].type); int i = 0;
return hr; HRESULT hr;
}
*propset = CoTaskMemAlloc(sizeof(DBPROPSET)); *propset = CoTaskMemAlloc(sizeof(DBPROPSET));
if (!*propset) if (!*propset)
{
VariantClear(&dest);
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
}
(*propset)->rgProperties = CoTaskMemAlloc(sizeof(DBPROP)); (*propset)->rgProperties = CoTaskMemAlloc(props->count*sizeof(DBPROP));
if (!(*propset)->rgProperties) if (!(*propset)->rgProperties)
{ {
VariantClear(&dest);
CoTaskMemFree(*propset); CoTaskMemFree(*propset);
*propset = NULL;
return E_OUTOFMEMORY; 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)->guidPropertySet = DBPROPSET_DBINIT;
(*propset)->rgProperties[0].dwPropertyID = dbproperties[n].id; (*propset)->rgProperties[i].dwPropertyID = descr->id;
(*propset)->rgProperties[0].dwOptions = dbproperties[n].options; (*propset)->rgProperties[i].dwOptions = descr->options;
(*propset)->rgProperties[0].dwStatus = 0; (*propset)->rgProperties[i].dwStatus = 0;
memset(&(*propset)->rgProperties[0].colid, 0, sizeof(DBID)); memset(&(*propset)->rgProperties[i].colid, 0, sizeof(DBID));
(*propset)->rgProperties[0].vValue = dest; (*propset)->rgProperties[i].vValue = dest;
i++;
}
return S_OK; return S_OK;
} }
/*** IDataInitialize methods ***/ /*** 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, static HRESULT WINAPI datainit_GetDataSource(IDataInitialize *iface, IUnknown *outer, DWORD clsctx,
LPWSTR initstring, REFIID riid, IUnknown **datasource) LPWSTR initstring, REFIID riid, IUnknown **datasource)
{ {
...@@ -519,65 +647,40 @@ static HRESULT WINAPI datainit_GetDataSource(IDataInitialize *iface, IUnknown *o ...@@ -519,65 +647,40 @@ static HRESULT WINAPI datainit_GetDataSource(IDataInitialize *iface, IUnknown *o
/* now set properties */ /* now set properties */
if (initstring) if (initstring)
{ {
WCHAR *eq, *start; struct dbprops props;
hr = IUnknown_QueryInterface(*datasource, &IID_IDBProperties, (void**)&dbprops); hr = IUnknown_QueryInterface(*datasource, &IID_IDBProperties, (void**)&dbprops);
if (FAILED(hr)) if (FAILED(hr))
{ {
ERR("provider doesn't support IDBProperties\n"); ERR("provider doesn't support IDBProperties\n");
if (datasource_created) datasource_release(datasource_created, datasource);
{
IUnknown_Release(*datasource);
*datasource = NULL;
}
return hr; return hr;
} }
start = initstring; hr = parse_init_string(initstring, &props);
while (start && (eq = strchrW(start, '='))) if (FAILED(hr))
{ {
static const WCHAR providerW[] = {'P','r','o','v','i','d','e','r',0}; datasource_release(datasource_created, datasource);
WCHAR *scol = strchrW(eq+1, ';'); return hr;
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)) hr = get_dbpropset_from_proplist(&props, &propset);
free_dbprop_list(&props);
if (FAILED(hr))
{ {
SysFreeString(name); datasource_release(datasource_created, datasource);
SysFreeString(value); return hr;
continue;
} }
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); hr = IDBProperties_SetProperties(dbprops, 1, propset);
IDBProperties_Release(dbprops);
free_dbpropset(1, propset); free_dbpropset(1, propset);
if (FAILED(hr)) if (FAILED(hr))
{ {
ERR("failed to set property, 0x%08x\n", hr); ERR("SetProperties failed, 0x%08x\n", hr);
if (datasource_created) datasource_release(datasource_created, datasource);
{ return hr;
IUnknown_Release(*datasource);
*datasource = NULL;
}
break;
}
} }
IDBProperties_Release(dbprops);
} }
return hr; return hr;
......
...@@ -148,7 +148,6 @@ static HRESULT WINAPI dbprops_SetProperties(IDBProperties *iface, ULONG set_coun ...@@ -148,7 +148,6 @@ static HRESULT WINAPI dbprops_SetProperties(IDBProperties *iface, ULONG set_coun
ok(set_count == 1, "got %u\n", set_count); ok(set_count == 1, "got %u\n", set_count);
ok(IsEqualIID(&propsets->guidPropertySet, &DBPROPSET_DBINIT), "set guid %s\n", wine_dbgstr_guid(&propsets->guidPropertySet)); 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); ok(propsets->cProperties == 2, "got propcount %u\n", propsets->cProperties);
if (propsets->cProperties == 2) { if (propsets->cProperties == 2) {
...@@ -278,7 +277,6 @@ static void test_GetDataSource2(WCHAR *initstring) ...@@ -278,7 +277,6 @@ static void test_GetDataSource2(WCHAR *initstring)
dbinit = &dbinittest; dbinit = &dbinittest;
hr = IDataInitialize_GetDataSource(datainit, NULL, CLSCTX_INPROC_SERVER, initstring, &IID_IDBInitialize, (IUnknown**)&dbinit); hr = IDataInitialize_GetDataSource(datainit, NULL, CLSCTX_INPROC_SERVER, initstring, &IID_IDBInitialize, (IUnknown**)&dbinit);
todo_wine
ok(hr == S_OK, "got %08x\n", hr); ok(hr == S_OK, "got %08x\n", hr);
IDataInitialize_Release(datainit); 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