使用Rational Open Access解耦RPG数据库IO:RPG版

全球的IBM i客户现在正在使用SQL来定义和访问数据。 在每个新发行版中,IBM继续提供只能通过SQL加以利用的大量新功能。

这些基于SQL的新应用程序利用了以数据为中心的现代开发概念,这些概念强调了将更多的业务规则和逻辑推入数据库的重要性。

这些客户中有许多仍然依赖以IBM RPG编程语言编写的传统应用程序。 这些RPG程序中的一些也将从利用现代数据中心技术中受益。 这些现有的RPG应用程序包含与新SQL应用程序相同的业务规则,但是它们是在多年前使用效率较低的传统记录一次数据访问方法编写的。 规则和逻辑的重复会(并且确实)导致昂贵的双重维护和事实的多个版本。

输入Rational Open Access:RPG Edition或ROA。 通过允许RPG IO操作被拦截并转换为SQL,此支持(由IBM i 7.1引入并经过改进以支持6.1)可以消除双重维护和/或昂贵的程序重写的高成本。 现在可以将新关键字(HANDLER)添加到现有RPG文件规范中。 handler关键字指定由IBM i操作系统调用的程序或服务程序入口点。 这种新的支持可以大大减少转换现有程序以共享公共模块所需的遗留代码重写量。 清单1中显示了对处理程序进行编码的示例。

清单1:编码HANDLER关键字的示例
FEMPADDRSL1UF E K DISK //-------------------Rational Open Access Addition ---------------------- // The handler keyword specifies the program/service program which will // now process the IO operations for this file F handler('UPDHANDLER')

在本文中,我将描述如何创建一个基于格式的处理程序,该处理程序允许多个程序使用共同的格式和唯一键来更新同一张表,以利用单个通用SQL UPDATE语句,该语句利用扩展的指示符变量支持。

以下是我将使用的方法:

  • 构建一个基于格式的处理程序,该程序在数据库IO操作时拦截RPG传统记录。 处理程序将拦截的IO操作转换为等效SQL语句。
  • 通过添加单行代码,使现有的非SQL RPG ILE程序能够使用处理程序。
  • 创建并注册一个外部存储过程,该存储过程允许支持存储过程调用的任何接口(Java,PHP等)访问处理程序

我选择了RPG IV自由格式样式作为基于主机的编程语言。 这主要是因为我相信使用Rational Open Access:RPG Edition将更吸引RPG程序员。 但是,必须注意,可以使用IBM i支持的任何基于主机的语言编写处理程序和SQL程序。

我还对代码示例,合并过程,移动和删除代码等采取了一些自由措施。这可能会导致代码示例无法按原样编译。 另外,某些代码示例仅在安装了Rational Open Access产品后才有效。

构建基于格式的处理程序

使用Rational Open Access在RPG程序和处理程序之间来回传递数据有两种方法。 第一种是基于结构的,而数据和键值是使用缓冲区传递的。 这些缓冲区可以是程序描述的,也可以是外部描述的。 第二种方法是基于列的,其中数据和键值作为单独的项目传递。 每个项目都包含数据或键字段的属性。 使用的方法直接影响可能需要编写的处理程序的数量。 无论哪种情况,都将要求使用动态嵌入式SQL,以最大程度地减少编码工作和处理程序的总数。

动态SQL是创建通用数据库处理程序的理想选择。 根据您对ILE和SQL的专业知识水平,可以开始部署三种类型的通用数据库处理程序。 这三种类型是格式,基于语句或基于过程的处理程序。 基于格式的处理程序非常适合固定列表样式的动态SQL。 基于语句的处理程序更适合于可变列表样式的动态SQL。 基于过程的处理程序最适合用于结果集使用或“一劳永逸”类型SQL语句,例如MERGE。

当应用程序提供动态更改行选择(通过WHERE子句)或列顺序(通过ORDER BY子句)的功能时,通常使用固定列表动态SQL,但是投影结果集是静态的。 在处理程序应用程序中,固定列表动态SQL将与基于结构的方法一起使用。 使用固定列表动态SQL时,不需要SQL描述符。

当应用程序从头开始构建整个SQL语句时,通常使用可变列表动态SQL。 在这种情况下,需要使用SQL描述符来描述SQL语句,结果集中投影的列以及任何输入参数。 有两种类型的描述符,一种是通过SQL ALLOCATE DESCRIPTOR创建的,另一种是根据SQLDA结构定义的。 可变列表动态SQL将与基于语句的处理程序一起使用。 要了解有关动态SQL的更多信息,请在线参考SQL编程指南:http://ibm.com/systems/i/db2/books.html

