AS400 之RPGLE Part 1

RPG

在写程序之前

关于程序开发,想强调的是:业务流程先于程序——程序是给计算机看的,流程是人执行的;程序是死的,而流程则是一个相对模糊的东西。所以在写程序前,要先弄清楚自己到底要做什么,然后将自己的思想表达给计算机——这个过程就是CODING。

RPG的长处在于数据库处理,界面交互能力倒是其次。所以最开始需要了解一些关于数据库文件的相关知识(这里就只强调跟400有关的)。在下面的操作中,假设朋友已经会用STRPDM,会文件的COPY,修改。

数据文件PF:COPY一个已经有的比较快点。然后修改一下里面的数据,就是自己的。

A*假设文件名字叫BAE
A          R BAER                                           记录名字
A            AREA           3          COLHDG('AREA CODE')  --field
A            AREANM        22          COLHDG('AREA DESC ') --field                                                       
A          K AREA                                           -Key,可选

关于域定义的参考,请在程序里面输入,然后在该行按F4,再在要看的参数上按F1,就可以得到详细信息。

数据文件LF:逻辑文件的作用是按特定的关键字顺序来检索数据库里面的记录。LF中的域定义可以是任意顺序,不必跟PF中顺序的一致。更进一步,LF可以先过滤一部分的记录,减少搜索的范围。下面先看LF如何定义,具体使用程序中再说:

A          R BAER                     
A                                      PFILE(BAE) ---表示这个LF引用的是BAE文件
A          K AREA                                 ---搜索关键字是AREA CODE

这个是简单的,再看一个稍微复杂点的:

A          R BAER                     
A                                      PFILE(BAE)
A          K AREANM                              
A          S AREA                      COMP(EQ '001')

上面的片断里面,关键字S表示“选择”,COMP表示比较,EQ表示等于。整句连起来就是:只选择AREA等于001的那些记录。

PS:如果一个PF每个库里面都有,如何确保被引用的就是自己希望的那个?将目标文件放在位于库列表的最上面的库里面。

DSP****显示程序DDS

DDS的创建,有些朋友用SDU(屏幕设计工具)比较快。但是如果是有类似的界面,则COPY一下比较方便。以下片断是几乎每个DDS都要的,除了REF那句可选以外。

A* 假设显示文件名字叫EX001D
A                                      DSPSIZ(24 80 *DS3)--设定显示屏大小
A                                      REF(*LIBL/BAE01L)---参考文件,subfile中使用
A                                      CHGINPDFT       
A                                      PRINT

再来看看接下来要定义什么东西:

A          R C0                                         -显示画面的名字
A                                      CA11(11 ' 退出 ')
A                                      CF08(08 ' 测试 ')

现在我们知道我们有一个显示画面叫C0(因为一个程序可能不止一个画面,这样需要定义不同的画面来处理不同的事务);而且这个画面还有3个命令键可以响应:F11,F8,ENTER(ENTER是系统默认的处理键)

再给这个画面添上几个域:

001 A                                  5 19' 选项 ..........:' ---常量,说明用
002 A            VSELEC    R        B  5 38REFFLD(DICT/SELEC DICT00F)
003 A                                      DSPATR(HI CS MDT)         
004 A                                      VALUES('1' '2' '3')     
005 A*                                                              
006 A            VNAME          6A  I  7 20
007 A*                                                             
008 A  81                              9 20' 查询日期 :'             
009 A            VDDATE    R        B    +1REFFLD(DICT/O8DAT DICT00F)
010 A                                      DSPATR(HI UL)

如上,

a.001和008行定义了2个显示常量,在屏幕上起提示和说明作用;

b.002行定义了一个选择域VSELEC,R表示是参考数据库里面已经有的域格式,B代表输入输出双向(双向的意思就是域里面的信息被程序修改了以后还可以反馈给画面), 5 38表示在第5行第38列,REFFLD(DICT/SELEC DICT00F)表示参考系统DICT00F文件里面的SELEC域的格式。003行和004行表示VSELEC的属性,003行是显示控制:HI高亮、CS字符分割方式、MDT必须输入。004行表示这个域可能/只能输入的值。

c.006行表示一个自己定义的域,名字叫VNAME, 6个字符长,I表示只做输入用

