关键词
人大金仓、KingbaseES、odbc、数据类型
前期准备
Kingbase可选的工作模式有pg,oracle以及mysql三种模式,每种模式用于兼容对应的数据库。在本文中介绍在基于兼容pg、oracle数据类型的基础上兼容mysql。
首先需要重新创建mysql的库
- 通过./initdb -D ../data -U SYSTEM --enable-ci --dbmode=mysql初始化数据库集群以及指定数据库的工作模式为mysql。
- 使用createdb -U user -p 54321 userbase,指定名为userbase的数据库。
- 使用kingbase –D ../data开启数据库服务器。
MySQL兼容模式
在使用SQLDriverConnect等连接接口时,会调用ODBC驱动的中的KBCC_get_mode接口,在该接口中会去查询服务器端的工作模式,并根据查询到的结果更新连接句柄。在ODBC中,KConnectionClass连接句柄中有lmode_type参数用来指定ODBC的兼容模式,在原本:
#define DB_MODE_ORACLE 1
#define DB_MODE_PG 2
定义了oracle与pg的兼容模式,因此在前两者的基础上新增mysql模式:
#define DB_MODE_MYSQL 3
因此当使用ODBC与数据库服务器建立连接后,可获取到数据库服务器的兼容类型并保存到连接句柄的lmode_type参数中,在后续若涉及到对不同兼容模式是不同的处理方式的时候可以通过判断lmode_type的值而确定,若lmode_type的值为1则是oracle模式、2则是pg模式、3则是mysql模式。
如在SQLDescribeCol函数接口中会确定kingbase的数据类型而调用子接口kb_true_type,在子接口中会对连接句柄中的lmode_type参数的值进行判断,而确定出kingbase的数据类型。
MySQL兼容数据类型
在本次实现的数据类型的兼容上,主要类型有:
TINYTEXT 文本字符类型,最大长度为255B
MEDIUMTEXT 文本字符类型,最大长度为16MB
LONGTEXT 文本字符类型,最大长度为4GB
TINYBLOB 二进制字符类型,最大长度为255B
MEDIUMBLOB 二进制字符类型,最大长度16MB
LONGBLOB 二进制字符类型,最大长度4GB
兼容到kingbase中数据类型为:
TINYTEXT 文本字符类型,最大长度为255B
MEDIUMTEXT 文本字符类型,最大长度为16777215B
LONGTEXT 文本字符类型,最大长度为1GB
TINYBLOB 二进制字符类型,最大长度为255B
MEDIUMBLOB 二进制字符类型,最大长度16777215B
LONGBLOB 二进制字符类型,最大长度1GB
由于服务器端所支持的大对象等操作都是最大长度为1GB,因此在ODBC端实现数据兼容时也是与服务器端所设置的一样。
实现数据兼容主要方式:
- 从服务器端获取char列的大小,根据不同的数据类型进行设置;
- 转化类型为简明类型:TINYTEXT、MEDIUMTEXT、LONGTEXT为SQL_VARCHAR或SQL_LONGVARCHAR;TINYBLOB、MEDIUMBLOB、LONGBLOB为SQL_VARBINARY或SQL_LONGVARBINARY;;
- 转化类型属性为八字节;
- 根据不同的类型设置类型名;
- 将TINYTEXT、MEDIUMTEXT、LONGTEXT类型设置为可搜索的;
测试数据兼容
- 首先根据不同的数据类型创建不同的表;
- 使用SQLPrepare与SQLBindParameter接口将本地缓存进行参数绑定,而后使用SQLExecute进行插入;
- 使用接口SQLColAttribute查看数据类型的名字;
- 使用SQLGetData接口获取插入的数据;
- 释放。
示例:
void TestSetAndGetTinyBlob(void)
{
int sRtn;;
SQLLEN cbParam1;;
SQLLEN ind;;
int nLen = 255;;//max size 255
int nNum;;
char *param1, *buf, kbname[50];;
HSTMT hstmt = SQL_NULL_HSTMT;
HSTMT hstmtF = SQL_NULL_HSTMT;
rc = SQLAllocHandle(SQL_HANDLE_STMT, conn, &hstmt);
if (!SQL_SUCCEEDED(rc))
{
print_diag("failed to allocate stmt handle", SQL_HANDLE_DBC, conn);
exit(1);
}
rc = SQLAllocHandle(SQL_HANDLE_STMT, conn, &hstmtF);
if (!SQL_SUCCEEDED(rc))
{
print_diag("failed to allocate stmt handle", SQL_HANDLE_DBC, conn);
exit(1);
}
param1 = (char *)malloc(nLen * sizeof(char));;
memset(param1, 0, nLen);;
nNum = nLen;;
while (nNum--) {
param1[nNum] = 15 - nNum % 16;;
}
rc = SQLExecDirect(hstmt, (SQLCHAR *) "CREATE TEMPORARY TABLE kodbc_tinyblob_test(id int, blob_data tinyblob)", SQL_NTS);;
CHECK_STMT_RESULT(rc, "(kodbctest) SQLExecDirect failed1", hstmt);;
/* 插入一个blob对象 */
printf("(kodbctest) inserting blob object...\n");;
sRtn = SQLPrepare(hstmt, (SQLCHAR *) "INSERT INTO kodbc_tinyblob_test VALUES (1, ?)", SQL_NTS);;
CHECK_STMT_RESULT(sRtn, "(kodbctest) SQLPrepare failed", hstmt);;
/* 绑定blob参数 */
cbParam1 = nLen;;
sRtn = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT,
SQL_C_BINARY, /* 值类型 */
SQL_VARBINARY, /* 参数类型 */
nLen, /* 列大小 */
0, /* 如果是浮点数,代表对应字段精度 */
param1, /* 参数值缓存 */
0, /* 参数缓存字节数 */
&cbParam1 /* 表示字符串长度或NULL值的标识 */);;
CHECK_STMT_RESULT(sRtn, "(kodbctest) SQLBindParameter failed", hstmt);;
/* 执行 */
sRtn = SQLExecute(hstmt);;
CHECK_STMT_RESULT(sRtn, "(kodbctest) SQLExecute failed", hstmt);;
sRtn = SQLFreeStmt(hstmt, SQL_CLOSE);;
CHECK_STMT_RESULT(sRtn, "(kodbctest) SQLFreeStmt failed", hstmt);;
/* 读取结果 */
printf("(kodbctest)reading it back...\n");;
SQLExecDirect(hstmt, (SQLCHAR *) "SELECT * FROM kodbc_tinyblob_test", SQL_NTS);;
printf("(kodbctest)PrintResultMeta...\n");;
print_result_meta(hstmt);;
sRtn = SQLColAttribute(hstmt, 2, SQL_DESC_TYPE_NAME, kbname, sizeof(kbname), NULL, NULL);;
CHECK_STMT_RESULT(sRtn, "(kodbctest) SQLColAttribute failed", hstmt);;
printf("(kodbctest) SQL_DESC_TYPE_NAME: %s\n", kbname);;
SQLExecDirect(hstmtF, (SQLCHAR *) "SELECT * FROM kodbc_tinyblob_test", SQL_NTS);;
sRtn = SQLFetch(hstmtF);;
CHECK_STMT_RESULT(sRtn, "(kodbctest) SQLFetch failed", hstmtF);;
buf = param1;;
memset(buf, 0, nLen);;
sRtn = SQLGetData(hstmtF, 2, SQL_C_BINARY, buf, nLen, &ind);;
CHECK_STMT_RESULT(sRtn, "(kodbctest) SQLGetData failed", hstmtF);;
printf("(kodbctest) reading length:%d\n", (int)ind);;
//printhex(buf, ind);;
printf("\n");;
free(param1);;
sRtn = SQLFreeStmt(hstmt, SQL_CLOSE);;
CHECK_STMT_RESULT(sRtn, "(kodbctest) SQLFreeStmt failed", hstmt);;
sRtn = SQLFreeStmt(hstmtF, SQL_CLOSE);;
CHECK_STMT_RESULT(sRtn, "(kodbctest) SQLFreeStmt failed", hstmtF);;
}
参考资料
提供该题目相关内容在产品手册中可以系统学习的位置,例如:
《KingbaseES与MySQL的兼容性说明》 更多信息,参见help.kingbase.com.cn/v8/index.ht…