对于本文,我将结合使用固定列表动态SQL和静态嵌入式SQL(用于UPDATE语句)来创建基于格式的处理程序。 在以后的文章中,我将提供基于语句和基于过程的处理程序的信息。

使用ROA产品的主要好处在于,它省去了修改和测试现有程序的昂贵时间和精力。 这种将IO分离的方法可以为负责维护现有RPG代码的开发人员提供“新起点”,这些RPG代码的结构可能不佳或无法利用ILE(集成语言环境)编程模型提供的模块化功能。

图1概述了处理程序如何为依赖SQL进行数据访问的现有过程集提供桥梁。 这些过程可以是使用嵌入式SQL的外部存储过程,也可以完全用SQL PL编写。 在本文中,我将使用嵌入式SQL使用RPG子过程。

图1:使用处理程序解耦IO
图1:使用处理程序解耦IO

处理程序使用ILE为RPG程序提供原型接口。 为了使用处理程序,现有的RPG程序必须是ILE程序,也称为RPG IV。 因此,如果现有的RPG程序不是ILE,则第一步将是将RPG程序转换为ILE。 这可以通过使用“转换RPG源”(CVTRPGSRC)命令来完成。

我的处理程序包含一个主模块,该模块将RPG操作定向到相应的处理程序模块。 这允许按应用程序类型自定义主模块。 例如,仅输入文件的处理程序不需要更新模块。

各个处理程序模块包含用于将RPG IO操作转换为适当SQL替代方案的逻辑。 转换代码包含在子过程中。 另外,处理程序模块包含对RPG SQL服务程序的原型调用,该程序包含嵌入式SQL子过程。 当前有19个与数据库相关的RPG IO操作,这些操作最终可能需要由您的处理程序进行处理。 在示例处理程序中,我使用了OPEN,CHAIN,UPDATE和CLOSE中的四个。

图2包含描述上述场景的Rational Visualize应用程序图。 处理程序主过程UPDHANDLER将传入的RPG IO操作移交给相应的子过程。 子过程在调用相应的RPG SQL服务程序子过程之前执行转换逻辑。

图2:RDP可视化应用程序图
图2:RDP可视化应用程序图

图2的大图

处理程序主要过程(UPDHANDLER)

基于格式的处理程序将需要定义要处理的文件的记录格式。 这是通过编码文件定义,文件记录格式,文件密钥和SQL空指示符数组的模板作为处理程序模块的一部分来完成的,如清单2所示。 这些被编码为RPG全局变量,以允许后续重用通用模板名称并最小化代码修改。

清单2:定义记录格式模板
FrcdFile_t IF E K DISK TEMPLATE F EXTDESC('EMPADDRESS') F RENAME(empAddr:rcdFormat) D rcdFormat_t... D DS LIKEREC(rcdFormat) D TEMPLATE D keys_t DS LIKEREC(rcdFormat:*KEY) D TEMPLATE D Ind_Array_t... D S 5i 0 DIM(7) D TEMPLATE

清单2包含定义文件模板的代码示例。 TEMPLATE关键字(IBM i 6.1中的新增功能)通知RPG编译器该文件仅用于字段定义,因此该文件不需要或不需要IO操作。 不需要EXTDESC关键字。 在这种情况下,它用于定义包含在处理程序中使用的记录格式定义的实际文件。

如果此代码用作其他格式处理程序的模板,则RENAME关键字用于提供通用格式名称,以减少代码更改。 这可以在基于重命名格式的rcdFormat_t数据结构模板中看到。 该数据结构模板在处理程序中的其他模块中使用。

在RPG HANDLE_CHAIN和RPG HANDLE_UPDATE子过程中使用SQL空指示符数组。 在执行SQL FETCH语句期间填充空指示符值。 空指示符值是在执行SQL UPDATE语句之前由RPG HANDLE_UPDATE子过程设置的。

为文件指定了handler关键字之后,现在对该文件执行的所有显式或隐式IO操作都将由处理程序处理。 程序员有责任编写必要的指令以处理IO操作并提供适当的结果。 ROA产品随附RPG包含文件(QRNOPENACC),该文件包含传递给处理程序的参数的子字段定义。

