多结果集IMultipleResult接口

在某些任务中,需要执行多条sql语句,这样一次会返回多个结果集,在应用程序就需要处理多个结果集,在OLEDB中支持多结果集的接口是IMultipleResult。

查询数据源是否支持多结果集

并不是所有数据源都支持多结果集,可以通过查询数据源对象的DBPROPSET_DATASOURCEINFO属性集中的DBPROP_MULTIPLERESULTS属性来确定,该值是一个按位设置的4字节的联合值。它可取的值有下面几个:

  • DBPROPVAL_MR_SUPPORITED:支持多结果集
  • DBPROPVAL_MR_SONCURRENT:支持多结果集,并支持同时打开多个返回的结果集(如果它不支持同时打开多个结果集的话,在打开下一个结果集之前需要关闭已经打开的结果集)
  • DBPROPVAL_MR_NOTSUPPORTED: 不支持多结果集
    这个属性可以通过接口IDBProperties接口的GetProperties方法来获取,该函数的原型如下:
    1
    2
    3
    4
    5
    HRESULT GetProperties (
    ULONG cPropertyIDSets,
    const DBPROPIDSET rgPropertyIDSets[],
    ULONG *pcPropertySets,
    DBPROPSET **prgPropertySets);

它的用法与之前的SetProperties十分类似
第一个参数是我们传入DBPROPIDSET数组元素的个数,第二个参数是一个DBPROPIDSET结构的参数,该结构的原型如下:

1
2
3
4
5
typedef struct tagDBPROPIDSET {
DBPROPID * rgPropertyIDs;
ULONG cPropertyIDs;
GUID guidPropertySet;
} DBPROPIDSET;

该结构与之前遇到的DBPROPSET类似,第一个参数是一个DBPROPID结构的数组的首地址,该值是一个属性值,表示我们希望查询哪个属性的情况,第二个参数表示我们总共查询多少个属性的值,第3个参数表示这些属性都属于哪个属性集。
接口方法的第三个参数返回当前我们总共查询到几个属性集的内容。
第四个参数返回具体查到的属性值。

多结果集接口的使用

多结果集对象的定义如下:

1
2
3
4
CoType TMultipleResults {
[mandatory] interface IMultipleResults;
[optional] interface ISupportErrorInfo;
}

一般在程序中,使用多结果集有如下步骤

  1. 查询数据源是否支持多结果集,如果不支持则要考虑其他的实现方案
  2. 如果它支持多结果集,在调用ICommandText接口的Execute方法执行SQL语句时,让其返回一个IMultipleRowset接口。
  3. 循环调用接口的GetResult方法获取结果集对象。
  4. 使用结果集对象

最后是一个完整的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
//判断是否支持多结果集
BOOL SupportMultipleRowsets(IOpenRowset *pIOpenRowset)
{
COM_DECLARE_BUFFER();
COM_DECLARE_INTERFACE(IDBInitialize);
COM_DECLARE_INTERFACE(IDBProperties);
COM_DECLARE_INTERFACE(IGetDataSource);

BOOL bRet = FALSE;

//定义相关结构用于获取关于多结果集的信息
DBPROPID dbPropId[2] = {0};
DBPROPIDSET dbPropIDSet[1] = {0};

dbPropId[0] = DBPROP_MULTIPLERESULTS;
dbPropIDSet[0].cPropertyIDs = 1;
dbPropIDSet[0].guidPropertySet = DBPROPSET_DATASOURCEINFO;
dbPropIDSet[0].rgPropertyIDs = dbPropId;

//定义相关结构用于接受返回的属性信息
ULONG uPropsets = 0;
DBPROPSET *pDBPropset = NULL;
//获取数据源对象
HRESULT hRes = pIOpenRowset->QueryInterface(IID_IGetDataSource, (void**)&pIGetDataSource);
COM_SUCCESS(hRes, _T("查询接口IGetDataSource失败,错误码为:%08x\n"), hRes);
hRes = pIGetDataSource->GetDataSource(IID_IDBInitialize, (IUnknown **)&pIDBInitialize);
COM_SUCCESS(hRes, _T("获取数据源对象失败,错误码为:%08x\n"), hRes);

//获取对应属性
hRes = pIDBInitialize->QueryInterface(IID_IDBProperties, (void**)&pIDBProperties);
COM_SUCCESS(hRes, _T("查询IDBProperties接口失败,错误码为:%08x\n"), hRes);
hRes = pIDBProperties->GetProperties(1, dbPropIDSet, &uPropsets, &pDBPropset);
COM_SUCCESS(hRes, _T("获取属性信息失败,错误码:%08x\n"), hRes);

//判断是否支持多结果集
if (pDBPropset[0].rgProperties[0].vValue.vt == VT_I4)
{
if (pDBPropset[0].rgProperties[0].vValue.intVal & DBPROPVAL_MR_CONCURRENT)
{
COM_PRINT(_T("支持多结果集\n"));
}else if (pDBPropset[0].rgProperties[0].vValue.intVal & DBPROPVAL_MR_SUPPORTED)
{
COM_PRINT(_T("支持多结果集\n"));
}else if (pDBPropset[0].rgProperties[0].vValue.intVal & DBPROPVAL_MR_NOTSUPPORTED)
{
COM_PRINT(_T("不支持多结果集\n"));
goto __CLEAR_UP;
}
else
{
COM_PRINT(_T("未知\n"));
goto __CLEAR_UP;
}
}

bRet = TRUE;
__CLEAR_UP:
SAFE_RELSEASE(pIDBInitialize);
SAFE_RELSEASE(pIDBProperties);
SAFE_RELSEASE(pIGetDataSource);

CoTaskMemFree(pDBPropset[0].rgProperties);
CoTaskMemFree(pDBPropset);

return bRet;
}

