首页 > 代码库 > 嵌套SQL语句訪问DB2中SQLCA的调用技巧

嵌套SQL语句訪问DB2中SQLCA的调用技巧

在IBM的关系型数据库产品DB2中,使用SQL Communication Area(SQLCA)将程序中嵌套的SQL语句执行情况返回给程序。

在程序中有针对性地对SQLCA实施调用,可对程序中各类SQL语句的执行结果实施控制,从而避免程序的意外终止。同一时候,也能够提高执行效率,减小系统开销和处理时间。本文将对此作一简要介绍。
SQLCA的结构
SQLCA的结构定义例如以下:
struc sqlca
{        unsigned char     sqlcaid[8];
long              sqlabc;
long              sqlcode;
short             sqlerrml;
unsigned char     sqlerrnmc[10];
unsigned char     sqlerrp[8];
long              sqlerrd[6];
unsigned char     sqlwarn[21];
unsigned char     sqlstate[5];        }
结构中各个域各有不同的含义和用途。部分域的功能和用途将在下面各小节中做具体探讨,其他一些域的含义例如以下:
sqlcaid:        标识性域。包括字符串“sqlca”.
Sqlabc:        包括sqlca结构的长度。
Sqlerrml:        包括sqlerrmc域中数据的实际长度。
Sqlerrmc:         由0或多个字串组成,它对返回的值给以一个更具体的解释。如返回的代码表示表没找到,则此域中包括未找到的表名。
Sqlerrp:         包括一些对用户没用的论断信息。
Sqlstate:         长度为5的字符串,它指示SQL语句的查询结果。

与sqlca不同的是,它遵循ANSI/ISOSQL92的标准,所以,虽然不同数据库产品的sqlca结构中sqlcode域的含义不同。但sqlstate域的含义是同样的。


调用方法
DB2通过一个函数:sqlaintp。能够方便地读取sqlca中SQL语句运行后的结果和错误。此函数定义在sql.h中,可通过下述语句实现对其定义:
EXEC SQL INCLUDE sqlca.h 
Sqlaintp函数格式例如以下:
int sqlaintp
(        char  *buffer
short   buffer_size
short   line_width
struct  sqlca *sqlca        )
当中, buffer为存放了sqlca信息的缓冲区;buffer_size中存放了buffer的长度;line_width存放了两个运行符之间的字符长度。

函数返回值为正时代表sqlca信息的长度,为负时代表没有sqlca信息返回。一般来讲,sqlca信息都可存放在长度为512个字节的缓冲区中。
为了处理各种错误情况,DB2提供了WHENEVER语句。其详细用法例如以下:
(1)        EXEC SQL WHENEVER SQLERROR action       SQLCODE<0时,运行action.
(2) EXEC SQL WHENEVER SQLWARNING action     SQLCODE>;0但不为100且SQLWARN[0]=W时时,运行action.
(3) EXEC SQL WHENEVER NOT FOUND action      SQLCODE=100时,运行action.
当中action有两种可能:
CONTINUE:继续运行程序中的还有一条命令。
GO TO label:转到label指定的语句開始。
值得注意的是,WHENEVER语句的作用范围到下一个WHENEVER时终止。


对SQLCODE的调用
   在对SQLCA的调用中,最常见的就是通过訪问SQLCODE来实现的。

非常多程序猿甚至在每条SQL语句运行完成后都设置检查SQLCODE返回值的代码,以对程序的运行进行监控。当返回值为+0的时。表明SQL语句运行成功。返回值为+100时,表明满足检索条件的记录没找到。

一般来说。负的SQLCODE返回负值意味着SQL语句运行失败,程序猿可在程序中实现依据不同的SQLCODE返回值,採取不同的程序流程以实现错误控制。比如。当SQLCODE的返回值为-911时, 表明系统检測到了死锁(Dead Lock),程序猿可针对这样的情况採取下面两种处置方法:
(1)设置循环,重复运行查询请求并检測SQLCODE,直至返回值为+0(运行成功)。
(2)设置一个计数器,运行查询请求到一定次数后终止程序或向用户发出警报。


