专栏首页MasiMaro 的技术博文OLEDB 静态绑定和数据转化接口

OLEDB 静态绑定和数据转化接口

OLEDB 提供了静态绑定和动态绑定两种方式,相比动态绑定来说,静态绑定在使用上更加简单,而在灵活性上不如动态绑定,动态绑定在前面已经介绍过了,本文主要介绍OLEDB中的静态,以及常用的数据类型转化接口。

静态绑定

之前的例子都是根据返回的COLUMNINFO结构来知晓数据表中各项的具体信息,然后进行绑定操作,这个操作由于可以动态的针对不同的数据类型绑定为不同的类型,因此称之为动态绑定。动态绑定是建立在我们对数据库中表结构一无所知,而又需要对数据库进行编程,但是一般在实际的项目中开发人员都是知道数据库的具体结构的,而且一旦数据库设计好了后续更改的可能性也不太大,因此可以采取静态绑定的方式来减少编程的复杂度。 在进行静态绑定时,一般针对每个数据库表结构定义一个结构体用来描述表的各项数据,然后利用结构体的偏移来绑定到数据库中。

数据关系对应表

一般静态绑定需要将数据库表的各项数据与结构体中的成员一一对应,这个时候就涉及到数据库数据类型到C/C++中数据类型的转化,下表列举了常见的数据库类型到C/C++数据类型的转化关系

数据库类型

OLEDB 类型

C/C++类型

binary

DBTYPE_BYTES/DBTYPE_IUNKNOWN

BYTE[length]/BLOB

varbinary

DBTYPE_BYTES/DBTYPE_IUNKNOWN

BLOB

bit

DBTYPE_BOOL

VARIANT_BOOL

char

DBTYPE_STR

char[length]

varchar

DBTYPE_STR

char[length]

nvarchar

DBTYPE_WSTR

wchar_t[length]

nchar

DBTYPE_WSTR

wchar_t[length]

text

DBTYPE_STR/DBTYPE_IUNKNOWN

BLOB

image

DBTYPE_BYTES/DBTYPE_IUNKNOWN

BLOB

ntext

DBTYPE_WSTR/DBTYPE_IUNKNOWN

BLOB

tinyint

DBTYPE_UI1

BYTE

smallint

DBTYPE_I2

SHORT

int

DBTYPE_I4

LONG

bigint

DBTYPE_I8

LARGE_INTEGER

real

DBTYPE_R4

float

float

DBTYPE_R8

double

money

DBTYPE_CY

LARGE_INTEGER

numeric

DBTYPE_NUMERIC

typedef struct tagDB_NUMERIC {    BYTE precision;    BYTE scale;    BYTE sign;    BYTE val[16];} DB_NUMERIC;

decimal

DBTYPE_NUMERIC

typedef struct tagDB_NUMERIC {    BYTE precision;    BYTE scale;    BYTE sign;    BYTE val[16];} DB_NUMERIC;

sysname

DBTYPE_WSTR

wchar_t[length]

datetime

DBTYPE_DBTIMESTAMP

typedef struct tagDBTIMESTAMP {    SHORT year;    USHORT month;    USHORT day;    USHORT hour;    USHORT minute;    USHORT second;    ULONG fraction;}DBTIMESTAMP;

timestamp

DBTYPE_BYTES

BYTE[length]

uniqueidentifier

DBTYPE_GUID

GUID

实例

下面是一个静态绑定的例子

//静态绑定的结构
typedef struct _tag_DBSTRUCT
{
    DBSTATUS dbCodeStatus;
    ULONG uCodeLength;
    int nCode;

    DBSTATUS dbNameStatus;
    ULONG uNameLength;
    WCHAR szName[NAME_LENGTH];
}DBSTRUCT, *LPDBSTRUCT;

