| 免费下载:IBM® DB2® Express-C 10.1 免费版 或者 DB2® 10.1 for Linux®, UNIX®, and Windows® 试用版 |
|---|
| 下载更多的 IBM 软件试用版,并加入 IBM 软件下载与技术交流群组,参与在线交流。 |
嵌入式 SQL 是执行嵌入在宿主语言应用程序中的 SQL 语句的一种方式。嵌入式 SQL 数据库应用程序首先连接到数据库,然后执行这些嵌入式 SQL。这些 SQL 可以动态执行,也可以静态执行。最常用的宿主语言是 C 和 C++。在可以编译应用程序之前,构建嵌入式 SQL 应用程序涉及两个主要步骤:PREP(或 PRECOMPILE)和 BIND。
命令 PREP 用于读取源代码、解析嵌入式 SQL 并将它转换成 DB2 运行时服务 API 调用,然后将输出写入一个新的源文件中。BIND 用于将应用程序中的 SQL 语句绑定到目标数据库。默认情况下,绑定操作是 PRECOMPILE 步骤自身完成的,但也可以将它扩展为单独的一个步骤。
完成绑定后,就生成了针对 SQL 语句的访问计划,并将这些计划存储在目标数据库内的一个包中。完成 PRECOMPILE 和 BIND 步骤之后,就可利用特定于宿主语言的开发工具对应用程序进行编译和链接。稍后我们会讨论获得嵌入式 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 文档,了解目前受支持的特性。
通常,将应用程序从一个 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 注册表变量,获得有关的更多信息)。
如上所述,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。
- 先决条件:
- 确保利用以下链接正确设置了开发环境(参阅 设置嵌入式 SQL 开发环境)。
- 确保已在 DB2 服务器上创建了所需的数据库,并在 DB2 客户端计算机上对它们进行编目。在这里,使用了一个样例数据库,它是 DB2 自带的数据库。但是,该数据库可以是包含所创建的所有对象的任何数据库。请参考以下链接,获得有关的更多详细信息:
- 确保在机器上安装了正确的 C/C++ 编译器(参阅 C 中的数据库应用程序开发支持,了解有关的更多信息)
- 迁移:
- 重命名 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++ 特性
- 利用文中提供的技巧和技术来加快应用程序的迁移速度
- 尝试执行自己的迁移。
学习
- "Converting Oracle Pro*C Programs to DB2 Universal Database" 介绍了使用嵌入式 DB2 SQL 调用将 Pro*C 程序转换成 C 程序期间采用的必要步骤。
- 在 Embedded SQL area on DB2 LUW 10.1 Information Center 中,获得提高您的嵌入式 SQL 技能所需的资源。
- 查看 IBM developerWorks 上的 专题:从 Oracle 迁移到 DB2,了解从 Oracle 迁移到 DB2 的详细步骤和注意事项。
- 在 developerWorks 中国网站 Information Management 专区 中了解有关信息管理的更多信息。找出技术文档、how-to 文章、教育资料、下载和产品信息等。
- 关注
developerWorks 技术活动 和 网络广播。
- 关注 Twitter 上的 developerWorks。
获得产品和技术
- 利用可从 developerWorks 直接下载的 评估 IBM 产品试用版软件 构建您的下一个开发项目。
- 现在可以免费使用 DB2。下载 IBM 软件下载:IBM DB2 Express-C 10.1,这是为社区提供的免费 DB2 Express Edition 版本,它提供了与 DB2 Express Edition 相同的核心数据特性,还为构建和部署应用程序提供了一个坚实的基础。
讨论
- 查看
developerWorks 博客 并加入
developerWorks 中文社区。