d.009行表示定义了一个VDDATE域,用来显示日期。010行表示显示控制:HI高亮、UL下划线。

e.008行的81是一个指示符,意思是当81号指示符是1的时候,“查询日期”才显示。

这样,显示文件就算定义完毕。

执行程序RPG

一个程序划分的粗一点,也就是2个部分:

一是数据定义,

二是执行代码。数据定义包括了文件引用(相当于C语言里面的头文件)、内部DS定义、普通常量等等;执行代码则包括主过程和子程序,也就是程序的主体及要调用的子函数。(详细定义方式请参见RPG400 REFERENCE)。

整个程序的执行过程如下:

定义部分(包括H/F/E/I/D等)à程序初始化(如果有INZ函数则自动执行,否则就是用户自己定义的变量初始化程序,也可以2个都执行)àMAIN循环(包括人机交互、数据处理、反馈)à退出(用户按退出命令键或者程序自动退出)。

如果用代码的表示方式来讲,就是如下的结构:

H            Y                           ----头文件定义
F*----------------------------------------
FBAE01L  IF  E           K        DISK    ---引入LF,搜索用
FBAE02L  IF  E           K        DISK                     
F                                      RENAME(BAE:BAE2)

F*请注意以上的2句:在使用不同LF检索同一个PF的时候,由于PF记录名字相同而导致一个冲突,这里就通过将记录名字重新命名为BAE2而避免这个问题。

FEX001D  CF  E                    WORKSTN       --显示界面

I* 下面定义一个DS结构,示范用

I@PARM       DS                                       --结构名字叫@PARM
I                                        1   6 #FCDDI --结构体内部的域
I                                        7  12 #TCDDI --ß起止范围可以不连续

C* 下面进入代码段,包括初始化,子程序

C           *INZSR    BEGSR                     ---本片断可以放在程序的任何地方
C                     MOVE *OFF      INDEX  40  ---但无论放哪里都是最先执行
C                     MOVE *ZERO     RESULT  40
C                     ENDSR

C*请注意以上的2句,最后2个40的位置错开了一位,但是意义完全不一样。第一个表示是INDEX变量的长度是40,类型是字符型(默认的,可以省略);第二行的40表示RESULT长度是4,小数点位置在0位——这是个数字型的变量。在用F4查看的时候,会很清楚地看到区别。所以MOVE到变量的数据也不一样(*OFF是字符’0’,*ZERO是数字0)

C* 主体部分,包括接受命令和处理

010 C           *INLR     DOWEQ*OFF            --程序在此不断循环,知道LR被置ON
011 C                     EXSR MAIN            
012 C                     ENDDO

C* 往下就是子程序定义了,包括按钮处理在里面

C           MAIN      BEGSR     
C                     EXFMTC0    ß这句是让C0画面获得焦点成为活动画面,程序就停在这个地方,直到输入完数据按了

画面获得焦点成为活动画面,程序就停在这个地方,直到输入完数据按了F11/F8/ENTER中的一个。当MAIN执行完毕,程序会从上面的012行跳转到010行,继续执行,直到LR标志被置ON才退出整个程序。当再进来的时候,程序会再次停在这个地方,等待用户命令。

C* F11 = QUIT
C           *IN11     IFEQ *ON                            
C                     SETON                     LR       
C                     ELSE                                
C* F8  = TEST                                   
C           *IN08     IFEQ *ON                  
C           VSELEC    IFEQ '1'                 
C                     MOVE 'AAAA'    VNAME     
C                     ENDIF                    
C           VSELEC    IFEQ '2'                 
C                     MOVEL'BB'      VNAME      -请注意MOVE和MOVEL的区别
C                     ENDIF                    
C                     ELSE

C* 如果有按键,既不是F11,也不是F8,那么就只有ENTER

C                     MOVE 20040623  VDDATE     --这个域是数字型的,外面不加引号
C                     EXSR SEARCH               --执行一个搜索子程序
C                     ENDIF
C                     ENDIF
C                     ENDSR
C*
C           SEARCH    BEGSR                    
C           *LOVAL    SETLLBAE        ---先将游标停到最低点,然后遍历整个数据库
C                     READ BAE                      92
C           *IN92     DOWEQ*OFF                      
C                     MOVELAREANM    LIST            
C                     READ BAE                      92
C                     ENDDO

