多结果集IMultipleResult接口

在某些任务中,需要执行多条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;
}

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


本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏jeremy的技术点滴

SSM项目脚手架

4564
来自专栏菩提树下的杨过

Spring Security笔记:登录尝试次数限制

今天在前面一节的基础之上,再增加一点新内容,默认情况下Spring Security不会对登录错误的尝试次数做限制,也就是说允许暴力尝试,这显然不够安全,下面的...

4515
来自专栏MasiMaro 的技术博文

枚举进程中的模块

在Windows中枚举进程中的模块主要是其中加载的dll,在VC上主要有2种方式,一种是解析PE文件中导入表,从导入表中获取它将要静态加载的dll,一种是利用查...

1432
来自专栏MasiMaro 的技术博文

windows 下文件的高级操作

本文主要说明在Windows下操作文件的高级方法,比如直接读写磁盘,文件的异步操作,而文件普通的读写方式在网上可以找到一大堆资料,在这也就不再进行专门的说明。

2323
来自专栏【转载】DRF+Vue+Mysql_生鲜超市系统

五、商品列表页

在goods文件夹下面新建view_base.py,为了区分django和django rest framework的view

2010
来自专栏Hadoop实操

如何使用Flume采集Kafka数据写入Kudu

1.5K2
来自专栏风中追风

redis 实现分布式锁的演进

比如说:每分钟要执行关闭未支付订单的定时任务,在集群的环境下,如果不做处理,每台服务器都会去执行这个定时任务,显然每个时间段的定时任务只需要执行一次,并不需要每...

7156
来自专栏Phoenix的Android之旅

Dagger2 Android应用:@Scope和@Subcomponent

这部分会介绍Dagger2中比较莫名的概念,同样也不涉及Android的具体代码。 Dagger2使用中的核心技巧包括@Subcomponent和@Scope,...

1032
来自专栏我是攻城师

在Lucene或Solr中实现高亮的策略

3795
来自专栏lgp20151222

学习sharding-jdbc 分库分表扩展框架

https://gitee.com/a247292980/sharding-jdbc

1323

扫码关注云+社区

领取腾讯云代金券