清单3包含UPDHANDLER程序中主要过程的示例。 输入参数(rpgIO)是类似于QrnOpenAccess_t模板定义的数据结构,该模板是QRNOPENACC包含模块的一部分。 主要过程作用于以下子字段:

  • rpgStatus字段用于输入和输出以指示成功或失败。 零表示操作成功。 如果发生异常,则处理程序提供有效的文件状态代码。 状态代码在《 ILE RPG参考手册》中定义。
  • rpgOperation字段包含与RPG操作相对应的代码,该代码刚由正在处理的RPG程序执行。 包含模块为每个IO操作代码(即QrnOperation_OPEN,QrnOperation_CHAIN等)提供命名常量。 RPG Select语句控制将基于RPG操作执行哪个子过程。 rpgIO数据结构传递到每个子过程,并且rpgStatus字段用作返回字段。 如果子过程将rpgStatus设置为1299,则发生了不可恢复的错误,并且处理程序被停用(* INLR已打开)。
清单3:处理程序主过程RPG代码示例
D UPDHANDLER PI D rpgIO... D LIKEDS(QrnOpenAccess_T) /COPY QOAR/QRPGLESRC,QRNOPENACC /FREE rpgIO.rpgStatus = *Zero; select; when rpgIO.rpgOperation = QrnOperation_OPEN; rpgIO.rpgStatus = Handle_Open(rpgIO); when rpgIO.rpgOperation = QrnOperation_CHAIN; rpgIO.rpgStatus = Handle_Chain(rpgIO); when rpgIO.rpgOperation = QrnOperation_UPDATE; rpgIO.rpgStatus = Handle_Update(rpgIO); when rpgIO.rpgOperation = QrnOperation_CLOSE; rpgIO.rpgStatus = Handle_Close (rpgIO); Other; ENDSL; //If unrecoverable error then shutdown handler If rpgIO.rpgStatus = 1299; *INLR = *On; ENDIF; return; /END-FREE

子过程接口

每个RPG IO操作子过程都使用一个公共接口,该接口由rpgIO参数和对应于rpgStatus代码的返回字段组成。 此外,每个过程在输入时都会将rpgStatus设置为零,并使用RPG监视器功能来处理意外错误。 发生此类错误时,rpgStatus字段将设置为1299(检测到其他I / O错误)。 这将导致正在处理的RPG程序中发生异常。

清单4包含了公共处理程序子过程接口的代码片段。

清单4:通用子过程接口原型
P Handle_Open B D Handle_Open PI LIKE(rpgIO.rpgStatus) D rpgIO... D LIKEDS(QrnOpenAccess_T) D* Local fields D retField S LIKE(rpgIO.rpgStatus) /FREE retField = *Zero; Monitor; //routine specific data and code begins here On-Error; retField = 1299; ENDMON; RETURN retField; /END-FREE P Handle_Open E

处理隐式和显式RPG开放操作

RPG文件打开可以在RPG初始化阶段隐式发生,也可以通过RPG OPEN操作以及在文件定义上使用USROPN关键字来显式打开。 在大多数情况下,隐式打开就足够了。 显式OPEN操作的使用在RPG程序和处理程序之间提供了更多的交互。

处理程序OPEN例程中应该做的第一件事是设置IO信息反馈数据结构的指针和长度。 这些是在发生意外错误时可以在RPG程序中使用的结构。 它允许您将其他状态信息发送回RPG程序。 清单5包含一个代码片段,用于在rpgIO数据结构中设置这些值。

清单5:IO反馈信息
rpgIO.openFeedback = %Alloc(80); rpgIO.ioFeedback = %Alloc(160); rpgIO.deviceFeedback = %Alloc(126); rpgIO.openFeedbackLen = 80; rpgIO.ioFeedbackLen = 160; rpgIO.deviceFeedbackLen = 126;

下一个重要的项目是rpgIO stateInfo指针。 此可选指针用于分配临时存储,您可以在其中存储在与处理程序之间的调用之间需要保留的信息。 这样的项目之一是记录前图像。 处理程序将比较之前的记录图像和从RPG更新操作传递到处理程序中的值。 我们将在“处理更新”子过程讨论中对此进行更多介绍。

清单6包含一个代码示例,该示例声明一个状态信息结构,然后根据该结构的大小为stateInfo指针分配存储空间。