C* 上面的片断中READ数据库,如果有记录,那么结果指示符92为OFF状态。如果没有读到记录(到文件末尾了?)就会置为ON。通过检测这个指示符状态可以完成遍历。

C* 下面再来试验一下KEY是如何工作的。

C           KBAE      KLIST                   --定义一个搜索键
C                     KFLD           KNAME    
C*                                           
C                     MOVE ‘AAA’   KNAME            --要查找的目标
C           *LOVAL    SETLLBAE                       --还原游标位置
C           KBAE      CHAINBAE                  93    --找到名字为AAA,93就置OFF
C           *IN93     DOWEQ*OFF                      
C                     MOVE AREANM    TMPSTR          
C           KCUSHD    READECUSHD                    93--如果数据库有重复记录
就多次查找
C                     ENDDO                          
C                     ENDSR

关于KLIST的使用:KLIST中FLD的定义必须跟要检索的目标LF中的域一一对应,但可以只有部分。比如LF中定义5个KEY域,分别是1 2 3 4 5,那么KLIST中的定义可以有1,1 2,1 2 3,但不能是2 3。各个对应的域的类型、大小都必须一样。

编译及调试

编译过程可以排除大部分的明显错误:字符拼错、未定义的变量、重复定义。编译完会产生一个SPLF,里面包含错误列表。编译过程不排除逻辑错误。

去掉逻辑错误就是调试的任务。

比如A B两个变量,A 12CHAR, B 8CHAR。希望去掉A的高4位,

那么MOVE A   B,

再MOVE B  A就可以。

但是这中间如果不CLEAR A,那么A的内容还是没有变化的。

程序大了以后逻辑比较复杂,调试有时很困难,这个时候就是需要心细加耐心。

RPG是采用一种结构化的语言,整个的结构可以采用模块化的编程方法。另外要注意的是变量的定义是即定义即用,而且都是全局的。这个将变量局部化的工作就留给程序员来完成——在其它地方不用就是咯~~~

数据库的操作及独占处理

在RPG中如果要对数据库进行读取,更新,删除,追加记录的操作,必须以相对应的方式说明对这个文件的引用。关于对数据库各种操作的组合及相应的文件引用声明,总结如下:

只从文件读取纪录

FFILENAME    IF  E           K        DISK

只向文件里面写纪录而不读取

FFILENAME    O  E                    DISK

读取纪录并更改和/或删除,不追加纪录

FFILENAME   UF  E           K        DISK

读取纪录并更改和/或删除,且追加纪录

FFILENAME   UF  E           K        DISK

A

读取纪录和追加纪录,不更新和删除

FFILENAME   IF  E           K        DISK                      A

需要注意的是对文件的操作必须和声明相对应,即有追加调用声明必须有WRITE, 有更新或删除声明必须有UPDAT和DELET操作。在对文件进行操作的时候,通常会用到指示器来判断对数据库的操作是否成功的情况,关于指示器的位置及其所代表的意义,图示如下:

图片

对文件进行更新或者删除操作的时候,需要注意的一点是更新和删除属于独占操作,同一时间只能为一个SESSION所独占,因而如果有一个SESSION锁定一条纪录,之后再有其他SESSION想以独占的方式读取这个纪录的时候,就会发生显示界面停滞60秒的情况,所以这种现象必须避免。

这种现象的避免相对来说在带有显示界面的程序中更为重要。因为中间有停顿的过程,所以如果在停顿前锁住某一条纪录,整个停顿期间其他人都不能试图以独占的方式来读取纪录。考虑到这种情况,独占的时间必须要尽可能短。对文件声明UF的时候,一般情况下在对文件纪录进行读取操作的时候,在下面的指示器前的H的位置加上N,这样文件就不是以独占的方式进行读取。

CL0N01N02N03FACTOR1+++OPCDEFACTOR2+++RESULTLENDHHILOEQCOMMENTS++++

C           SDKY0A      CHAIN(N) DBREC

在确认需要更新的时候,可以在临更新前锁住纪录,在对需要改变的字段赋值以后,立即进行更新操作。尽可能减少其间的代码以减少独占的时间来防止出现停滞的现象。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Saidywin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值