1
0
Fork 0
mirror of synced 2025-03-07 03:53:26 +01:00

msado15: Store all data from provider.

This commit is contained in:
Alistair Leslie-Hughes 2023-03-19 15:27:36 +11:00 committed by Alexandre Julliard
parent 4ae5d2537b
commit 49f7059745

View file

@ -52,6 +52,7 @@ struct recordset
VARIANT filter;
DBTYPE *columntypes;
HACCESSOR *haccessors;
};
struct fields
@ -1204,6 +1205,10 @@ static void close_recordset( struct recordset *recordset )
{
ULONG row, col, col_count;
ULONG i;
IAccessor *accessor;
if (recordset->haccessors)
IRowset_QueryInterface(recordset->row_set, &IID_IAccessor, (void**)&accessor);
if ( recordset->row_set ) IRowset_Release( recordset->row_set );
recordset->row_set = NULL;
@ -1220,8 +1225,17 @@ static void close_recordset( struct recordset *recordset )
struct field *field = impl_from_Field( recordset->fields->field[i] );
field->recordset = NULL;
Field_Release(&field->Field_iface);
if (recordset->haccessors)
IAccessor_ReleaseAccessor(accessor, recordset->haccessors[i], NULL);
}
if (recordset->haccessors)
{
IAccessor_Release(accessor);
free(recordset->haccessors);
recordset->haccessors = NULL;
}
recordset->fields->count = 0;
Fields_Release( &recordset->fields->Fields_iface );
recordset->fields = NULL;
@ -1686,6 +1700,7 @@ static HRESULT create_bindings(IUnknown *rowset, struct recordset *recordset, DB
{
HRESULT hr;
IColumnsInfo *columninfo;
IAccessor *accessor;
DBORDINAL columns;
DBCOLUMNINFO *colinfo;
OLECHAR *stringsbuffer;
@ -1698,6 +1713,13 @@ static HRESULT create_bindings(IUnknown *rowset, struct recordset *recordset, DB
if (FAILED(hr))
return hr;
hr = IUnknown_QueryInterface(rowset, &IID_IAccessor, (void**)&accessor);
if (FAILED(hr))
{
IColumnsInfo_Release(columninfo);
return hr;
}
hr = IColumnsInfo_GetColumnInfo(columninfo, &columns, &colinfo, &stringsbuffer);
if (SUCCEEDED(hr))
{
@ -1706,6 +1728,7 @@ static HRESULT create_bindings(IUnknown *rowset, struct recordset *recordset, DB
offset = 1;
recordset->columntypes = malloc(sizeof(DBTYPE) * columns);
recordset->haccessors = calloc(1, sizeof(HACCESSOR) * columns );
/* Do one allocation for the bindings and append the DBOBJECTS to the end.
* This is to save on multiple allocations vs a little bit of extra memory.
@ -1769,6 +1792,10 @@ static HRESULT create_bindings(IUnknown *rowset, struct recordset *recordset, DB
bindings[i].obStatus = offset + sizeof(DBBYTEOFFSET);
offset += sizeof(DBBYTEOFFSET) + sizeof(DBBYTEOFFSET);
hr = IAccessor_CreateAccessor(accessor, DBACCESSOR_ROWDATA, 1, &bindings[i], 0, &recordset->haccessors[i], NULL);
if (FAILED(hr))
FIXME("IAccessor_CreateAccessor Failed 0x%0lx\n", hr);
}
*size = offset;
@ -1778,11 +1805,205 @@ static HRESULT create_bindings(IUnknown *rowset, struct recordset *recordset, DB
CoTaskMemFree(stringsbuffer);
}
IAccessor_Release(accessor);
IColumnsInfo_Release(columninfo);
return hr;
}
static HRESULT load_all_recordset_data(struct recordset *recordset, IUnknown *rowset, DBBINDING *bindings,
DBBYTEOFFSET datasize)
{
IRowset *rowset2;
DBORDINAL columns;
HRESULT hr;
DBCOUNTITEM obtained;
HROW *row = NULL;
int datarow = 0, datacol;
char *data;
columns = get_column_count(recordset);
/* Create the data array */
if (!resize_recordset( recordset, recordset->count ))
{
WARN("Failed to resize recordset\n");
return E_OUTOFMEMORY;
}
hr = IUnknown_QueryInterface(rowset, &IID_IRowset, (void**)&rowset2);
if (FAILED(hr))
{
WARN("Failed to get IRowset interface (0x%08lx)\n", hr);
return hr;
}
data = malloc (datasize);
if (!data)
{
ERR("Failed to allocate row data (%Iu)\n", datasize);
IRowset_Release(rowset2);
return E_OUTOFMEMORY;
}
hr = IRowset_GetNextRows(rowset2, 0, 0, 1, &obtained, &row);
while (hr == S_OK)
{
VARIANT copy;
for (datacol = 0; datacol < columns; datacol++)
{
hr = IRowset_GetData(rowset2, *row, recordset->haccessors[datacol], data);
if (FAILED(hr))
{
ERR("GetData Failed on Column %d (0x%08lx), status %Id\n", datacol, hr,
*(DBBYTEOFFSET*)(data + bindings[datacol].obStatus));
break;
}
VariantInit(&copy);
if ( *(DBBYTEOFFSET*)(data + bindings[datacol].obStatus) == DBSTATUS_S_ISNULL)
{
V_VT(&copy) = VT_NULL;
goto writedata;
}
/* For most cases DBTYPE_* = VT_* type */
V_VT(&copy) = bindings[datacol].wType;
switch(bindings[datacol].wType)
{
case DBTYPE_IUNKNOWN:
{
ISequentialStream *seq;
char unkdata[2048];
ULONG size = 4096, dataRead = 0, total = 0;
char *buffer = malloc(size), *p = buffer;
HRESULT hr2;
/*
* Cast directly to the object we specified in our bindings. As this object
* is referenced counted in some case and will error in GetData if the object
* hasn't been released.
*/
seq = *(ISequentialStream**)(data + bindings[datacol].obValue);
TRACE("Reading DBTYPE_IUNKNOWN %p\n", seq);
do
{
dataRead = 0;
hr2 = ISequentialStream_Read(seq, unkdata, sizeof(unkdata), &dataRead);
if (FAILED(hr2) || !dataRead) break;
total += dataRead;
memcpy(p, unkdata, dataRead);
p += dataRead;
if (total == size)
{
size *= 2; /* Double buffer */
buffer = realloc(buffer, size);
p = buffer + total;
}
} while(hr2 == S_OK);
if (recordset->columntypes[datacol] == DBTYPE_WSTR)
{
V_VT(&copy) = VT_BSTR;
V_BSTR(&copy) = SysAllocStringLen( (WCHAR*)buffer, total / sizeof(WCHAR) );
}
else if (recordset->columntypes[datacol] == DBTYPE_BYTES)
{
SAFEARRAYBOUND sab;
sab.lLbound = 0;
sab.cElements = total;
V_VT(&copy) = (VT_ARRAY|VT_UI1);
V_ARRAY(&copy) = SafeArrayCreate(VT_UI1, 1, &sab);
memcpy( (BYTE*)V_ARRAY(&copy)->pvData, buffer, total);
}
else
{
FIXME("Unsupported conversion (%d)\n", recordset->columntypes[datacol]);
V_VT(&copy) = VT_NULL;
}
free(buffer);
ISequentialStream_Release(seq);
break;
}
case DBTYPE_R4:
V_R4(&copy) = *(float*)(data + bindings[datacol].obValue);
break;
case DBTYPE_R8:
V_R8(&copy) = *(DOUBLE*)(data + bindings[datacol].obValue);
break;
case DBTYPE_I8:
V_VT(&copy) = VT_I8;
V_I8(&copy) = *(LONGLONG*)(data + bindings[datacol].obValue);
break;
case DBTYPE_I4:
V_I4(&copy) = *(LONG*)(data + bindings[datacol].obValue);
break;
case DBTYPE_WSTR:
{
V_VT(&copy) = VT_BSTR;
V_BSTR(&copy) = SysAllocString( (WCHAR*)(data + bindings[datacol].obValue) );
break;
}
case DBTYPE_DBTIMESTAMP:
{
SYSTEMTIME st;
DBTIMESTAMP *ts = (DBTIMESTAMP *)(data + bindings[datacol].obValue);
DATE d;
V_VT(&copy) = VT_DATE;
st.wYear = ts->year;
st.wMonth = ts->month;
st.wDay = ts->day;
st.wHour = ts->hour;
st.wMinute = ts->minute;
st.wSecond = ts->second;
st.wMilliseconds = ts->fraction/1000000;
hr = (SystemTimeToVariantTime(&st, &d) ? S_OK : E_FAIL);
V_DATE(&copy) = d;
break;
}
default:
V_I2(&copy) = 0;
FIXME("Unknown Type %d\n", bindings[datacol].wType);
}
writedata:
VariantInit( &recordset->data[datarow * columns + datacol] );
if ((hr = VariantCopy( &recordset->data[datarow * columns + datacol] , &copy)) != S_OK)
{
ERR("Column %d copy failed. Data %s\n", datacol, debugstr_variant(&copy));
}
VariantClear(&copy);
}
datarow++;
hr = IRowset_ReleaseRows(rowset2, 1, row, NULL, NULL, NULL);
if (FAILED(hr))
ERR("Failed to ReleaseRows 0x%08lx\n", hr);
hr = IRowset_GetNextRows(rowset2, 0, 0, 1, &obtained, &row);
}
free(data);
IRowset_Release(rowset2);
return S_OK;
}
static HRESULT WINAPI recordset_Open( _Recordset *iface, VARIANT source, VARIANT active_connection,
CursorTypeEnum cursor_type, LockTypeEnum lock_type, LONG options )
{
@ -1796,7 +2017,7 @@ static HRESULT WINAPI recordset_Open( _Recordset *iface, VARIANT source, VARIANT
DBBINDING *bindings;
DBBYTEOFFSET datasize;
FIXME( "%p, %s, %s, %d, %d, %ld Semi-stub\n", recordset, debugstr_variant(&source), debugstr_variant(&active_connection),
TRACE( "%p, %s, %s, %d, %d, %ld\n", recordset, debugstr_variant(&source), debugstr_variant(&active_connection),
cursor_type, lock_type, options );
if (recordset->state == adStateOpen) return MAKE_ADO_HRESULT( adErrObjectOpen );
@ -1860,6 +2081,21 @@ static HRESULT WINAPI recordset_Open( _Recordset *iface, VARIANT source, VARIANT
recordset->count = affected;
recordset->index = affected ? 0 : -1;
/*
* We can safely just return with an empty recordset here
*/
if (affected > 0)
{
hr = load_all_recordset_data(recordset, rowset, bindings, datasize);
if (FAILED(hr))
{
WARN("Failed to load all recordset data (%lx)\n", hr);
CoTaskMemFree(bindings);
IUnknown_Release(rowset);
return hr;
}
}
CoTaskMemFree(bindings);
ADORecordsetConstruction_put_Rowset(&recordset->ADORecordsetConstruction_iface, rowset);
@ -2476,6 +2712,7 @@ HRESULT Recordset_create( void **obj )
recordset->editmode = adEditNone;
VariantInit( &recordset->filter );
recordset->columntypes = NULL;
recordset->haccessors = NULL;
*obj = &recordset->Recordset_iface;
TRACE( "returning iface %p\n", *obj );