清单6:stateInfo数据结构的代码示例
//stateinfo data structure template D rpgSI_t... D DS TEMPLATE D OLD_ROW_p * /FREE rpgIO.stateInfo = %Alloc(%Size(rpgSI_t));

此时,我们准备构造SQL语句,该语句将用于响应RPG CHAIN操作返回输入记录。 该语句将是一个字符串变量,该变量将传递给Prepare_SQL_Statement子过程。 图3详细说明了处理RPG隐式文件打开操作的过程以及主要功能的代码片段。 由RPG程序打开的文件名将传递给rpgIO externalFile结构中的处理程序。 此结构包含两个子字段:库和名称。 如果库列包含* LIBL,则仅外部文件名用于表引用,否则库和名称列组合以形成合格的表引用。 然后,将表引用变量用于SQL Select语句FROM子句。 当对RPG PREPARE_SQL_STATEMENT子过程的调用失败时,会将rpgStatus值1299返回给正在处理的RPG程序。 如图3的HANDLE_OPEN进程图标下的代码片段所示。

图3:处理RPG开放操作
图3:处理RPG开放操作

将WHERE子句添加到Select语句字符串中,该字符串表示与RPG CHAIN操作中使用的键字段相对应的一列或多列。 在此的示例EMPNO是表的唯一键。 此时EMPNO的值未知,因此将参数标记(?)用作占位符。 实际值将在第一个RPG键控IO操作中提供。 将FOR FETCH ONLY子句添加到Select语句中,以避免记录锁定并利用SQL自动阻塞。

SQL语句格式化完成后,将传递给RPG PREPARE_SQL_STATEMENT子过程。 包含嵌入式SQL语句的RPG过程通常创建为单独的模块,然后用于创建服务程序。 该服务程序可以在编译时绑定到处理程序。 SQL模块还必须包含格式模板代码,如清单2所示。 另外,为了支持使用SQL扩展指示符,需要使用precompiler命令的OPTION参数上的* EXTIND来编译SQL模块,或者包含指定EXTIND(* YES)SQL Set Option语句。 需要在模块内的任何其他SQL语句之前指定Set Option语句。

图3包含RPG PREPARE_SQL_STATEMENT子过程的RPG代码示例,该子过程准备动态SQL语句字符串(v_SQL_String),如果成功,则为准备SQL语句声明SQL游标。 响应于RPG Open操作,SQL语句字符串(p_SQL_String)从RPG HANDLE_OPEN子过程传递到RPG子过程。

处理RPG CHAIN操作

在RPG程序更新通过键访问的行之前,它必须执行读取操作以锁定行以进行更新。 使用键执行随机读取的最常见的RPG方法是链操作。 图4详细说明了RPG CHAIN操作的处理过程以及主要功能的代码片段。

图4:处理RPG CHAIN操作
图4:处理RPG CHAIN操作

当使用基于结构的IO方法时,RPG将为输入和输出缓冲区创建初始存储,并为空指标映射创建存储。 rpgIO参数包含指向这些存储区域的指针。 RPG HANDLE_CHAIN子过程定义数据结构,如之前定义的全局模板。 结构中包含的数据基于RPG提供的指针。 清单7提供了数据结构定义的源代码示例。 图4包含RPG HANDLE_CHAIN子过程的RPG源代码示例。

清单7:处理RPG链
D Handle_Chain PI LIKE(rpgIO.rpgStatus) D rpgIO LIKEDS(QrnOpenAccess_T) D i S 5i 0 D keys DS LIKEDS(keys_t) D BASED(rpgIO.key) D inpRcd DS LIKEDS(rcdFormat_t) D BASED(rpgIO.inputBuffer) D OLD_ROW DS LIKEDS(rcdFormat_t) D BASED(rpgSI.OLD_ROW_p) D rpgSI... D DS LIKEDS(rpgSI_t) D BASED(rpgIO.stateInfo) D IndAry S 5i 0 DIM(%elem(Ind_Array_t)) D InpNullMap S N DIM(%elem(Ind_Array_t)) D BASED(rpgIO.inputNullMap)

一旦RPG程序接收到数据,RPG会将inputBuffer指针设置为null。 为了比较记录前后的图像,处理程序必须复制输入记录。 旧行的存储被定义为清单6中描述的stateInfo数据结构的一部分。 这样可以确保在链和后续的UPDATE操作之间保留数据。

