加速从基于 Oracle 数据库的 Pro*C 应用程序到 DB2 嵌入式 SQL C 的迁移

作为 DB2® 中的 Oracle 兼容性的持续增强的一部分,自 DB2 Linux®, UNIX®, and Windows® (LUW) 9.7 fixpack 5 版本起,DB2 中受支持的 Oracle Pro*C 特性的数量开始增加。随着 DB2 V 10.1 中相关特性的不断增加,迁移现有 Pro*c 应用程序成为了一项挑战。本文中的技巧和技术有助于加速 Pro*c 的迁移。文中的所有内容都基于一些实时迁移项目。

Gaurav Shukla, DB2 顾问, IBM

Gaurav Shukla 是 IBM India Software 实验室的一名 DB2 顾问,曾参与了很多从端对端 Oracle 到 DB2 的迁移活动,其中包括很多从 Pro*C 到 DB2 嵌入式 SQL SQC 项目的迁移。早些时候,他曾是 Optim pureQuery(JDBC 客户端优化器)开发组的成员之一。



2012 年 11 月 12 日

免费下载:IBM® DB2® Express-C 10.1 免费版 或者 DB2® 10.1 for Linux®, UNIX®, and Windows® 试用版
下载更多的 IBM 软件试用版,并加入 IBM 软件下载与技术交流群组,参与在线交流。

DB2 LUW 上的嵌入式 SQL 的简介

嵌入式 SQL 是执行嵌入在宿主语言应用程序中的 SQL 语句的一种方式。嵌入式 SQL 数据库应用程序首先连接到数据库,然后执行这些嵌入式 SQL。这些 SQL 可以动态执行,也可以静态执行。最常用的宿主语言是 C 和 C++。在可以编译应用程序之前,构建嵌入式 SQL 应用程序涉及两个主要步骤:PREP(或 PRECOMPILE)和 BIND

命令 PREP 用于读取源代码、解析嵌入式 SQL 并将它转换成 DB2 运行时服务 API 调用,然后将输出写入一个新的源文件中。BIND 用于将应用程序中的 SQL 语句绑定到目标数据库。默认情况下,绑定操作是 PRECOMPILE 步骤自身完成的,但也可以将它扩展为单独的一个步骤。

完成绑定后,就生成了针对 SQL 语句的访问计划,并将这些计划存储在目标数据库内的一个包中。完成 PRECOMPILEBIND 步骤之后,就可利用特定于宿主语言的开发工具对应用程序进行编译和链接。稍后我们会讨论获得嵌入式 SQL 支持的这些步骤的语法。32 位和 64 位的嵌入式 SQL 应用程序都可以利用嵌入式 SQL 源代码进行开发。在 Oracle 数据库中,基于 C/C++ 的嵌入式 SQL数据库应用程序支持是 Pro*C/C++;在 DB2 LUW 中,则为嵌入式 SQL C/C++

在本文当中,我们将了解嵌入式 SQL C/C++ 和 Pro*C/C++ 之间的主要差别,但我们会重点介绍将基于 Pro*C/C++ 的应用程序从 Oracle 迁移到 DB2 LUW 的一些技巧和技术。请参阅最新的 DB2 LUW 文档,了解目前受支持的特性。


DB2 上的 Oracle 兼容性支持

通常,将应用程序从一个 RDBMS 迁移到另一个 RDBMS 非常困难。但是,自 DB2 LUW 9.7 fixpack 5 版本起,增加了一些新的 SQL 和 PL/SQL 功能,这些功能提高了从 Oracle 数据库迁移到 DB2 的速度。在最新的 DB2 LUW(DB2 LUW 10.1)版本中,这些功能得到了进一步的增强。

对这些功能的支持是原生支持。DB2 为数据类型、标量函数、包、语言元素、内置包和 PL/SQL 过程语言提供了原生支持。通过本地支持,在 DB2 引擎中,能够采用与其他 DB2 原生语言元素相同的完整性和效能级别提供对这些功能的支持。这样,就可以利用 DB2 提供的原有速度和效率来执行它们。Oracle 的兼容特性消除了转换大多数 Oracle 数据库对象(包括 PL/SQL)的需求,并使得将为 Oracle 编写的应用程序迁移到 DB2 的任务变得更轻松。

