OLEDB static binding and data conversion interface

OLEDB provides static binding and dynamic binding. Compared with dynamic binding, static binding is simpler to use, but not as flexible as dynamic binding. Dynamic binding has been introduced earlier. , This article mainly introduces the static in OLEDB, as well as the commonly used data type conversion interface.

static binding

The previous examples are based on the returned COLUMNINFO structure to know the specific information of each item in the data table, and then perform the binding operation. This operation can be dynamically bound to different types for different data types, so it is called dynamic. bind. Dynamic binding is based on the fact that we know nothing about the table structure in the database, and we need to program the database, but generally in actual projects, developers know the specific structure of the database, and once the database is designed, the follow-up The possibility of change is not too large, so static binding can be adopted to reduce the complexity of programming.
When performing static binding, a structure is generally defined for each database table structure to describe the various data of the table, and then the offset of the structure is used to bind to the database.

Data relationship correspondence table

Generally, static binding needs to correspond the data of the database table with the members in the structure one by one. At this time, it involves the conversion of database data types to C/C++ data types. The following table lists common database types to C /C++ data type conversion relationship

database type OLEDB type C/C++ types
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

example

Here is an example of static binding

//静态绑定的结构
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. 数据类型转化

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325051801&siteId=291194637