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

目录

[一、Pro*C 基础与 KingbaseES 兼容机制](#一、Pro*C 基础与 KingbaseES 兼容机制)

[二、KingbaseES Pro*C 对 Oracle 功能兼容范围](#二、KingbaseES Pro*C 对 Oracle 功能兼容范围)

[1. 连接管理](#1. 连接管理)

[2. 数据类型与变量](#2. 数据类型与变量)

[3. 嵌入式 SQL 与游标](#3. 嵌入式 SQL 与游标)

[4. 动态 SQL](#4. 动态 SQL)

[5. 嵌入式 PL/SQL](#5. 嵌入式 PL/SQL)

[6. 错误处理](#6. 错误处理)

[7. 高级特性](#7. 高级特性)

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

[1. 适配度评估](#1. 适配度评估)

[2. 系统环境评估](#2. 系统环境评估)

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

[1. 运行库部署](#1. 运行库部署)

[2. 环境变量配置](#2. 环境变量配置)

[3. Makefile 编译配置](#3. Makefile 编译配置)

[4. 数据库连接配置](#4. 数据库连接配置)

[5. 迁移后验证](#5. 迁移后验证)

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

[1. 数据库连接示例](#1. 数据库连接示例)

[2. 数组批量插入示例](#2. 数组批量插入示例)

[3. 带指示器变量的查询](#3. 带指示器变量的查询)

[4. LOB 大字段读写](#4. LOB 大字段读写)

[5. Oracle 动态 SQL 方法 4](#5. Oracle 动态 SQL 方法 4)

[6. 嵌入式 PL/SQL 块](#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的代码文件:

bash 复制代码
# 常规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,就能规避兼容问题:

bash 复制代码
-D_GLIBCXX_USE_CXX11_ABI=0

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

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

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

1. 运行库部署

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

2. 环境变量配置

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

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

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

3. Makefile 编译配置

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

bash 复制代码
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接口完全一致,写法简单直观:

bash 复制代码
[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. 数据库连接示例

cpp 复制代码
#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. 数组批量插入示例

cpp 复制代码
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. 带指示器变量的查询

cpp 复制代码
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 大字段读写

cpp 复制代码
#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

cpp 复制代码
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 块

cpp 复制代码
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字段等核心功能,都能稳定运行,完全满足企业生产要求。

相关推荐
jimy11 小时前
Oracle的always free oci实例,standard em2.1.micro,保活脚本
服务器·oracle
曹牧20 小时前
Oracle:视图排序
数据库·oracle
文档搬运工21 小时前
单独导出Oracle中的job
oracle
会编程的土豆1 天前
MySQL DDL(数据定义语言)总结
数据库·mysql·oracle
Irene19911 天前
Oracle SQL Developer:多租户架构(CDB/PDB)、表空间管理和用户权限管理
oracle
Yushan Bai1 天前
oracle exadata x9的存储节点重启问题分析
数据库·oracle
文档搬运工1 天前
RU 19.31安装
oracle
jimy11 天前
Oracle的oci实例vm.standard.e2.1.micro安装tailscale
服务器·安全·oracle
Irene19911 天前
Oracle 别名使用限制:同一SELECT子句中,不能识别前面定义的列别名
oracle