关注

金仓 KingbaseES Pro*C 迁移指南:从 Oracle 平滑迁移

目录

一、Pro*C 基础与 KingbaseES 兼容机制

二、KingbaseES Pro*C 对 Oracle 功能兼容范围

1. 连接管理

2. 数据类型与变量

3. 嵌入式 SQL 与游标

4. 动态 SQL

5. 嵌入式 PL/SQL

6. 错误处理

7. 高级特性

三、迁移前准备:适配度与系统环境评估

1. 适配度评估

2. 系统环境评估

四、工程搭建与迁移全流程

1. 运行库部署

2. 环境变量配置

3. Makefile 编译配置

4. 数据库连接配置

5. 迁移后验证

五、标准开发与测试代码示例

1. 数据库连接示例

2. 数组批量插入示例

3. 带指示器变量的查询

4. LOB 大字段读写

5. Oracle 动态 SQL 方法 4

6. 嵌入式 PL/SQL 块

六、迁移常见问题与处理建议

七、迁移总结


正文开始——

现如今国产化数据库替换已经是行业常态,很多企业早年上线的业务系统,大量采用 Oracle Pro*C 开发。这类嵌入式C语言数据库程序运行稳定、执行效率高,长期承载金融、政务、电信等行业的核心业务。但也正因年代久远、代码体量庞大,迁移改造一直是开发人员比较头疼的问题。金仓数据库KingbaseES专门针对这类存量程序,推出了Oracle兼容版Pro*C运行组件,不用大规模改写源码,仅调整环境依赖就能完成迁移,整体改造成本很低。下面这篇文章包括兼容特性、环境硬性要求、工程部署步骤、配置写法以及测试代码。

一、Pro*C 基础与 KingbaseES 兼容机制

简单来说,Pro*C就是在C语言代码中嵌入SQL语句。这种写法开发便捷、事务可控,不过普通C编译器无法识别内嵌的SQL语法,必须依靠专门的预编译工具,把后缀为.pc的文件转成标准C代码,之后再链接数据库运行库,程序才能正常访问数据库。

在传统Oracle环境里,我们一般使用Oracle自带的proc工具完成预编译。迁移到金仓数据库之后,很多人会误以为需要更换编译工具,实际并不是。金仓目前没有自研的Pro*C预编译程序,预编译环节依旧沿用Oracle的proc工具,改动只集中在运行阶段:把Oracle运行库替换成金仓提供的Pro*C运行库,以此做到语法、逻辑、调用方式全方位兼容。

我整理了金仓Pro*C的硬性部署规范,实际部署时必须遵守:

  • 操作系统仅支持64位Linux,适配x86_64、arm、mipsel、loongarch64常见服务器架构,Windows平台无法部署使用;

  • 驱动包结构简单,核心只有lib文件夹,存放所有运行依赖库文件;

  • 金仓不单独提供开发头文件,直接复用Oracle原有头文件,若业务代码不涉及SQLDA复杂操作,甚至可以不用引入头文件;

  • 预编译命令完全沿用Oracle写法,不需要修改原有编译脚本。

日常开发中常用的预编译命令不多,下面两种通用写法,适配普通SQL文件和带PL/SQL的代码文件:

# 常规SQL文件预编译
$ORACLE/bin/proc iname=sample.pc oname=sample.c dynamic=ORACLE
# 简化写法
proc sample.pc

# 含PL/SQL语义检查的预编译(需连接数据库校验语法)
proc sample.pc SQLCHECK=SEMANTICS userid=user/password

一个常见问题:预编译过程中如果提示系统头文件缺失,直接把系统头文件路径补充到pcscfg.cfg配置文件即可,该文件路径一般在$ORACLE_HOME/precomp/admin/目录下。

二、KingbaseES Pro*C 对 Oracle 功能兼容范围

兼容性永远是迁移工作的重中之重。兼容对照表,区分常用兼容功能和不支持特性,方便迁移前快速评估,避免后期踩坑。

1. 连接管理

常规数据库连接方式基本全部兼容,包含标准CONNECT连接、Oracle Net Services远程连接。同时支持多并发登录、显式连接、隐式连接,适合多会话、多数据库切换的业务场景,原有连接逻辑不用改动。

2. 数据类型与变量

开发中常用的宿主变量、指示器变量、VARCHAR、游标变量、结构体、指针变量都能正常使用,数据类型转换、常量求值也没有限制。需要注意,Universal ROWIDs、NCHAR字符类型以及国际化相关的全球化功能,金仓当前版本不兼容。

3. 嵌入式 SQL 与游标

基础增删改查、DDL语句、DML返回子句都能正常执行。游标、滚动游标、CURRENT OF行定位语法完全兼容,数组、结构体数组批量操作语法也没有改动。唯一需要注意,Oracle专属的优化器Hint、模拟CURRENT OF语法、隐式缓冲区插入等扩展功能不支持,迁移时需要手动剔除。