dbBindings[0].bPrecision = 0;
    dbBindings[0].bScale = 0;
    dbBindings[0].cbMaxLen = sizeof(int);
    dbBindings[0].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
    dbBindings[0].dwPart = DBPART_STATUS | DBPART_LENGTH | DBPART_VALUE;
    dbBindings[0].iOrdinal = pdbColumnInfo[0].iOrdinal;
    dbBindings[0].obStatus = offsetof(DBSTRUCT, dbCodeStatus);
    dbBindings[0].obLength = offsetof(DBSTRUCT, uCodeLength);
    dbBindings[0].obValue = offsetof(DBSTRUCT, nCode);
    dbBindings[0].wType = DBTYPE_I4;

    dbBindings[1].bPrecision = 0;
    dbBindings[1].bScale = 0;
    dbBindings[1].cbMaxLen = sizeof(WCHAR) * NAME_LENGTH;
    dbBindings[1].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
    dbBindings[1].dwPart = DBPART_STATUS | DBPART_LENGTH | DBPART_VALUE;
    dbBindings[1].iOrdinal = pdbColumnInfo[1].iOrdinal;
    dbBindings[1].obStatus = offsetof(DBSTRUCT, dbNameStatus);
    dbBindings[1].obLength = offsetof(DBSTRUCT, uNameLength);
    dbBindings[1].obValue = offsetof(DBSTRUCT, szName);
    dbBindings[1].wType = DBTYPE_WSTR;

    hRes = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 2, dbBindings, 0, &hAccessor, NULL);
    pdbStruct = (DBSTRUCT*)COM_ALLOC(sizeof(DBSTRUCT) * cRows);

    while (TRUE)
    {
        hRes = pIRowset->GetNextRows(DB_NULL_HCHAPTER, 0, cRows, &cRowsObtained, &prghRows);
        if (hRes != S_OK && cRowsObtained == 0)
        {
            break;
        }

        ZeroMemory(pdbStruct, sizeof(DBSTRUCT) * cRows);
        for (int i = 0; i < cRowsObtained; i++)
        {
            hRes = pIRowset->GetData(prghRows[i], hAccessor, &pdbStruct[i]);
            if (!FAILED(hRes))
            {
                COM_PRINTF(_T("%012d\t%s\n"), pdbStruct[i].nCode, pdbStruct[i].szName);
            }
        }

        pIRowset->ReleaseRows(cRowsObtained, prghRows, NULL, NULL, NULL);
    }

我们针对之前的行政区表来进行演示,在这个表中我们只查询其中的两列数据,与之前的例子相似,针对每列定义3项数据,分别是状态,长度和真实的数据,在绑定的时候就不需要计算总体需要内存的大小,行内存大小就是结构体的大小,在绑定的时候我们结构体成员在结构体中的偏移作为返回数据时各项在缓冲中的偏移。而在访问数据时就需要自己计算偏移,直接使用结构体中的成员即可。 从上面的例子,我总结了静态绑定和动态绑定之间的差别:

  1. 其实从本质上将动态绑定和静态绑定没有区别,都是分配一段缓冲作为行集的缓冲,然后在使用的时候进行偏移的计算
  2. 静态绑定是利用我们提前知道数据库的结构,实现通过结构体来安排各项在缓冲中的偏移所占内存的大小。
  3. 动态绑定中所有成员的分配和所占内存大小都是根据COLUMNINFO结构事后动态分配的,需要自己计算偏移。
  4. 相比于动态绑定来说,静态绑定不需要获取数据库的各项的属性信息,不需要自己计算各项的偏移,相对比较简单,适用于事先知道数据库的表结构,使用相对固定,一旦数据库结构改变就需要改变代码
  5. 动态绑定可以适用于几乎任何情形,可扩展性强,几乎不需要考虑数据库表结构变更问题。代码灵活,但是需要自己计算偏移,自己分配管理内存,相对来说对程序员的功力要求更高一些。

数据类型转化