值得注意的是,为了保证数据的完整性。有时须要针对返回的错误类型对数据库进行回滚(ROLLBACK)操作,且回滚的起点不一定是未运行成功的SQL语句导致系统所处于的状态。回滚的起点与SQL语句的嵌套类型(动态,静态。复合式)以及错误类型都有关系。

尤其是后者,由于有些错误类型会导致系统作一个隐式的回滚(比如SQLCODE -911),从而使回滚的起点推断更为复杂。
   虽然多数情况下我们希望SQL语句运行成功,但有些时候。通过一个有益“制造”的负的SQLCODE返回值,能够使程序中的逻辑推断更为简洁。还可在较大程度上降低系统开销。我们能够设想这样一种情况:邮电局有两种话费收据,一种是针对仅仅安有一部电话的用户的,还有一种是针对安有多部电话的用户的,两种话费收据上的项目个不同样,须要不同的子程序进行处理。在话费收据处理程序中,首先依据每个用户唯一的ID号检索相应的电话号码。并设置计数器对检索到的记录数(安装电话数)进行统计,当某用户ID仅相应一条电话号码记录时。调用单机用户话费收据处理程序对相应用户的话费数据进行处理;当某用户ID仅相应多条电话号码记录时,调用多机用户话费收据处理程序对相应用户的话费数据进行处理。不管何种情况。都需对用户的数据又一次进行读取方可进行下一步处理。也就是说,须要对一个用户的电话数据进行两次读取才干完毕相应的数据处理。这无疑会极大的添加系统处理时间。

通过对SQLCODE的调用。能够使这样的情况得以显著改善。首先。针对每个用户的ID作一个SELECT操作,然后检查SQLCODE返回值,当返回值为+0时,表明该用户仅仅安装了一部电话;当返回值为-811时。表明该用户安装了不止一部电话。可由此推断应由那种程序来处理用户话费信息。採用这样的解决方式,仅仅对用户的数据读取一次就可完毕用户的话费处理。差点儿降低了一半的系统处理时间。

与其他诸如改变表的结构等方法。此种方法对系统的修改最小。而且简便易行。效果明显。


   在对数据库訪问的程序中,程序通常要求实现例如以下功能:更新数据库中的某一条记录,当这条记录不存在时创建对应的记录。

比較常见的做法是,先进行一次SELECT查询,当SQLCODE返回+0时,表明此条记录已存在,然后再重读此记录对其进行UPDATE操作;当SQLCODE返回+100时,表明对应记录不存在,接下来再进行INSTER操作。还有一种实现方岸依据数据訪问的特点,当对数据的更新多于新值插入时。直接进行UPDATE操作。当SQLCODE返回+0时更新成功,反之。返回+100时,需对其进行INSERT操作。当新值插入要多余于更新操作时。首先进行INSERT操作。SQLCODE值为+0时插入成功,否则返回-803,表明原记录已存在,须要进行UPDATE操作。显而易见,多数情况下,另外一种方法仅仅需对数据进行一次操作就可以,从而提高系统的处理效率。
对SQLWARN的调用
   虽然程序猿通常总是忽略SQL的警告错误。但适当的使用能够帮助程序检測到各种潜在的错误,而且能够使编程更加简洁。

因此,此类警告信息亦应受到程序猿的重视。
   警告信息在SQLCA中有两种表示方法。

每个除了+100以外的SQLCODE正返回值都代表一定的警告信息;同一时候,SQLCA中的SQLWARN[n](n=1,2,3,4。5。6或A)返回值也代表着对应的警告信息。当系统发现警告错误时,系统会以这两种方式通知程序。

此时。查询可能会返回一些结果。但此时的结果极有可能是错误或不完整的。当SQLWARN[O]=W时。DB2提供了帮助用户推断详细警告类型的信息,其对应值及含义例如以下表:


SQLCA值        返回值        警告内容
SQLWARN[1]        W        序主变量长度不够而发生截取
SQLWARN[2]        W        字段功能处理的数据中有空(NULL)值
SQLWARN[3]        W        返回字段个数大于程序定义的序主变量个数
SQLWARN[4]        W        在UPDATE或DELETE操作中未指定WHERE条件
SQLWARN[6]        W        对时间数据进行数学运算后进行修正
SQLWARN[A]        W        转换出错
       如果某学校要计算某一学期各班。各科。个人的平均成绩。