// 执行sql语句并返回多结果集对象
BOOL ExecSQL(LPOLESTR lpSQL, IOpenRowset *pIOpenRowset, IMultipleResults* &pIMultipleResults)
{
COM_DECLARE_BUFFER();
COM_DECLARE_INTERFACE(IDBCreateCommand);
COM_DECLARE_INTERFACE(ICommandText);
COM_DECLARE_INTERFACE(ICommandProperties);

BOOL bRet = FALSE;
DBPROP dbProp[2] = {0};
DBPROPSET dbPropset[1] = {0};
dbProp[0].colid = DB_NULLID;
dbProp[0].dwOptions = DBPROPOPTIONS_REQUIRED;
dbProp[0].dwPropertyID = DBPROP_UPDATABILITY;
dbProp[0].vValue.vt = VT_I4;
dbProp[0].vValue.intVal = DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_DELETE | DBPROPVAL_UP_INSERT;

//设置SQL语句
HRESULT hRes = pIOpenRowset->QueryInterface(IID_IDBCreateCommand, (void**)&pIDBCreateCommand);
COM_SUCCESS(hRes, _T("查询接口IDBCreateCommand失败,错误码:%08x\n"), hRes);
hRes = pIDBCreateCommand->CreateCommand(NULL , IID_ICommandText, (IUnknown**)&pICommandText);
COM_SUCCESS(hRes, _T("创建接口ICommandText失败,错误码:%08x"), hRes);
hRes = pICommandText->SetCommandText(DBGUID_DEFAULT, lpSQL);
COM_SUCCESS(hRes, _T("设置SQL语句失败,错误码为:%08x\n"), hRes);

//设置属性
hRes = pICommandText->QueryInterface(IID_ICommandProperties, (void**)&pICommandProperties);
COM_SUCCESS(hRes, _T("查询接口ICommandProperties接口失败,错误码:%08x\n"), hRes);

//执行SQL语句
hRes = pICommandText->Execute(NULL, IID_IMultipleResults, NULL, NULL, (IUnknown**)&pIMultipleResults);
COM_SUCCESS(hRes, _T("执行SQL语句失败,错误码:%08x\n"), hRes);

bRet = TRUE;
__CLEAR_UP:
SAFE_RELSEASE(pIDBCreateCommand);
SAFE_RELSEASE(pICommandText);
SAFE_RELSEASE(pICommandProperties);

return bRet;
}

int _tmain(int argc, TCHAR *argv[])
{
CoInitialize(NULL);
COM_DECLARE_BUFFER();
COM_DECLARE_INTERFACE(IOpenRowset);
COM_DECLARE_INTERFACE(IMultipleResults);
COM_DECLARE_INTERFACE(IRowset);

LPOLESTR pSQL = OLESTR("Select * From aa26 Where Left(aac031,2) = '11';\
Select * From aa26 Where Left(aac031,2) = '32';\
Select * From aa26 Where Left(aac031,2) = '21';");

if (!CreateSession(pIOpenRowset))
{
goto __EXIT;
}

if (!SupportMultipleRowsets(pIOpenRowset))
{
goto __EXIT;
}

if (!ExecSQL(pSQL, pIOpenRowset, pIMultipleResults))
{
goto __EXIT;
}

//循环取结果集
while (TRUE)
{
HRESULT hr = pIMultipleResults->GetResult(NULL, DBRESULTFLAG_DEFAULT, IID_IRowset, NULL, (IUnknown**)&pIRowset);
if (hr != S_OK)
{
break;
}
//后面的代码就是针对每个结果集来进行列的绑定与数据输出,在这就不列举出来了
__CLEAR_UP:
CoTaskMemFree(pdbColumn);
CoTaskMemFree(pColumsName);
FREE(pDBBinding);
FREE(pData);
pIAccessor->ReleaseAccessor(hAccessor, NULL);
SAFE_RELSEASE(pIColumnsInfo);
SAFE_RELSEASE(pIAccessor);
SAFE_RELSEASE(pIRowset);

_tsystem(_T("PAUSE"));
}

__EXIT:
SAFE_RELSEASE(pIOpenRowset);
SAFE_RELSEASE(pIMultipleResults);

CoUninitialize();
return 0;
}

最后贴出例子完整代码的链接:
源代码查看