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

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

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

  • DBPROPVAL_MR_SUPPORITED:支持多结果集
  • DBPROPVAL_MR_SONCURRENT:支持多结果集,并支持同时打开多个返回的结果集(如果它不支持同时打开多个结果集的话,在打开下一个结果集之前需要关闭已经打开的结果集)
  • DBPROPVAL_MR_NOTSUPPORTED: 不支持多结果集

    这个属性可以通过接口IDBProperties接口的GetProperties方法来获取,该函数的原型如下:
HRESULT GetProperties (
ULONG cPropertyIDSets,
const DBPROPIDSET rgPropertyIDSets[],
ULONG *pcPropertySets,
DBPROPSET **prgPropertySets);

它的用法与之前的SetProperties十分类似

第一个参数是我们传入DBPROPIDSET数组元素的个数,第二个参数是一个DBPROPIDSET结构的参数,该结构的原型如下:

typedef struct tagDBPROPIDSET {
DBPROPID * rgPropertyIDs;
ULONG cPropertyIDs;
GUID guidPropertySet;
} DBPROPIDSET;

该结构与之前遇到的DBPROPSET类似,第一个参数是一个DBPROPID结构的数组的首地址,该值是一个属性值,表示我们希望查询哪个属性的情况,第二个参数表示我们总共查询多少个属性的值,第3个参数表示这些属性都属于哪个属性集。

接口方法的第三个参数返回当前我们总共查询到几个属性集的内容。

第四个参数返回具体查到的属性值。

多结果集接口的使用

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

CoType TMultipleResults {
[mandatory] interface IMultipleResults;
[optional] interface ISupportErrorInfo;
}

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

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

最后是一个完整的例子:

//判断是否支持多结果集
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;
}

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

[源代码查看](https://gitee.com/masimaro/codes/vypocjnkabdu6wz8gfh0m36# MultipleResults)


多结果集IMultipleResult接口的更多相关文章

  1. 通过Dapr实现一个简单的基于.net的微服务电商系统(十五)——集中式接口文档实现

    之前有小伙伴在评论区留言说如何集成swagger,最开始没有想透给了对方一个似是而非的回答.实际上后来下来想了一下,用.NET5 提供的Source Generator其实可以很方便的实现接口集成.今 ...

  2. 类集-collection接口

    类集就是一个动态的对象数组,与一般的对象数组不同,类集的对象类容可以随意扩充. 1,对象数组使用的时候会存在一个长度的限制,那么类集是专门解决这种限制的.使用类集可以向数组增加任意多的数据. 2,对象 ...

  3. nodejs:使用puppeteer在服务器中构建一个获取电影电视剧剧集的接口

    首先我们看下数据来源: 来源于这个网站:https://z1.m1907.cn/ 可以说这个网站上能找到很多你想看的很多电影或电视剧,最重要的是很多电影电视剧在别的网站是收费的,但是在这里看是免费的, ...

  4. 使用SpringDataJdbc的@Query注解实现自动映射结果集 ----- RowMapper接口

    使用@Query注解的时候,常常需要写sql来映射非域类的实例,通常的做法就是 实现 RowMapper接口,然后new实例一个一个的设置值进去...为此.出世了自动映射工具类 注意事项:此抽象类只是 ...

  5. ModelViewSet 视图集 实现接口

    一.创建项目 1.创建 项目 : django-admin startprojet drf 2. 创建 两个app   ------ app1 ,book python manage.py start ...

  6. JSON API免费接口

    来自:http://www.bejson.com/knownjson/webInterface/ 电商接口 京东获取单个商品价格接口: http://p.3.cn/prices/mgets?skuId ...

  7. 转:WebService通用接口

    看到许多中小项目的webservice接口的源代码,不禁有个吐槽的冲动.除了会用CXF,Axis2等神级框架,其他的懒得动了,都是Ctrl+V,Ctrl+C,把其他模块的Request,Respons ...

  8. 分享整理的免费API接口

    天气接口 聚合数据: http://op.juhe.cn/onebox/weather/query 用例 官方文档 来源:weather.com 百度接口: http://api.map.baidu. ...

  9. Tomcat集群如何同步会话

    Tocmat集群中最重要的交换信息就是会话消息,对某个tomcat实例某会话做的更改要同步到集群其他tomcat实例的该会话对象,这样才能保证集群所有实例的会话数据一致.在tribes组件的基础上完成 ...

随机推荐

  1. 根据枚举获取枚举的Description特性值

    首先定义一个枚举:两个值:已确认.未确认. public enum ConfirmStatusEnum { [Description("未确认")] unconfirmed = , ...

  2. 使用过多的递归出现错误,“System.StackOverflowException”类型的未经处理的异常在 mscorlib.dll 中发生

    class Program { static void Main(string[] args) { sub(0); }     private static void sub(int count) { ...

  3. AtCoder - 2566 优先队列

    Let N be a positive integer. There is a numerical sequence of length 3N, a=(a1,a2,…,a3N). Snuke is c ...

  4. 【原创】elasticsearch入门

    示例 示例一: 示例二: 示例三: 示例四: ES介绍 ElasticSearch是一个基于Lucene的搜索服务器.它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口.Ela ...

  5. org.hibernate.QueryException: Unable to resolve path [SecWilldosetdate.name],xxxxxxxx...异常处理

    今天在写hql语句的时候出现了这个错误,然后一直运行到执行hql这儿就出错了.页面报500. 原hql如下: String hql = "from SecWilldosetdate wher ...

  6. 【AC自动机】【字符串】【字典树】AC自动机 学习笔记

    blog:www.wjyyy.top     AC自动机是一种毒瘤的方便的多模式串匹配算法.基于字典树,用到了类似KMP的思维.     AC自动机与KMP不同的是,AC自动机可以同时匹配多个模式串, ...

  7. 【研究】Joomla二阶注入

    受影响Joomla版本:3.7.0 到 3.8.3 1.下载安装Joomla3.8.3,登录后台管理系统:http://127.0.0.1/joomla/administrator/index.php ...

  8. PIE SDK频率域滤波

    1.算法功能简介 频率域滤波的基本工作流程为:空间域图像的傅里叶变换→频率域图像→设计滤波器→傅里叶逆变换→其他应用. 低通滤波,对频率域的图像通过滤波器削弱或抑制高频部分而保留低频部分的滤波方法,可 ...

  9. java中的线程(2):如何正确停止线程之3种常见停止方式

    1.常见停止方式 自定义线程,其中含退出标志位,在run中判断它. 使用interrupt()方法中断线程 使用stop方法暴力终止(已经弃用) 2.使用标志位 class TestThread ex ...

  10. oracle 基础知识(十)----exp/imp--->>>>>expdp/impdp

    一,简介 存活下来的远古级别的导入导出软件exp/imp  ,软件多数使用于oracle 9i 之前 到了10g以后基本全面被数据库泵(Data Pump)取代,即expdp/impdp.本文会分别介 ...