当中。个人平均成绩=(个人总分)/(本学期所学科目数)。

因为工作人员疏忽,误将某一同学的学期学习科目输为0。

在使用嵌套SQL语句的程序对相关数据进行处理时,SQLCODE返回值为-802(除数为零)导致程序终止执行。虽然用户知道可能是某一项数据错误,但无法知道详细是哪一项数据错误。对于一个拥有较多数据的学校来说,查找起来是非常费事的。

通过下述办法能够非常好的解决这一问题:在定义代表计算结果的序主变量的同一时候,为其指定一个能够为空的指示变量,如 :AVGRD :IND代表序主变量为AVGRD,指示变量为IND。此时发生被零除错误时,指示变量值被设为-2,同一时候SQLCODE返回值为+802警告信息。

程序捕捉到此信息时,可向用户提供对应的信息,帮助用户确定出错数据位置。
   当SQLWARN[O]的值为W时,表明系统检測到警告错误。此时系统提供的警告信息也可被程序猿所利用。比方:当程序把一个表中的某一字符型字段值传入一个比其长度要短的序主变量中时,发生字符截取。虽然此时SQLCODE会返回+0,但程序获取的数据是不完整的。通过为序主变量指定一个指示变量。发生相同错误时,SQLWARN[O]和SQLWARN[1]的返回值都为W。同一时候,指示变量被赋给了字段中数据的实际长度。此种方法甚至能够用来推断表中字段中字符串数据的实际长度。
对SQLERRD数组的调用
    SQLERRD是SQLCA中代表SQL查询执行结果的一个数组。数组中的不同元素有不同的含义。

当中较经常使用的是SQLERRD[3]。它将返回程序中上一次INSERT,UPDATE或DELETE操作所影响到的记录数。否则。程序须要借助一定的循环来统计被以上操作影响到的记录数。但值得注意的是。在执行DELETE操作时。假设相关字段的删除类型被设为CASCADE而导致被删除其他记录数不会被包括在内;同一时候,假设在DELETE语句中未指定WHERE条件,则SQLERRD[3]的返回值为-1。以上两点在使用此数组时应予以注意。SQLERRD中各元素的含义以及其对于复合式SQL语句。连接方法的不同含义例如以下:
SQLERRD元素        表示意义        复合式SQL语句        连接方式
SQLERRD[2]        保存当前SQL语句处理的行数。但若当前SQL失败, 则无定义; 若在数组操作中出错, 则停于出错行, 这时给出成功处理的行数; OPEN 运行后, 清为0, FECTH 后增值(原有值+上本次fetch的行数); EXECUTE、INSERT、UPDATE、SELETE和SELECT后, 为成功处理的行数。
SQLERRD[3]        返回的记录数(预计)及INSERT/UPDATE或DELETE操作所影响到的记录数(不包括因限制条件而影响到的记录)           总语句数         0:由底层客户机的一段式提交托付确认1:一段式提交2:一段式仅仅读提交3:两段式提交
SQLERRD[4]        指出语句中出错的位移, 首字符位移为0。


SQLERRD[5]        INSERT/UPDATE或DELETE操作所影响到的记录数(包括因限制条件而影响到的记录)        因限制条件而影响到的记录数        无

经常使用:SQLERRD[2]  ,如:#define SQLROWS sqlca.sqlerrd[2]


    DB2支持多种高级语言(包含当前极为流行的C和C++等)通过嵌套SQL语句对其上的数据进行訪问。同一时候,因为对多种嵌套(动态,静态,复合式)方式的支持,更加增强了訪问的灵活性。

通过在程序中调用SQLCA。可对程序中嵌套的SQL语句的执行结果进行控制。增强了程序的可靠性。防止程序意外终止。也可使程序的编写更加简洁。提高程序的执行效率,缩短系统的处理时间。

嵌套SQL语句訪问DB2中SQLCA的调用技巧