4. 动态 SQL

动态SQL是老项目高频使用的功能,金仓对Oracle动态方法4、ANSI动态方法4做到了完整兼容。不管是未知参数、未知查询列的动态语句,还是动态SQL混合PL/SQL的写法,都能正常运行。唯一限制是不支持动态SQL语句缓存机制。

5. 嵌入式 PL/SQL

代码里内嵌的PL/SQL匿名块、存储过程、函数调用无需改写,主变量、指示器变量传参逻辑保持不变。仅外部C程序调用PL/SQL的特殊写法不兼容,普通业务代码基本不受影响。

6. 错误处理

生产环境必备的错误捕获功能全部兼容,包括SQLCODE错误码、SQLSTATE状态位、SQLCA通信区以及WHENEVER异常跳转。为缩减适配成本,ORACA通信区、原始SQL语句抓取、完整错误详情查询这类小众功能没有适配。

7. 高级特性

针对生产级项目,金仓支持多线程运行、连接池、C++编译、LOB大字段读写。为了减少冗余适配,OCI高低版本接口、嵌入式OCI调用、X/Open开发规范这类Oracle底层接口全部不兼容。

这里提醒一句,官方文档明确规定:兼容表里没有标注的功能,一律默认不支持,评估阶段不要主观判定兼容,严格对照文档执行。

三、迁移前准备:适配度与系统环境评估

迁移不能直接上手部署,必须提前做两层评估,一层是代码功能适配评估,另一层是服务器环境评估,这两步能规避绝大多数报错问题。

1. 适配度评估

适配评估的方式很简单,对照官方兼容表逐条筛查业务代码。如果代码里包含不支持特性,提前做替换改造:删除SQL优化Hint、把嵌入式OCI调用改成标准嵌入式SQL、NCHAR统一替换为NVARCHAR2。从实测情况来看,市面上绝大多数常规业务Pro*C代码,基本不用改动就能迁移。

2. 系统环境评估

服务器环境的坑主要集中在编译器版本,官方文档对环境要求标注得十分严格:

  • 硬性要求64位Linux系统,拒绝Windows平台;

  • 金仓驱动默认基于gcc 4.8.5编译;

  • gcc5.1以上版本重构了C++底层库,新旧ABI不互通,混用会出现undefined symbol符号未定义报错。

高版本gcc编译程序时,增加宏定义强制使用旧版ABI,就能规避兼容问题:

-D_GLIBCXX_USE_CXX11_ABI=0

一定要保证应用编译环境、驱动编译环境的gcc版本和ABI模式一致,这是链接报错最常见的原因。

四、工程搭建与迁移全流程

整套迁移流程并不复杂,不需要改动预编译生成的C代码,只需要部署运行库、配置环境变量、修改编译脚本、填写数据库连接信息即可。

1. 运行库部署

解压官方提供的kbproc压缩包,自定义放置服务器目录,解压后仅包含lib库文件夹和sys_service.conf配置文件,没有多余冗余文件。

2. 环境变量配置

需要配置两个核心环境变量,一个指向配置文件目录,一个用于系统识别库文件路径,一般直接写入.bashrc永久生效:

# 配置文件所在路径
export KINGBASE_CONFDIR=/home/kingbase/kbproc/
# 运行时库搜索路径
export LD_LIBRARY_PATH=/home/kingbase/kbproc/lib:$LD_LIBRARY_PATH

配置完成执行source命令刷新,用echo打印变量,确认配置无误。

3. Makefile 编译配置

编译脚本只需要改动库依赖部分,删除原有Oracle库路径,替换为金仓运行库,官方标准模板如下:

PROC_LIB_DIR = /home/kingbase/kbproc/lib
DEST_LIB = -L$(PROC_LIB_DIR)
CC = gcc
CFLAGS = -O2 -Wall

