DB编译问题记录

轻松实现应用程序移植!

是否计划将 Oracle 应用程序移植到 IBM® DB2® for Linux®, UNIX® and Windows®?学习如何使用本文描述的步骤完成此任务。本文包含的示例脚本可以使任务更加简单。
简介

本文适用于以下开发人员、管理员或独立软件供应商(Independent Software Vendor,ISV):

拥有支持非 IBM 数据库(比如 Oracle Server)的数据库应用程序 
其客户希望将 Oracle 应用程序迁移到位于分布式平台上的 IBM DB2 — DB2 for Linux, UNIX, and Windows(本文中使用 DB2) 
许多想迁移 Oracle 应用程序以支持 DB2 的企业和业务合作伙伴提出了以下问题: 

许多使用 Oracle 服务器的客户都希望在 DB2 上运行他们的应用程序。我需要进行哪些更改才能使应用程序支持 DB2 数据访问? 

只要逐步执行本文描述的步骤,就很容易将 Oracle 应用程序移植到 DB2 平台。本文指出了在将 Oracle 应用程序迁移到 DB2 时可能遇到的最常见问题,同时也提供了克服这些问题的步骤。我曾经成功对拥有 1 亿行源代码的 Oracle 应用程序进行了概念证明(proof-of-concept)迁移,本文就是建立在这个基础之上。

以下是针对本文的示例迁移的一些假设:

示例 Oracle 应用程序是用 C/C++ 编程语言编写的。 
在 UNIX (AIX® 5.2) 平台上的 DB2 Version V8.2 上进行移植。本文讨论的大多数问题也适用于 DB2 9。 
以下是本文将描述的问题:

DB2 预编译器不能识别声明部分中用户定义的数据类型(typefef,#define macros),位于 EXEC SQL BEGIN DECLARE SECTION 和 EXEC SQL END DECLARE SECTION 语句之间。 
由于参数类型不同,使用用户定义函数(UDF)(比如 ||、rawtohex、hextoraw,等等)开发的应用程序不能在 DB2 上编译。 
使用 DECODE 函数的 Oracle 应用程序不能在 DB2 上正确编译。 
需要在 DB2 中执行与包含 NOWAIT 的 Oracle SQL 语句类似的行为。 
需要在 DB2 中处理大小超过 32672 的主机变量。 
当移植到 DB2 时,需要考虑 Oracle 的 “Select for update” 语句。 
本文将移植过程分解成一些主要任务,然后探讨每个任务涉及的问题。

任务 1:标识嵌入式 SQL(.sqC)程序

对于此任务,需要在应用程序中标识所有的 Pro C(SQL + C/C++ 程序组合)程序。首先应该将这些 Pro C 程序转换为 DB2 能用其预编译器解释的嵌入式 SQL 程序。 

SQL 与 C 程序组合:扩展名为 .sqc(在 UNIX 上) 
SQL 与 C++ 程序组合:扩展名为 .sqC(在 UNIX 上) 
也许还需要回顾一下用 C/C++ 开发的嵌入式 SQL 程序示例。可以在 DB2 实例目录下的以下路径中找到它们: 

C 程序:sqllib/samples/c 
C++ 程序:sqllib/samples/cpp 
这些嵌入式 SQL 程序是用 DB2 的预编译器(db2 prep)编译的。 

问题 1

如果在 EXEC SQL BEGIN DECLARE SECTION 和 EXEC SQL END DECLARE SECTION 语句之间使用了用户定义的数据类型(例如 C/C++ 中的 “typedef”)和宏(#define),那么 DB2 预编译器在编译这些程序时会遇到一些问题。

因此,如果将一个包含嵌入式 SQL 语句的文件(.sqC)传递到 db2 precompile 命令,则编译时会提示出错。如清单 1 所示。

注:
此示例只是为了描述问题并在编译之后生成相应的错误,所以其形式非常简单。要重现此场景,可以执行 db2 "create table test_table (dept int)" 命令创建一个 “TEST_TABLE” 表。  

考虑如下的 test1.sqC 文件: 

清单 1. test1.sqC
                
#include 

#define LONGBIG long

/* 
Or we can have a definition like:
typedef long LONGBIG
*/

EXEC SQL INCLUDE SQLCA;
EXEC SQL BEGIN DECLARE SECTION;
        LONGBIG col1_val;
EXEC SQL END DECLARE SECTION;

int main()
{
        EXEC SQL SELECT DEPT 
        INTO :col1_val 
        FROM TEST_TABLE;
        
        return 0;
}      

当试图使用 db2 prep 编译 test1.sqC 文件时,会得到以下错误:

清单 2. 预编译 test1.sqC 的结果
                
db2 prep test1.sqC bindfile 

LINE    MESSAGES FOR test1.sqC
------  --------------------------------------------------------------------
        SQL0060W  The "C++" precompiler is in progress.
  11  SQL0008N  The token "LONGBIG" found in a host variable
                  declaration is not valid.
  18  SQL4942N  The statement selects an incompatible data type
                  into host variable ":col1_val".  SQLSTATE=42806
        SQL0095N  No bind file was created because of previous
                  errors.
        SQL0091W  Precompilation or binding was ended with "3"
                  errors and "0" warnings.

[db2inst1]/users/ganesh_gosavi/mig1/issues/NULL_issue>
      

出现这些错误是因为 DB2 预编译器不能解析一些 typedef 和宏,这些 typedef 和宏用于通过 EXEC SQL BEGIN DECLARE SECTION 和 EXEC SQL END DECLARE SECTION 语句定义的声明部分。 

问题 2

第 2 个问题与在代码声明部分中广泛使用的类型定义有关,这些类型定义包括 typedef 结构、嵌入式结构中的 typedef、用户定义的数据类型,以及在各种嵌入式头文件中声明的 typedef。

清单 3 中的示例源代码演示了该问题。

清单 3. test2.sqC
                                                
#include 
#include 
.
.

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;
#include "extrndef.h"
        EXEC SQL INCLUDE 'UPR_ELEMENTS.H';

        EXTERN varchar b2k_amount_host_str[50][35];
        static varchar cur_time[20];
        static varchar cur_user[16];

        static char cur_time[20];
        static char cur_user[16];
EXEC SQL END DECLARE SECTION; 
        

问题 1 和 2 的解决方案

以上问题的一个常用解决方案是,不要在 EXEC SQL 声明部分中使用 typedef 和宏。但是如果拥有很多这样的文件,手动完成此操作很麻烦,您也许希望进行自动处理。我们在此处提供一个 Perl 脚本(esql_prep),以减少手动操作的麻烦,该脚本使任务变得更加简单。

注:该脚本的主要开发人员是 Knut Stolze ([url=mailto:stolze@de.ibm.com]stolze@de.ibm.com[/url])。请谨慎使用此脚本,跟平常一样,在将其应用到源代码中之前,请首先测试其功用。也许有一些特殊条件未包含在脚本中,这可能会产生错误的结果。 

使用此 Perl 脚本的语法如下:

清单 4. Perl 脚本的语法
                        
./esql_prep xxxxxxx.SQX "gcc -E -I" 

此处,

“path” 既可以是头(.h)包含文件的相对路径,也可以是其绝对路径。 
“xxxxxxx.SQX” 是一个含有问题 1 和问题 2 中所描述问题的文件。 
“gcc -E” 选项告诉 C++ 编译器对 “xxxxxxx.SQX” 文件进行预处理。 

上面的命令对 xxxxxxx.SQX 文件进行预处理,并生成一个新文件 xxxxxxx.SQC。在 xxxxxxx.SQC 文件中可以看到,预定义的宏和用户定义类型已经被替换了。然后可以将 xxxxxxx.SQC 文件传递给 db2 prep 预编译器执行下一步操作。 

问题 3

当将嵌入式 SQL 程序(例如,test3.sqc 或 test3.sqC)传递给 db2 prep 预编译器时,会输出两个文件:

一个修改过的 C 或 C++ 程序(test.c 或 test.C) 
一个绑定文件(test.bnd) 
当将 test3.c 或 test3.C 传递给语言编译器(C/C++)时,语言编译器有时会返回一个与清单 5 类似的错误: 

清单 5. test3.sqC 编译错误
                
"test3.i",line 6043.38:1540-0274 (S)The name lookup for "NULL" did not find a declaration.
        

此错误是由于预编译器在创建 C 文件时插入与清单 6 类似的语句引起的: 

清单 6. 预编译器输出
                
.
.
sql_setdlist[0].sqldata = (void*)&col1_val;
#line 6043 "test3.i"
      sql_setdlist[0].sqlind = 0L;
#line 6043 "test3.i"
      sqlasetdata(3,0,1,sql_setdlist,NULL,0L);
    }        

此时发生了如下操作?

上面的 esql_prep 通过 C/C++ 预编译器运行源代码(仍包含嵌入式 SQL 语句)。结果,所有的 #include 指令都被解析了,包括  中的指令。 
DB2 预编译器插入这些语句(包含 “NULL”),如上面的清单所示。 
常规的 C/C++ 编译器开始编译。它执行一个常规的 C/C++ 预编译。但是预编译不会做任何事情,因为这些都在步骤 1 中完成了。特别是,不再有 #include 指令。结果,代码中的 “NULL” 未被更改。C/C++ 编译器找到 “NULL” 并报告错误,因为它不知道该怎么做。毕竟 “#define NULL (void *)0” 不在此处,因为没有找到 #include 。 
因此,必须为 NULL 提供一个常规的 #define。 

结果,db2 prep 预编译器返回清单 4 所示的错误。

问题 3 的解决方案

要消除此错误,可以使用编译器的 -D 选项。

例如:

清单 7. test2.sqC
                        
/usr/vacpp/bin/xlC  -c  -o test3.o -DNULL=0  -I./  -I/db2/db2inst1/sqllib/include

任务 2:在 DB2 for Linux, UNIX, and Windows 中实现 Oracle UDF 行为

这是在将 Oracle 应用程序迁移到 DB2 for Linux, UNIX, and Windows 时面临的主要挑战。应用程序调用 Oracle 支持的各种 UDF。对各个文件和目录的所有代码(可能有数百万条)进行检查是非常困难的。找到每个位置并更改相应的源代码,从而让应用程序支持 DB2,这是一项单调、麻烦且容易出错的工作。

本文下载部分的 OracleToDB2UDFs.zip 提供了许多等价的 Oracle UDF。只需在选择的模式下对它们进行注册即可。无需修改应用程序源代码就可使用这些 UDF。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
SQL Server是一种关系型数据库管理系统,它提供了强大的数据存储和查询功能。在SQL Server中,可以使用多种方法导出SQL语句,以下是几种常见的方法: 1. 使用SQL Server Management Studio (SSMS):SSMS是SQL Server的官方管理工具,它提供了图形化界面和丰富的功能。要导出SQL语句,可以在SSMS中执行查询语句,并将结果保存为SQL文件。在查询结果窗口中,右键单击结果集,选择“保存结果为”或“脚本结果为”,然后选择保存为SQL文件。 2. 使用bcp命令行工具:bcp是SQL Server提供的命令行工具,用于导入和导出数据。可以使用bcp命令导出整个表或查询结果为SQL文件。例如,使用以下命令导出表数据: ``` bcp <数据库名>.<模式名>.<表名> out <输出文件路径> -S <服务器名> -U <用户名> -P <密码> -c ``` 其中,`<数据库名>`是要导出的数据库名称,`<模式名>`是表所属的模式(可选),`<表名>`是要导出的表名称,`<输出文件路径>`是保存SQL文件的路径,`<服务器名>`是SQL Server的名称,`<用户名>`和`<密码>`是连接数据库所需的凭据。 3. 使用SQL Server Integration Services (SSIS):SSIS是SQL Server的ETL(Extract, Transform, Load)工具,可以用于数据导入和导出。通过创建一个SSIS包,可以定义数据源和目标,并将数据导出为SQL文件。在SSIS中,可以使用“导出数据”任务或“SQL任务”来实现。 4. 使用编程语言和SQL Server驱动程序:如果你熟悉编程,可以使用支持SQL Server的编程语言(如Python、Java、C#等)和相应的SQL Server驱动程序来导出SQL语句。通过连接到数据库,执行查询语句,并将结果保存为SQL文件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值