要启用一个或多个 DB2 兼容特性,则需要使用 DB2_COMPATIBILITY_VECTOR 注册表变量。该变量是一个十六进制值,该变量中的每个位代表一个 DB2 兼容特性。利用这个向量,可以选择启用特定功能(通过设置 DB2_COMPATIBILITY_VECTOR 的特定位),也可以启用所有特性,将这个注册表变量设置为 ORA。可以通过 db2set 设置此变量,建议在创建数据库之前设置该变量,并在数据库生命周期期间持续保持所选的兼容水平。关于该变量的详细讨论超出了本文的讨论范围(请参阅 DB2_COMPATIBILITY_VECTOR 注册表变量,获得有关的更多信息)。


Pro*C/C++ 支持

如上所述,DB2 LUW 提供了许多兼容特性,这些特性有助于将基于 Pro*C/C++ 的应用程序从 Oracle 迁移到 DB2 中的嵌入式 SQL C/C++。通过将 PRECOMPILE 的选项 COMPATIBILITY_MODE 设置为 ORA,可以启用这些兼容特性。例如,对于名为 myapp1.sqc 的文件,可以通过运行 db2 PRECOMPILE myapp1.sqc BINDFILE COMPATIBILITY_MODE ORA 命令来启用兼容特性。有关启用迁移兼容性的更多内容,请参阅 启用针对迁移的兼容特性


Oracle Pro*C/C++ 和嵌入式 SQL C/C++ 的主要区别

让我们来查看一下 Oracle Pro*C/C++ 和嵌入式 SQL C/C++ 之间的一些主要差别:

  • DB2 中的静态包支持:在 DB2 LUW 中,可以采用两种方式执行 SQL 语句:静态和动态。对于静态执行,需要在 PRECOMPILE(预编译)时了解语句语法(必须在 PRECOMPILE 时了解 SQL 语句中引用的列名称和表)。PRECOMPILE 为 SQL 语句生成访问计划,并将其存储在数据库中定义的包中。Oracle Pro*C/C++ 语句无法静态执行上述语句。Oracle Pro*C/C++ 仅支持动态 SQL 语句执行。动态执行的 SQL 语句是已经构建/准备好的,在运行时执行。由于静态执行的性能优于动态执行,因此,DB2 LUW 中的嵌入式 SQL 应用程序的表现非常良好。
  • 包维护:为静态执行创建的包存储在数据库中,所以,如果嵌入式 SQL 语句中发生任何变化,都需要重新绑定包。仅对静态 SQL 执行有这样的要求,对动态 SQL 执行没有这样的要求。如果存储在包中的 SQL 语句中的数据库对象引用发生了改变,那么该包需要重新绑定。
  • PRECOMPILE 阶段需要数据库连接:在 PRECOMPILE 阶段,需要数据库连接。

从 Pro*C/C++ 迁移到嵌入式 SQL C/C++ 的样例