test: test.c
   CC) $(CFLAGS) test.c -o test $(DEST_LIB) -lclntsh -lsqllib -ldl -Wl,-rpath=$(PROC_LIB_DIR)     $(

注意必须链接lclntsh、lsqllib两个库文件,彻底替换Oracle运行库,防止库冲突。

4. 数据库连接配置

Pro*C程序不再硬编码连接参数,统一读取sys_service.conf,配置格式和金仓DCI接口完全一致,写法简单直观:

[kingbase]
name = kingbase
drivername = kingbase
ip = 192.168.1.100
port = 54321
username = system
password = 123456
dbname = test

5. 迁移后验证

部署完成不要直接投产,按照官方要求做功能校验:先测试数据库连通性,再依次测试普通SQL、批量插入、动态SQL、PL/SQL代码、LOB大字段读写。对比Oracle环境下的执行结果、事务提交状态、错误返回码,确保业务行为完全一致。

五、标准开发与测试代码示例

下面代码是官方给出的标准测试demo,覆盖日常开发高频场景,可直接编译运行用于环境校验。

1. 数据库连接示例

#include <stdio.h>
#include <stdlib.h>
EXEC SQL INCLUDE SQLCA;

void do_connect() {
    EXEC SQL BEGIN DECLARE SECTION;
        char user[100] = "system";
        char pwd[100] = "123456";
        char dbname[100] = "kingbase";
    EXEC SQL END DECLARE SECTION;

    EXEC SQL CONNECT :user IDENTIFIED BY :pwd USING :dbname;
    if (SQLCODE != 0) {
        printf("connect error\n");
        exit(1);
    }
    printf("connect success\n");
}

2. 数组批量插入示例

void do_batch_insert() {
    EXEC SQL BEGIN DECLARE SECTION;
        int ids[7] = {1,2,3,9,95,2022,43001};
        char names[10][10] = {"ababab","abcabc","3d3d3d3d","","xkhxx","dynamic","dynamic3"};
    EXEC SQL END DECLARE SECTION;

    EXEC SQL INSERT INTO tab01 VALUES (:ids, :names);
    EXEC SQL COMMIT;
    printf("insert rows: %d\n", sqlca.sqlerrd[2]);
}

3. 带指示器变量的查询

void do_select_with_indicator() {
    EXEC SQL BEGIN DECLARE SECTION;
        int id = 1;
        char name[50];
        short ind_name;
    EXEC SQL END DECLARE SECTION;

    EXEC SQL SELECT name INTO :name:ind_name FROM tab01 WHERE id=:id;
    if (ind_name == -1) {
        printf("name is NULL\n");
    } else {
        printf("name: %s\n", name);
    }
}

4. LOB 大字段读写

#include <oci.h>
void do_lob_test() {
    OCIBlobLocator *blob;
    unsigned char buf[128] = "TEST_LOB_DATA";
    unsigned int amt = 12, offset = 1;

    EXEC SQL ALLOCATE :blob;
    EXEC SQL SELECT b INTO :blob FROM t_proc_lob FOR UPDATE;
    EXEC SQL LOB WRITE ONE :amt FROM :buf INTO :blob AT :offset;
    EXEC SQL FREE :blob;
}

5. Oracle 动态 SQL 方法 4

void do_dynamic_sql4() {
    char *sql = "select id,name from tab01 where id>=:id";
    SQLDA *bind_dp, *select_dp;

    bind_dp = SQLSQLDAAlloc(SQL_SINGLE_RCTX, 20, 10, 10);
    select_dp = SQLSQLDAAlloc(SQL_SINGLE_RCTX, 20, 10, 10);

    EXEC SQL PREPARE stmt FROM :sql;
    EXEC SQL DECLARE C CURSOR FOR stmt;
    EXEC SQL DESCRIBE BIND VARIABLES FOR stmt INTO bind_dp;
    EXEC SQL OPEN C USING DESCRIPTOR bind_dp;
    EXEC SQL DESCRIBE SELECT LIST FOR stmt INTO select_dp;

    for (;;) {
        EXEC SQL FETCH C USING DESCRIPTOR select_dp;
        if (SQLCODE != 0) break;
    }

    EXEC SQL CLOSE C;
    SQLSQLDAFree(SQL_SINGLE_RCTX, bind_dp);
    SQLSQLDAFree(SQL_SINGLE_RCTX, select_dp);
}

6. 嵌入式 PL/SQL 块

void do_plsql_block() {
    EXEC SQL BEGIN DECLARE SECTION;
        int acct = 1;
        double debit = 100;
        VARCHAR status[20];
    EXEC SQL END DECLARE SECTION;

    EXEC SQL EXECUTE
    DECLARE
        old_bal NUMBER;
    BEGIN
        SELECT bal INTO old_bal FROM accounts WHERE account_id=:acct;
        :status := 'PL/SQL EXEC SUCCESS';
    END;
    END-EXEC;
    status.arr[status.len] = '\0';
    printf("status: %s\n", status.arr);
}

六、迁移常见问题与处理建议

  1. 预编译提示头文件缺失:直接把系统头文件路径写入pcscfg.cfg配置文件;

  2. 编译链接出现undefined symbol:核对gcc版本,统一ABI模式,添加旧ABI兼容宏;

  3. 数据库连接失败:优先检查两个环境变量,核对配置文件内IP、端口、账号密码;

  4. 存在不兼容语法:提前修改代码,替换Oracle专属扩展写法;

  5. 运行时提示库文件加载失败:确认LD_LIBRARY_PATH包含金仓lib目录。

七、迁移总结

结合官方文档以及实操部署经验来看,金仓KingbaseES对Oracle Pro*C的兼容方案十分成熟。整套迁移不用改动业务源代码,预编译流程完全沿用Oracle工具,仅替换运行库、调整环境配置就能完成适配。常规连接、SQL执行、事务控制、动态SQL、PL/SQL、LOB字段等核心功能,都能稳定运行,完全满足企业生产要求。

转载自CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/lrq13965748542/article/details/160884615

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--