数据库中数据类型繁多,而对应到具体的编程语言上有不同的展示方式,具体的语言中对同一种数据库类型有不同的数据类型对应,甚至有的可能并没有什么类型可以直接对应,这就涉及到一个从数据库数据类型到具体编程语言数据类型之间进行转换的问题,针对这一问题OLEDB提供了一个接口——IDataConvert 一般情况下任何数据类型都可以转化为相应格式的字符串,而对应的字符串又可以反过来转化为数据库中相应的数据类型。当然一些特殊转换也是允许的,比如:整型数据间的转换,浮点数间的转换等。这也是使用这个数据转化接口的主要原则。

数据转换接口的使用

  1. 使用COM标准的方式创建IDataConver接口(调用CreateInstance函数传入CLSID_OLEDB_CONVERSIONLIBRARY创建一个IID_IDataConvert接口)
  2. 接着调用该接口的DataConvert方法可以进行数据转化
  3. 调用接口的CanConvert可以知道两种数据类型之间能否进行转化。
  4. 调用GetConversionSize可以知道源数据类型转化为指定类型时需要的缓冲大小。

实例

这个例子相对比较简单,就简单的在之前打印数据库数据中加了一句转化为字符串的操作,然后打印,就不在文中展示了,具体的例子见我放到码云中的代码片段

例子代码:

  1. 静态绑定
  2. 数据类型转化

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

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java 学习笔记(4)——java 常见类

    上次提前说了java中的面向对象,主要是为了使用这些常见类做打算,毕竟Java中一切都是对象,要使用一些系统提供的功能必须得通过类对象调用方法。其实Java相比...

    Masimaro
  • 使用Python调用Nessus 接口实现自动化扫描

    之前在项目中需要接入nessus扫描器,研究了一下nessus的api,现在将自己的成果分享出来。 Nessus提供了丰富的二次开发接口,无论是接入其他系统还...

    Masimaro
  • WinSock WSAEventSelect 模型

    在前面我们说了WSAAsyncSelect 模型,它相比于select模型来说提供了这样一种机制:当发生对应的IO通知时会立即通知操作系统,并调用对应的处理函数...

    Masimaro
  • Java SE | 每日作业卷day13

    定义一个数组,数组中元素为:{24,69,80,57,13},将数组中的元素按照从小到大的顺序进行排序。

    剑走天涯
  • 1819: [JSOI]Word Query电子字典

    1819: [JSOI]Word Query电子字典 Time Limit: 10 Sec  Memory Limit: 64 MB Submit: 729  ...

    HansBug
  • 神器与神器:微软宣布VsCode支持Jupyter Notebook

    大家都知道Jupyter Notebook是一款编写Python的神器,然而编辑Jupyter Notebook离不开网页,很多本地的编辑器都不支持编译Note...

    HuangWeiAI
  • 【知识星球】猫猫狗狗与深度学习那些事儿

    欢迎大家来到《知识星球》专栏,这两天有三AI知识星球会更新一些猫狗相关的数据集和任务,可爱的猫猫狗狗对深度学习可是做出了不少的贡献呢。

    用户1508658
  • 使用一个特别设计的损失来处理类别不均衡的数据集

    本文是谷歌对CVPR ' 19上发表的一篇文章的综述,文章的标题是Class-Balanced Loss Based on Effective Number o...

    AI算法与图像处理
  • undo retention的思考(一)

    最近有个网友咨询我一个问题,是关于undo_retention的,对于这个参数没有过多关注,只是知道需要设置undo_retention搭配使用undotabl...

    jeanron100
  • 使用多数据中心部署来应对Kafka灾难恢复(一)使用多数据中心部署来应对灾难恢复

    数据中心宕机和数据丢失能导致企业损失很多收入或者完全停摆。为了将由于事故导致的宕机和数据丢失带来的损失最小化,企业需要制定业务可持续性计划和灾难恢复策略。

    扫帚的影子

扫码关注云+社区

领取腾讯云代金券