如果该列定义为支持null的列,则必须相应地更新null指示符映射。 RPG使用1字符字段(如指示符)来确定列是否包含空值。 SQL使用一个小的整数,如果该列不为null,则该整数为零;如果该列为null,则为-1。

在SQL中,RPG CHAIN没有等效项,因此我选择使用带有游标的FETCH FIRST语句作为适当的选择。 这也说明了PREPARE,DECLARE,OPEN和CLOSE SQL游标语句的用法。

一个学派可能建议使用SELECT INTO来代替CHAIN操作。 在某些方面,它类似于使用CHAIN的RPG程序,因为它隐式执行了准备,打开和关闭功能。 但是缺点远远超过了这种速记功能。 这些缺点是:

  1. SELECT INTO必须返回单行,否则将失败。 不能保证RPG程序在链上使用唯一密钥。 在这种情况下,返回到RPG的行取决于创建密钥逻辑文件时使用了哪些重复的密钥处理DDS关键字(LIFO(默认),FIFO或LCFO)。
  2. 可以通过使用DISTINCT和一个或多个时间戳列来模拟FIFO或LCFO来避免上述问题。 但是,DB2将使用额外的步骤来消除重复项。 如果存在大量重复的键值,这可能会导致性能显着下降。
  3. 因为SELECT INTO返回单行,所以它不能用于其他RPG读取操作。 而FETCH可用于返回1或更多行,从而允许将单个RPG子过程用于CHAIN,READ或READE操作。

图4包含FETCH_FIRST_FROM_OPEN_CURSOR子过程的RPG源代码示例。 RPG HANDLE_CHAIN子过程传递一个或多个键,inputBuffer指针和指示器数组。

键(或多个键)用于替换一个或多个参数标记,这些参数标记是在RPG HANDLE_OPEN子过程中创建SQL语句字符串的一部分。 OPEN CURSOR语句作为FETCH进程的一部分执行。 如果OPEN成功,则执行SQL FETCH FIRST语句。 inpRcd结构和indAry参数包含成功执行FETCH的结果。 SQL OPEN和FETCH的组合等效于代表RPG CHAIN执行的系统指令。 本质上,OPEN位置进入索引,FETCH FIRST将基于索引提供的RRN检索第一行。

在同一会话或作业中第二次执行OPEN之后,SQL游标将变为可重用。 这意味着后续SQL OPEN和CLOSE操作将仅将游标重新定位到结果集的第一行。 无论RPG程序是否使用LR指示器,都将发生此现象。 这样就可以继续使用LR作为管家工具,同时避免了SQL打开和关闭开销的高额费用。

处理RPG UPDATE操作

为了理解RPG HANDLE_UPDATE子过程,我们需要讨论扩展指标变量支持的概念。 在DB2 i 6.1发行版之前,SQL Update和Insert语句可以使用值为-1的指示符变量将具有null值的列设置为null值。 借助6.1中引入的扩展指标变量支持,您可以通过提供其他指标值来扩展更新和插入功能。

最令人感兴趣的是能够使用指标值-7来允许更新绕过该列,就好像它不是UPDATE语句的一部分一样。 此支持使您可以编写可用于任何更新事务的通用更新过程,而与要更新的列无关。 图5详细说明了RPG UPDATE操作的处理过程以及主要功能的代码片段。

图5:处理RPG更新操作
图5:处理RPG更新操作

如图5中RPG HANDLE_UPDATE子过程中的代码片段所示,更新指示器数组被初始化为-7。 将outputBuffer中的值与从inputBuffer中保存的值进行比较。 对于每个不同的值,该列的指标变量都设置为零。 可以添加其他代码来执行检查,以查看新值是否是用户定义的值,该值指示应将数据库值设置为NULL还是为该列定义的默认值。 如果前者为true,则将该列的指标变量设置为-1,这将导致该列被更新为空值。 如果后者为true,则将该列的指标变量设置为-5,这会将列设置为该列的默认值。 如果旧值和新值相同,那么指标变量将保持为-7,并且该列将被忽略。 RPG HANDLE_UPDATE子过程是特定于格式的,必须为每个文件自定义。

比较所有列后,将执行RPG UPDATE_COLUMNS_USING_EXTENDED_INDICATORS子过程。 RPG UPDATE_COLUMNS_USING_EXTENDED_INDICATORS子过程接受两个参数updRcd和Ind_Ary。 updRcd参数包含表中可更新列的值(已更改和未更改)。 Ind_Ary列包含SQL扩展指示器设置。