注意:此处提供的示例主要是一些代码片段,不能作为单独的样例进行编译。我们使用的是 DB2 LUW 10.1。

  1. 先决条件:
  2. 迁移:
    • 重命名 Pro*C/C++ 应用程序,采用嵌入式 SQL 程序的扩展名(例如,对于 Pro*C 代码,请将扩展名从 *.pc 更改为 *.sqc,比如 mv myappl.pc myappl.sqc。
    • 利用以下命令连接到数据库
      db2 connect to sample user newton  using password

    • PRECOMPILE 嵌入式 SQL 程序(指定 bindfile 将会在本地创建 bindfile (myapp1.bnd),并需要手动将其添加到数据库中:db2 prep myapp1.sqc bindfile COMPATIBILITY_MODE ORA,将此作为下一个步骤)。
    • 如果 PRECOMPILE 步骤报错,则需要在继续后面操作之前修复这些错误。如果 PRECOMPILE 成功,则会与绑定文件一起生成一个 .c 文件 (myapp1.c)。
    • 现在将所生成的 bindfile 绑定到应用程序使用的数据库(这是上面第 2 步中连接的数据库)。
    • 使用嵌入式 SQL C 支持的编译器来编译生成的 .c 程序,例如,在 Linux® 上,编译命令可能是:
      gcc -o myapp1.exe -I${HOME}/sqllib/include -L${HOME}/sqllib/lib
          -ldb2 myapp1.c
    • 指定正确的 include 和库路径。
    • 利用 db2 terminate 终止 DB2 连接。
    • 现在准备使用应用程序的二进制格式: ./myapp1.exe [argument1, argument2,]

常见实时场景和解决方案

  • 维护 DB2 与 Oracle 之间的通用代码基:通常需要维护 Oracle 与 DB2 LUW 之间的通用代码库。通过在 DB2 中添加 Oracle 兼容支持,该维护变得很简单。不过,可能会导致 DB2 上的某些类似功能的支持不可用。在这种情况下,可以采用有条件的 #ifdef 预处理器结构。
    清单 1. 有条件的 #ifdef 预处理器结构的样例代码
    for (;;) { 
                printf("fetch\n"); 
                EXEC SQL FETCH cur INTO :c1, :c2;
    #ifdef ORA 
                if (sqlca.sqlcode == 1403) { 
    #elif DB2 
                if (sqlca.sqlcode == 100) { 
    #endif 
                    break; 
                } 
            printf("%d %s\n", c1, c2); 
            } EXEC SQL CLOSE cur; 
    #ifdef ORA
            EXEC SQL COMMIT WORK RELEASE; 
    #elif DB2 
            EXEC SQL COMMIT; 
            EXEC SQL CONNECT RESET; 
    #endif

    完成所有这类更改之后,PRECOMPILE 该程序,如下所示(假设将样例代码命名为 sample_ifdef.sqc):

    db2 "prep sample_ifdef.sqc bindfile package using sample_ifdef preprocessor 
    \"cl /P /DDB2\" COMPATIBILITY_MODE ORA"

    在使用 AIX (xlC) 的情况下,利用 xlC -P -DDB2=1 替代了 cl /P /DDB2。在编译器选项是特定于平台的选项时,需要检查这些选项。P 选项通常意味着预处理器。

  • 利用 C 宏:如果应用程序采用了 C 宏 (#define),则需采用以下内容。
    清单 2. 采用 C 宏功能的应用程序的样例代码
    #define _MYSHORT_  short
    #define MAX_LENGTH (128)
    ...
    int main (...)
    {
        EXEC SQL BEGIN DECLARE SECTION
             _MYSHORT_ c1_empno;
             char      c2_empname[MAX_LENGTH+1];
        EXEC SQL END DECLARE SECTION
        ...
    }

    DB2 的 PRECOMPILE 支持 PREPROCESSOR 选项,允许通过 C 编译器的预处理器来解析嵌入式 SQL 程序,从而扩展宏,然后调用嵌入式 SQL 分析器来处理 EXEC SQL。以下示例进行了相关说明(在 Linux 上)。

    db2 connect to sample
    db2 prep myapp1.sqc bindfile PREPROCESSOR 
    "'gcc -E -o myapp1.i -I${HOME}/sqllib/include'"
    db2 bind macro.bnd
    gcc -o macro -I${HOME}/sqllib/include -L${HOME}/sqllib/lib -ldb2 macro.c
    db2 terminate
  • 如果应用程序使用了一个复合 SQL,那么可以尝试采用下列代码。
    清单 3. 采用复合 SQL 的应用程序的样例代码
    execute
    DECLARE
            t_x VARCHAR2(10);
        ……
        BEGIN
        SELECT….  INTO t_x  FROM…… ;
        Update ….  WHERE;
        ………..
        commit;
        end;
    end-exec;

    在 DB2 的嵌入式 SQL C/C++ 中,将这些语句转换为动态 SQL,如下所示:

    strcpy (plsql, "declare ... begin ... end;");
    EXEC SQL PREPARE stmt FROM :plsql;
    EXEC SQL EXECUTE stmt into :xxx, :xxx using :xxx, :xxx;
  • DB2CI 支持(类似于 Oracle 的 OCI):B2 支持 DB2CI,这与 Oracle 的 OCI 类似。因此,大多数 OCI 能够在 DB2 上运行。然而,它与 OCI 支持还是有一个很大的区别。与 Oracle 不同,OCI 和嵌入式 SQL 不能处于同一个源文件中。作为解决方法之一,可将代码的整个源文件转换成 DB2CI 或者嵌入式 SQL C/C++。有关的更多信息,请参阅 DB2CI 应用程序开发
  • 采用 DESCRIPTOR:如果应用程序采用的是 DESCRIPTOR,如下所示:
    EXEC SQL DECLARE select_stmt  statement
    EXEC SQL ALLOCATE DESCRIPTOR 'out'; 
    EXEC SQL ALLOCATE DESCRIPTOR 'in';

    那么,在 DB2 嵌入式 SQL C/C++ 中,可以使用 DESCRIBE INPUT/DESCRIBE OUTPUT 语句。请参阅 DESCRIBE INPUT 语句DESCRIBE OUTPUT 语句,了解有关的更多信息。

    类似的,如果应用程序采用的是 DESCRIPTOR 语法:EXEC SQL FETCH select_cursor INTO DESCRIPTOR 'out'。参见 USING DESCRIPTORS 语法:FETCH 语句

  • 在多线程应用程序中采用上下文:对于具有嵌入式 SQL 上下文支持的多线程应用程序,应用程序可从多个线程执行 SQL 语句。可以将上下文定义为一个环境,在该环境中,应用程序将运行所有的 SQL 语句和 API 调用。所有连接、工作单元和其他数据库资源都与某个特定的上下文相关。因此,如果应用程序在 Pro*C/C++ 中采用上下文,比如: EXEC SQL CONTEXT USE :my_context; ,则应该使用 嵌入式 SQL 应用程序中的并发事务和多线程数据库访问 中提到的上下文 API。
  • DB2 10.1 中添加了许多 Oracle Pro*C/C++ 兼容特性,其中包括:
    • C 数组主机变量
    • INDICATOR 变量数组
    • 新的 CONNECT 语句语法
    • 利用双引号指定 include 文件名
    • VARCHAR 类型的简单类型定义
    • BIND 命令上的 GENERIC 选项的 STATICASDYNAMIC 字符串
    • 在 PREPARE 语句中使用字符串字面值
    • WHENEVER 语句中的 BREAK 操作

    请参阅 启用针对迁移的兼容特性,了解有关的详细信息。


常见错误

  • SQL0805N Package "XXX.DUMMY 0X514175474B644C62" was not found (SQLSTATE=51002):DB2 嵌入式 SQL 需要将应用程序作为包绑定到数据库服务器中,应用程序需要在执行运行时期间连接到该服务器。如果 DB2 BIND 没有在数据库服务器上运行,则会出现此错误。此外,在执行 BIND 时,要确保连接到了正确的数据库,这样才会仅在预期的数据库中创建该包。
  • SQL0818N A timestamp conflict occurred. SQLSTATE=51003 :通常,在重新编译应用程序但没有刷新 bindfile 时,才会出现此错误。请使用最新的 bindfile 来执行 DB2 BIND

限制

  • 使用指针作为主机变量:嵌入式 SQL 不支持在 DECLARE SECTION 下使用指针作为主机变量。在提供这些变量作为 EXEC SQL 中的任何 SQL 的输入之前,应用程序应该使用非指针变量。
  • 了解嵌入式 SQL C/C++ 应用程序的字符集上的限制:使用 C 和 C++ 编写嵌入式 SQL 应用程序的字符集上的限制

结束语

通过阅读本文,您将:

  • 了解如何将 Pro*C/C++ 迁移到嵌入式 SQL C/C++
  • 更好地理解 DB2 中支持的 Pro*C/C++ 特性
  • 利用文中提供的技巧和技术来加快应用程序的迁移速度
  • 尝试执行自己的迁移。

参考资料

学习

获得产品和技术

  • 利用可从 developerWorks 直接下载的 评估 IBM 产品试用版软件 构建您的下一个开发项目。
  • 现在可以免费使用 DB2。下载 IBM 软件下载:IBM DB2 Express-C 10.1,这是为社区提供的免费 DB2 Express Edition 版本,它提供了与 DB2 Express Edition 相同的核心数据特性,还为构建和部署应用程序提供了一个坚实的基础。

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Information Management
ArticleID=845309
ArticleTitle=加速从基于 Oracle 数据库的 Pro*C 应用程序到 DB2 嵌入式 SQL C 的迁移
publish-date=11122012