图5包含RPG UPDATE_COLUMNS_USING_EXTENDED_INDICATORS子过程的RPG源代码示例。 UPDATE上使用的表名是包含清单2中使用的格式的文件的名称。在IBM Data Access Reengineering策略中,此文件称为代理文件。

不能使用数组索引技术指定指标变量。 每个指标变量必须单独命名。 为了解决这个问题,我使用数据结构为每个数组元素定义一个命名指示器变量。 数据结构基于Ind_Ary的地址。 清单8包含用于将输入指示器数组重新定义为数据结构的RPG源代码示例。

清单8:带有扩展指示器的更新过程
D Update_Columns_Using_Extended_Indicators... D PI N D updRcd... D LIKEDS(rcdFormat_t) D Ind_Ary... D LIKE(Ind_Array_t) D DIM(%elem(Ind_Array_t)) D* Local fields D retField S N D Ind_Ary_DS DS BASED(Ind_Ary_Ptr) D Ind_Ary_1 5i 0 D Ind_Ary_2 5i 0 D Ind_Ary_3 5i 0 D Ind_Ary_4 5i 0 D Ind_Ary_5 5i 0 D Ind_Ary_6 5i 0 D Ind_Ary_7 5i 0 /FREE Ind_Ary_Ptr = %Addr(Ind_Ary);

处理隐式和显式RPG关闭操作

处理程序必须执行两个功能:1)关闭SQL游标; 2)释放由stateInfo数据结构使用的内存。 图6详细说明了处理隐式或显式RPG CLOSE操作以及主要功能的代码片段的过程。

图6:处理RPG CLOSE操作
图6:处理RPG CLOSE操作

RPG程序打开最后记录(* INLR)指示器,这将导致对已处理文件进行隐式CLOSE操作。 处理程序拦截RPG CLOSE操作并将控制权传递给RPG HANDLE_CLOSE子过程。 分配给stateInfo指针的内存已取消分配。 将向包含嵌入式SQL CLOSE语句的RPG CLOSE_SQL_CURSOR子过程发出调用。

实施方案

以下场景用于测试处理程序代码:1)使用5250显示文件的传统RPG程序,以及2)从Java应用程序调用的外部存储过程。 5250方案是许多传统RPG商店的典型情况,其中许多程序正在访问同一表进行更新。 Java场景描述了一种技术,其中单个外部存储过程用于表更新,而许多应用程序中包含多个SQL UPDATE语句。 目标是为同一表的所有更新提供一个控制点,而不管其起源点如何。 这些场景如图7所示

图7:共享通用处理程序的混合应用程序
图7:共享通用处理程序的混合应用程序

本质上,一个基于格式的处理程序能够使用多种UPDATE方法为多个基于主机的RPG 5250程序提供服务。 这包括使用数据结构或RPG内置函数%FIELDS更新文件或记录格式。 此外,一旦将RPG程序注册为外部存储过程,任何支持存储过程调用的接口(Java,PHP等)都可以访问处理程序。 这种外部存储过程方法还允许诸如浏览器客户端之类的外部应用程序也利用DB2 for i扩展指示器支持。

清单9包含SQL CREATE PROCEDURE语句的代码示例,该语句用于将RPG程序注册为外部存储过程。

清单9:外部存储过程的代码示例
CREATE PROCEDURE TEST_UPDFIELDS ( IN p_ADDRESS1 VARCHAR(30) ,IN p_ADDRESS2 VARCHAR(30) ,IN p_ADDRESS3 VARCHAR(30) ,IN p_CITY VARCHAR(15) ,IN p_STATE VARCHAR(10) ,IN p_ZIPCODE VARCHAR(10) ,IN Unique_Key CHAR(6) ) LANGUAGE RPGLE PARAMETER STYLE GENERAL WITH NULLS RESULT SETS 2 NOT DETERMINISTIC MODIFIES SQL DATA EXTERNAL NAME RPGEXTPROC

清单10包含了已注册为外部存储过程的现有RPG程序的代码。 UPDHANDLER程序将处理的RPG IO操作代码为BOLD 。 RPG程序正在定义用于更新目的的替代文件。 清单9中所示SQL CREATE PROCEDURE语句中的PARAMETER STYLE GENERAL WITH NULLS子句指定将空指示符数组作为附加参数发送到外部存储过程。 传递给外部存储过程的每个输入参数在数组中将有一个元素。 RPG程序使用此参数(p_Ind_Ary)确定输入参数是否包含非NULL(-1)的值。 如果是这样,则使用输入参数值更改相应的数据列。 由于文件EMPADDRESS由程序UPDHANDLER处理,因此UPDATE操作的处理如前面图5中所述

清单10:RPG外部过程的代码示例
FEMPADDRESSUF E K DISK F handler('UPDHANDLER') D i S 5i 0 D HandleTheInternet... D PR EXTPGM('RPGEXTPROC') D p_ADDRLINE1 LIKE(ADDRLINE1) D p_ADDRLINE2 LIKE(ADDRLINE2) D p_ADDRLINE3 LIKE(ADDRLINE3) D p_CITY LIKE(CITY) D p_STATE LIKE(STATE) D p_ZIPCODE LIKE(ZIPCODE) D p_EMPNO LIKE(EMPNO) D p_Ind_Ary... D 5i 0 DIM(7) P HandleTheInternet... P B D HandleTheInternet... D PI D p_ADDRLINE1 LIKE(ADDRLINE1) D p_ADDRLINE2 LIKE(ADDRLINE2) D p_ADDRLINE3 LIKE(ADDRLINE3) D p_CITY LIKE(CITY) D p_STATE LIKE(STATE) D p_ZIPCODE LIKE(ZIPCODE) D p_EMPNO LIKE(EMPNO) D p_Ind_Ary... D 5i 0 DIM(7) D inpRecord Ds LIKEREC(EMPADDR:*INPUT) /Free Monitor; CHAIN(e) p_EMPNO EMPADDRESS inpRecord; If %Found; If p_Ind_Ary(1) = *Zero; inpRecord.ADDRLINE1 = p_ADDRLINE1; ENDIF; If p_Ind_Ary(2) = *Zero; inpRecord.ADDRLINE2 = p_ADDRLINE2; ENDIF; If p_Ind_Ary(3) = *Zero; inpRecord.ADDRLINE3 = p_ADDRLINE3; ENDIF; If p_Ind_Ary(4) = *Zero; inpRecord.CITY = p_CITY; ENDIF; If p_Ind_Ary(5) = *Zero; inpRecord.STATE = p_STATE; ENDIF; If p_Ind_Ary(6) = *Zero; inpRecord.ZIPCODE = p_ZIPCODE; ENDIF; inpRecord.EMPNO = p_EMPNO; Update(E) EMPADDR inpRecord; ENDIF; On-Error; ENDMON; *INLR = *On; //Implicit CLOSE Return; /End-Free P HandleTheInternet... P E

摘要

在本文中,我向您介绍了使用Rational Open Access:RPG Edition一次转换传统记录的概念,以利用更高级SQL技术(例如,扩展的指示符变量支持)中的代码更改少一行的优势。现有的RPG程序。

借助扩展的指标支持,可以将单个程序用于基于公共键针对单个表的所有传入更新事务。 这包括使用传统更新方法的现有程序以及能够利用存储过程调用的外部接口。 这种技术可以消除构造多个SQL语句来更新表中列的子集的需要。

我还介绍了基于格式的处理程序的概念,该概念允许您将RPG输入和输出缓冲区用作在RPG程序和处理程序之间移动数据的机制。 基于格式的处理程序利用了RPG IV的新模板功能。 它还以外部描述的数据结构的概念为基础,这是对固定列表动态SQL使用的主机变量进行软编码的一种方式。

在以后的文章中,我将通过创建与可变列表动态SQL结合使用的基于语句的处理程序来扩展这些概念,这可以大大减少所需的处理程序数量。 我将使用这些技术来利用以下高级SQL功能:

  • 利用SQL阻止的FETCH和INSERT来克服无法阻止的传统操作(即READE)的批量数据处理技术。
  • 使用SQL搜索的UPDATE和DELETE技术进行批量更新
  • 用SQL MERGE语句替换RPG传统的归档和清除技术
  • 存储过程结果集消耗
  • 使用INSTEAD OF TRIGGER支持的可更新SQL Join视图

通过IBM Rational Open Access:RPG Edition产品,只需对现有程序进行最少的更改即可利用上述所有功能。

翻译自: https://www.ibm.com/developerworks/ibmi/library/i-roaforsql/index.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值