文章目录
前言
- 负责的说如果你是刚接触T100,可以不用通读全文,看看目录,大概知道有什么就可以了,后期使用的时候来搜索,节省时间。
- 关于内容方面,如果发现有什么问题,如果你愿意,可以联系我修改,谢谢。
Genero FGL
是什么?
由Four j's基于INFORMIX数据开发的的数据库管理语言
优点
- 分为client与server端,加快执行效率
- 通过XML在client与server端传递数据
- 支持不同的操作系统与数据库平台
- 引入基本对象的概念
- 可以在执行阶段控制输出的格式
组成部分
- 页面(Form)与程序(Moudle)组成程序作业(Program)
- 程序(Moudle)由函数(Function)与 (Report)组成
- 作业(Program)必须指明执行的入口
编译
Moudle编译
语法(4gl ==》42m):
fglcomp [編譯參數] 待編譯檔檔名[.4gl]
Form编译:
文字格式(per档):
语法(per ==》 42f):
fglform [編譯參數] 待編譯檔檔名[.per]
XML格式(4fd档)
语法(4fd ==》 42f)
gsform [編譯參數] 待編譯檔檔名[.4fd]
连接
首先,如果不需要使用外部的4gl可以忽略连接(link)直接执行(execute)作业
其次,如果该作业有子程序或副程序(如上图),可以将不含MAIN的子程序打包为动态连接库(42x),最后再与主程序共同连接生成作业执行档(42r)。
连接语法
fgllink -o 連結完成的完整檔名 待連結檔案 1 [待連結檔案 2] ….
eg:
fgllink -o test.42x text1.42m text2.42m text13.42m
fgllink -o program.42r text.42x main.42m other.42m
页面不需要连接,直接通过OPEN WINDOW…WITH FORM 指令直接呼叫 42f
运行
运行前需要开启GDC(Genero Desktop Client)并占用的6400端口
运行语法:
fglrun [執行參數] 執行檔檔名[.42r]
其他GDC命令
1. fglrun -V 查看GDC版本
Hello Wold程序
1. 编写hello.4gl文件
MAIN
DISPLAY "HELLO, WORLD!"
END MAIN
2. 编译4gl文件
fglcomp hello
3. 没有使用外部4gl,所以可以跳过连接直接运行
fglrun hello
编译前处理
1. &include
eg: &include "common_action.4gl"
会将导入的文件一起编译
2. &define
eg: &define MAX_VALUE 12
等同于constant,在程序内均可以使用该常量
3. &ifdef、&else、&endif
eg:
&defineIS_DEFINED
&ifdef IS_DEFINED DISPLAY "defind!" &endif
Genero FGL 语法
定义变量
语法:
1. DEFINE 变量名 变量类型
2. DEFINE 变量名 LIKE 数据库表名.字段名
eg:
1. DEFINE employee_no CHAR(20)
2. DEFINE p_employee_no LIKE employee_file.employee_no,
p_team_no SMAILINT,
p_join_date, p_birthday DATE
ps:
1. 使用数据库对应字段的方式定义变量,需要使用DATABASE或SCHEMA声明数据库
2. 创建变量是尽量采用变量的方式,后期修改变量就不用手动修改字段宽度
3. 连续定义可以使用逗号隔开,省略DEFINE声明
4. 同类型的定义可以使用逗号合并使用
变量类型
STRING类型的METHOD
Genero 的预定义变量
定义变量集合(Records)
# 方法一(直接定义):
DEFINE rec RECORD
id INTEGER,
name VARCHAR(20),
birth DATE
END RECORD
# 方法二(对于数据库中的字段):
DEFINE cust RECORD LIKE customer.*
# 方法三(对于数据库中的字段):
DEFINE cust RECORD
id LIKE customer.id
name LIKE customer.name
birth LIKE customer.birth
END RECORD
使用数据结构(TYPE)
eg1:
PUBLIC TYPE customer RECORD
id INTEGER,
name VARCHAR(20),
birth DATE
END RECORD
DEFINE c customer # 使用定义的数据结构定义变量
eg2:
PUBLIC TYPE rpt_order RECORD
order_num INTEGER,
store_num INTEGER,
order_date DATE,
fac_code CHAR(3)
END RECORD
MAIN
DEFINE o rpt_order #使用資料結構 rpt_order 並取名為 o
DECLARE order_c CURSOR FOR
SELECT order_num, store_num, order_date, fac_code FROM orders
START REPORT order_list
FOREACH order_c INTO o.*
OUTPUT TO REPORT order_list(o.*)
END FOREACH
FINISH REPORT order_list
END MAIN
REPORT order_list(ro)
DEFINE ro rpt_order #使用資料結構 rpt_order 並取名為 ro
FORMAT
ON EVERY ROW
PRINT ro.order_num, ... #使用 ro.* 存取資料
变量赋值
通过LET给定义好的变量赋值
语法
LET variable = expression
eg:
MAIN
DEFINE c1,c2 CHAR(10)
LET c1 = "GENERO"
LET c2 = c1
END MAIN
变量值初始化(INITIALIZE)
使用场景:
初始化数据结构(Records)的变量为NULL,或则为数据结构的预设值
eg:
DEFINE cr RECORD LIKE customer.*
INITAILIZE cr.cust_name TO NULL
INITAILIZE cr.* LIKE customer.*
预定义常数(PRE-DEFINED Constant)
定义常数
使用CONSTANT定义常数
语法:
CONSTANT constant_id [data_type] = value 可不指明数据类型,会自动设置,设置错误也会自动修改
eg:
CONSTANT c1 = "Drink" -- 自行宣告為 STRING
CONSTANT c2 = 4711 -- 自行宣告為 INTEGER
CONSTANT c3 SMALLINT = 12000 -- 自行修正為 INTEGER
CONSTANT c4 CHAR(10) = "abc" -- 遵照設定為 CHAR(10)
运算符
比较运算符
逻辑运算符
数值运算符
字符串运算符
关联运算符
日期运算符
对话框处理运算符(Dialog handling)运算符
设置全局变量(GLOBALS)
方法一(直接定义):
语法:
GLOBALS
declaration-statement
[,...]
END GLOBALS
eg:
GLOBALS
DEFINE g1 VARCHAR,
DEFINE g2 VARCHAR
END GLOBALS
方法二(导入外部文件):
语法:
GLOBALS "filename"
变量的生命周期
Local变量(Local Variables)
位置:Moudle中的函数(FUCTION、MAIN等)中
生命周期:与函数共存亡
Moudle变量(Moudle Variables)
位置:位于Moudle中,函数外
生命周期:属于当前Moudle
Global变量(Global Variables)
位置:GLOBALS和END GLOBALS中
生命周期:属于所有Moudle
eg:
SCHEMA ds
GLOBALS
DEFINE g_employee CHAR(10)
END GLOBALS
DEFINE g_tty CHAR(32)
MAIN
DEFINE answer CHAR(1)
END MAIN
FUNCTION ins_employee()
DEFINE flag CHAR(1),
change SMALLINT
END FUNCTION
以上示例属于GLOBAL变数的有g_employee
属于MODULE变数的有g_tty
属于LOCAL变数的有answer、flag、change
USING
指定数字或日期的输出格式
数值
日期
eg:
流程控制
Moudle架构
程序(Moudle)可以简单分为前段的设定+函数:
前端的设定:
导入外部程序
eg:
1. 导入4GL函数库
IMPORT FGL 42m_modulde
2. 导入java程序
IMPORT JAVA class_name
3. 导入C-extension或程序标准函数库
IMPORT pacakage 包名
ps:不可以循环IMPORT,否则编译时会报错
声明参照数据库
SCHEMA 声明数据库在编译的时候起参照作用,执行程序是不会进行数据库的连接
DATABASE声明数据库除了编译的时候起参照作用,执行时也会进行数据库的连接
eg:
SCHEMA ds
MAIN
DEFINE lc_zz01 LIKE zz_file.zz01
SELECT zz01 into lc_zz01 FROM zz_file where zz01='hgh'
END MAIN
由于SCHEMA没有真正连接数据库,所以上面的代码会返回一下错误:
Program stopped at 'test_schema.4gl', line number 5.
SQL statement error number -1803 (-1). Connection does not exist.
全局或模组变量
函数
MAIN函数
一个程序只能有一个MAIN函数
MAIN函数eg:
MAIN
DISPALY "Hello World!~"
END MAIN
MAIN中的设置
DEFER 设置
定义是否拦截中断(interrupt)或退出(quit)信号
语法:
DEFER { INTERRUPT | QUIT }
ps:
1. DEDER INTERRUPT:当使用者按下中断键(Ctrl+c或Delete键),系统会拦截信号并将INT_FLAG设置为TRUE。当程序中包含ON ACTION interrupt也会重复上述流程。
2. DEDER QUIT:当使用者按下退出按键,系统会拦截信号并将QUIT_FLAG设置为TRUE,以及中断程序。
OPTIONS设置
修改系统预设项,见 OPTIONS设置(图)
Exceptions设置
当发生SQL错误时,告诉系统该如何处理。程序中想改变应对方式时可再次设置,即以新设置方式处理。
语法:
WHENEVER [ANY] ERROR { CONTINUE | STOP | CALL function | GOTO label }
MAIN中的设置eg:
MAIN
OPTIONS #修改系统预设值
INPUT NO WRAP, #离开最后一个输入格不重新开始
FIELD ORDER FORM # 数据输入按照字段的顺序
WHENEVER ERROR STOP # 发生错误,程序停止运行
DISPLAY "Change Exception!" # 提示
WHENEVER ERROR chk_err # 发生错误调用函数,此处调用函数无需括号
END MAIN
FUNCTION chk_err()
DISPLAY "Error Hanppend"
END FUNCTION
OPTIONS设置(图)
套件
os.Path
eg:
IMPORT OS
MAIN
DISPLAY "The Path is :", os.Path.pwd()
IF os.Path.mkdir("newdir") THEN DISPLAY "New a new directory OK" END IF
END MAIN
dirname / basename / rootname及extension的比较
util.Math
eg:
IMPORT util
MAIN
DISPLAY util.Math.pi()
END MAIN
一般FUNCTION函数
函数提供一些特定的功能,也称为子函数
语法:
[PUBLIC | PRIVATE ] FUNCTION function_name( [arg [ , … ] ] )
eg:
MAIN
CALL say_hello_public()
CALL sya_hello_private()
END MAIN
FUNCTION say_hello_public()
DISPLAY "Hello, world"
END FUNCTION
FUNCTION say_hello_private()
END FUNCITON
报表结构函数REPORT
用于设置输出报表的格式
eg:
REPORT test_rep(sr)
FORMAT·
PAGE HEADER
BEFORE GROUP
ON EVERY ROW
AFTER GROUP
END REPORT
函数相关的内容
CALL
执行函数,若有返回值使用RETURING 接收
语法:
CALL function ( [ parameter [,...] ] ) [ RETURNING variable [,...] ]
RETURN
返回数值,并结束函数的运行
语法:
RETURN [ value [,...] ]
函数相关的练习
1. 返回字符串
MAIN
DEFINE var1 CHAR(10)
DEFINE var2 CHAR(10)
LET var1 = foo()
DISPLAY "var1 = " || var1
CALL foo() RETURNING var2
DISPLAY "var2 = " || var2
END MAIN
FUNCTION foo()
RETURN "hello"
END FUNCTION
2. 返回布尔值
MAIN
IF foo() THEN
DISPLAY "Hello World"
END IF
END MAIN
FUNCTION foo()
RETURN TRUE
END FUNCTION
3. 返回两个值
MAIN
DEFINE var1 CHAR(10)
DEFINE var2 CHAR(10)
CALL foo() RETURNING var1 var2
DISPLAY var1,var2
END MAIN
FUNCTION foo()
RETURN “hello”,"world"
END FUNCTION
常用内置函数 built-in-functions
4GL注解
{} 模块注解
#、-- 单行注解
IF
语法:
IF condition THEN
statement
[...]
[ELSE
statement
[...]
]
END IF
eg:
MAIN
DEFINE name CHAR(20)
LET name = "John Smith"
IF name MATCHES "John*" THEN
DISPLAY "The first name is too common to be displayed."
IF name MATCHES "*Smith" THEN
DISPALY "Even the last name is too common to be displayed."
END IF
ELSE
DISPLAY "This name is ",name,"."
END IF
END MAIN
CASE
语法一:
CASE expression-1
WHEN expression-2
{ statement | EXIT CASE }
[...]
[ OTHERWISE
{ statement | EXIT CASE }
[...]
]
END CASE
eg:
MAIN
DEFINE v CHAR(10)
LET v = "C1"
CASE v
WHEN "C1"
DISPLAY "This is C1."
WHEN "C2"
DISPLAY "This is C2."
OTHERWISE
DISPLAY "Unexpected value"
END CASE
END MAIN
语法二:
当有多个表达式值为真,使用第一个符合条件的statement
CASE
WHEN boolean-expression1
{ statement | EXIT CASE}
[...]
WHEN boolean-expression2
{ statement | EXIT CASE}
[...]
[OTHERWISE
{ statement | EXIT CASE}
[...]
]
END CASE
eg:
MAIN
DEFINE v CHAR(20)
LET v = "C1"
CASE
WHEN (v="C1" OR v="C2")
DISPLAY "This is C1 or C2."
WHEN (v="C3" OR v="C4")
DISPLAY "This is C3 or C4."
OTHERWISE
DISPLAY "Unexpected value."
END CASE
END MAIN
FOR
语法:
FOR counter = start TO finish [ STEP value ]
statement
[...]
eg:
MAIN
DEFINE i, i_min, i_max INTEGER
LET i_min = 1
LET i_max = 10
DISPLAY "正序:"
FOR i = i_min TO i_max
DISPLAY i
END FOR
DISPLAY "倒序:"
FOR i = i_max TO i_min STEP -1
DISPLAY i
END FOR
END MAIN
END FOR
WHILE
语法:
WHILE b-expression
statement
[...]
END WHILE
eg:
MAIN
DEFINE a, b INTEGER
LET a=20
LET b=1
WHILE a>b
DISPLAY "a>b"
LET b = b + 1
END WHILE
END MAIN
CONTINUE
语法:
CONTINUE { FOR | FOREACH | MENU | CONSTRUCT | INPUT | WHILE }
eg:
MAIN
WHILE TRUE
DISPLAY "Show this expression."
COTINUE WHILE
DISPLAY "Never show this expression."
END WHILE
END MAIN
EXIT
语法:
EXIT { CASE | FOR | MENU | CONSTRUCT | FOREACH | REPORT | DISPLAY | INPUT | WHILE | PROGRAM }
eg:
MAIN
DEFINE i INTEGER
LET i = 1
WHILE TRUE
LET i = i + 1
IF i = 100 THEN
EXIT WHILE
END IF
END WHILE
DISPLAY "OK!"
END MAIN
ps:
执行 EXIT PROGRAM,程序通过正常方式退出,不会抛出异常。可以传出大小为8bit的数值,传负数,exit_code接收时自动转为正数。
eg:
EIXT PROGRAM(1)
TRY CATCH
语法:
TRY
[待偵測是否會發生問題的程式段落]
CATCH
[處理問題或回報訊息的程式段落]
END TRY
eg:
MAIN
LET lc_a = ARG_VAL(1)
TRY
DATABASE lc_a
CATCH
DISPLAY lc_a,' not in fglprofile, number:',SQLCA.SQLCODE
END TRY
END MAIN
SLEEP
语法:
SLEEP seconds
eg:
MAIN
DISPlAY "Sleep 5 seconds."
SLEEP 5
DISPLAY "Sleep ok!"
END MAIN
LABEL
在程序中添加书签
语法:
LABEL label-id〆
GOTO
跳转放到指定位置
语法:
GOTO〆 label-id
eg:
MAIN
DISPLAY "Before GOTO"
GOTO: label_id1
DISPLAY "Never Been Displayed"
LABEL label_id1:
DISPLAY "After GOTO"
END MAIN
基本输入输出 Channel
通过内置的base.Channel函数库,可以读写txt文件、以及执行系统命令(ls -a等)获取系统信息
eg1(读取文件内容):
custinfo.txt:
8712|David|Cosneski|24-12-1978|
3422|Frank|Zapinetti|13-04-1968|
323|Mark|Kelson|03-10-1988|
MAIN
DEFINE ch base.Channel # 定义变量ch,用于存储Channel实例
DEFINE custinfo RECORD # 定义结构体用于存储文本文件的数据
cust_num INTEGER,
cust_fname VARCHAR(40),
cust_lname VARCHAR(40),
cust_bdate DATE
END RECORD
LET ch = base.Channel.create() # 创建Channel实例
CALL ch.setDelimiter("|") # 设置文本分隔符
CALL ch.openFile("custinfo.txt", "r") # 通过文件的方式打开custinfo.txt,设置行为r
WHILE ch.read([custinfo.*]) # 循环读数据到custinfo中
DISPLAY custinfo.* # 打印读入的数据
END WHILE
CALL ch.close() # 关闭Channel,释放资源
END MAIN
eg2(读取系统指令获取的内容):
MAIN
DEFINE fn STRING # 定义变量存储用来存储结果
DEFINE ch base.Channel # 定义Channel变量存储实例
LET ch = base.Channel.create()
CALL ch.setDelimiter("") # 执行系统指令无需设置分隔符
CALL ch.openPipe("ls -l", "r") # 通过管道的方式执行ls -l指令,设置行为是读r
WHILE ch.read(fn) # 循环便利
DISPLAY fn
END WHILE
CALL ch.close()
END MAIN
输入(INPUT)
使用INPUT输入数据,必须要页面显示到屏幕上
语法:
1. Implicit field-to-variable mapping:
INPUT BY NAME { variable | record.* } [,...]
[ WITHOUT DEFAULTS ]
[ ATTRIBUTE ( { display-attribute | control-attribute } [,...] ) ]
[ HELP help-number ]
[ dialog-control-block
[...]
END INPUT ]
2. Explicit field-to-variable mapping:
INPUT { variable | record.* } [,...]
[ WITHOUT DEFAULTS ]
FROM field-list
[ ATTRIBUTE ( { display-attribute | control-attribute }
[,...] ) ]
[ HELP help-number ]
[dialog-control-block
[...]
END INPUT ]
eg:
语法1:INPUT BY NAME p_employee.no
语法2:INPUT p_employee.no FROM no
ps:
如使用语法1,没有指定【FIELD ORDER FORM】顺序,则使用定义这组变量的顺序
INPUT架构(生命周期)
控制区间执行顺序(时间触发之后,函数执行顺序)
INPUT 控制点(触发的事件)
WITHOUT DEFAULTS
使用INPUT给栏位(变量)会使用栏位的属性defaultvalue给栏位设值,如果没有设置defaultvalue,则使用
NULL,但如果数据库中已经有数据也会被设置为NULL,导致数据丢失,因此要使WITHOUT DEFAULTS保留原先的值
eg:
SELECT * INTO p_employee.* FROM employee_file
WHERE no = ‘David’
DISPLAY BY NAME p_employee.*
INPUT BY NAME p_employee.* WITHOUT DEFAULTS
PROMPT
询问一些小问题,类似与弹窗,并可以获取用户的答案
语法:
PROMPT question FOR [CHAR[ACTER]] variable
[ ATTRIBUTE ( input-attributes ) ]
ON ACTION action-name
#僅有二控制區塊,與 INPUT 功能相同。
ON IDLE idle-seconds
END PROMPT
eg:
MAIN
DEFINE a CHAR(10)
PROMPT "Are you ok? " FOR CHAR a
ON IDLE 30
EXIT PROGRAM
END PROMPT
END MAIN
指标(CURSOR)
当进行SQL查询的时候,若需要一次查找多个资料,是一次性查取,还是查询一次处理完成之后再查取。这就要通过一个指标(CURSOR)来说明。首先说明
与SQL查询相关的CONSTRUCT、PREPARE、FREE。
CONSTRUCT
语法一:
ps:
1. char_variable 為接取使用者輸入資料的字串變數(建議以 STRING 格式變數接取)
2. column_list 為對應到表格(TABLE)的欄位名稱清單(逗號隔開)
3. field_list 為畫面(WINDOW 或是 FORM)上的欄位代碼清單(逗號隔開)
4. 若有增加控制區段(CONTROL BLOCK,如 ON ACTION 等),則就要加上『END
CONSTRUCT』
语法二:
eg(CONSTRUCT 結束後會將組合完成的 WHERE 條件置入『l_str』後回傳到程式中):
CONSTRUCT BY NAME l_str ON employee, salary
ON IDLE 10
EXIT PROGRAM
END CONSTUCT # l_str =『employee='1000' AND salary>'30000'』
PREPARE
通过CONSTRUCT获取到查询条件之后,需要使用PREPARE转为真正可执行的SQL指令
PREPARE会检查SQL语法的正确性,执行之后还会传递回一个返回值(prepared-id)。
语法:
PREPARE statement-name FROM char_variable
ps:
1. statement-name即返回值(prepared-id)。
2. 使用PREPARE之前,应确保SQL是完整的,例如加上SELECT等。
FREE
释放PREPARE内存
语法:
FREE statement-name
eg:
...
LET l_str = "“employee='1000' AND salary>'30000’"
LET l_sql = "SELECT * from employee_file WHERE", l_str
PREPARE emp_pre FROM l_sql
...
FREE emp_pre
...
CURSOR两个值
SCROLLING CURSOR
一次取一个数据,处理完毕之后,可以修改指针位置获取其他数据
语法:
DECLARE cursor_id CURSOR [WITH HOLD] FOR sql statement
FOREACH cursor_id
[USING value]
[INTO variable ]
…
END FOREACH
组成部分
DECLARE
1. 語法﹝1﹞使用已知的 SQL 敘述進行 CURSOR 宣告:
DECLARE cursor_id SCROLL CURSOR FOR select-statement
2. 語法﹝2﹞使用已宣告的 PREPARED ID 來進行 CURSOR 宣告:
DECLARE cursor_id SCROLL CURSOR FOR prepared_id
3. 語法﹝3﹞使用已知的 STRING 敘述進行 CURSOR 宣告:
DECLARE cursor_id SCROLL CURSOR FROM string-expression
OPEN
在SCROLLING CURSOR的情况下使用CURSOR,需要通过OPEN打开CURSOR
语法:
OPEN cursor_id [USING value]
ps:
1. 可以通过status检查此命令是否执行成功
FETCH
移动cursor获取数据
语法:
FETCH cursor_id INTO program_variable
CLOSE
在SCROLLING CURSOR下,需要手动关闭cursor。
语法:
CLOSE cursor_id
SCROLLING CURSOR eg:
DATABASE ds
MAIN
DEFINE a STRING
DEFINE b,c CHAR(10)
DECLARE test01 SCROLL CURSOR FOR
SELECT zz01 FROM zz_file WHERE zz01 = “axmt410”
OPEN test01
FETCH FIRST test01 INTO b
DISPALY b
LET c = "axmt410"
LET a = "SELECT zz01 FROM zz_file WHERE zz01 = '",c CLIPPED,","
DECLARE test02 SCRCOLL CURSOR FROM a
OPEN test02
FETCH LAST test02 INTO b
DISPLAY
END MAIN
NON-SCROLLING CURRSOR
一次性获取所有所需数据
语法:
DECLARE cursor_id CURSOR [WITH HOLD] FOR sql statement
FOREACH cursor_id
[USING value]
[INTO variable ]
…
END FOREACH
DECLARE 声明
1. 語法﹝1﹞使用已知的 SQL 敘述進行 CURSOR 宣告:
DECLARE cursor_id SCROLL CURSOR FOR select-statement
2. 語法﹝2﹞使用已宣告的 PREPARED ID 來進行 CURSOR 宣告:
DECLARE cursor_id SCROLL CURSOR FOR prepared_id
3. 語法﹝3﹞使用已知的 STRING 敘述進行 CURSOR 宣告:
DECLARE cursor_id SCROLL CURSOR FROM string-expression
FOREACH 声明
语法:
FOREACH cursor_id INTO program_variable
Statement
END FOREACH
FOREACH 与 FETCH的不同
1. FOREACH只能做循环获取数据,FETCH可以跳转获取数据
2. FETCH实现循环获取数需要搭配循环语句
3. FOREACH指令可以自动开启关闭CURSOR,FETCH必须手动开启关闭
NON-SCROLLING CURSOR eg:
MAIN
DEFINE clist ARRAY[300] OF RECORD
cnum INTEGER,
cname CHAR(50)
END RECORD
DEFINE l INTEGER
DEFINE str STRING
DEFINE c_name CHAR(50)
DATABASE stores
LET c_name = ARG_VAL(1)
LET str = "SELECT customer_num, cust_name FROM customer WHERE cname = ?"
PREPARE pre_id FROM str
DECLARE c1 CURSOR FROM str
FOREACH c1 USING c_name INTO clist[l].*
LET l = l + 1
END FOREACH
DISPLAY "获取:",l," 条记录"
END MAIN
数据的锁定(LOCK)
LOCKING CURSOR
又名:FOR UPDATE CURSOR
用于对记录进行更新(UPDATE)时,将记录进行锁定(LOCK)。
语法:
DECLARE cursor_name CURSOR FOR sql statement FOR UPDATE [NOWAIT]
OPEN cursor_id [USING value]
FETCH cursor_id INTO variable
CLOSE cursor_id
LOCKING CURSOR组成部分
DECLARE
语法一:
DECLARE cursor_id CURSOR FOR select_statement FOR UPDATE [NOWAIT]
语法二(char_variables是Sql变量):
DECLARE cursor_id CURSOR FROM char_variable FOR UPDATE [NOWAIT]
ps:
与 SCROLL CURSOR 或 NOT-SCROLL CURSOR不同点在于:需要在最后加上 FOR UPDATE,对于ORACLE数据库还需加上NOWAIT
OPEN
打开cursor
语法:
OPEN cursor_id
FETCH
读取数,并给记录加锁,其他人不能使用该记录,直到使用CLOSE关闭cursor_id
语法:
FETCH cursor_id INTO program_variable
CLOSE
释放资源,取消记录的锁定
语法:
CLOSE cursor_id
LOCKING CURSOR eg:
DATABASE ds
MAIN
DEFINE g_gav01 LIKE gav_file.gav01
DEFINE g_gav02 LIKE gav_file.gav02
LET g_forupd_sql = "SELECT * from gav_file WHERE gav01=? AND gav08=?", " FOR UPDATE"
DECLARE p_per_lock_u CURSOR FROM g_forupd_sql
OPEN p_per_lock_u USING g_gav01, g_gav02
IF STATUS THEN
CLOSE p_per_lock_u
RETURN
END IF
FETCH p_per_lock_u INTO g_gav_lock.*
IF SQLCA_sqlcode THEN
CLOSE p_per_lock_u
RETURN
END IF
CLOSE p_per_lock_u
END MAIN
USING
这里的USING使用来传值到Sql串中,之前那个USING是用来限制字符串输出的格式
语法:
LET sql statement = “SELECT * FROM table_id WHERE key_value = ? “
DECLARE cursor_name CURSOR FOR sql statement FOR UPDATE [NOWAIT]
OPEN cursor_id USING value
ps:
1. 使用USING传参,参数需要与Sql中的问号一一对应,使用逗号隔开
2. USING的使用必须在OPEN(Scroll Cursor 与 Locking Cursor)、FOREACH(Non-scroll Cursor)、EXECUTE(批量执行Sql Cursor)之后
eg:
...
LET g_forupd_sql = "SELECT * from gav_file WHERE gav01=? AND gav08=?", " FOR UPDATE"
DECLARE p_per_lock_u CURSOR FROM g_forupd_sql
OPEN p_per_lock_u USING g_gav01, g_gav02
...
事务(TRANSACTION)
和Mysql的事务含义相同,执行多个UPDATE、INSERT、DELETE指令,通过事务处理让这些命令要么都执行成功,要么都都执行失败
语法:
BEGIN WORK # 开启事务
[ UPDATE statement ]
[ INSERT statement ]
[ DELETE statement ]
IF ( condiction ) THEN
COMMINT WORK # 提交事务
ELSE
ROLLBACK WORK # 回滚事务
END IF
ps:
1. 使用BEGIN后一定要使用COMMINT WORK或ROLLBACK WORK说明SQ如何处理
2. 建议BEGIN WORK后的Sql命令不要太多,以避免出现大量用户等待相同记录的操作权限
3. 部分DDL(数据库定义语言,如CREATE TABLE)有自动COMMIT WORK的功能
4. 当执行COMMIT WORK或ROLLBACK WORK后会自动CLOSRE掉没有在声明时加WITH HOLD的CURSOR
大量执行同一Sql(EXECUTE)
当执行大量同一Sql,可以通过循环+Sql的方式实现,通过EXECUTE效率更高
语法:
PREPARE prepared_id FROM sql_statement
EXECUTE prepared_id [USING variable_list ] [ INTO fvar [,...] ]
FREE prepared_id
ps:
1. EXECUTE可以应用到INSERT、DELETE、UPDATE、SELECT
2. USING传值使用尽量在EXECUTE
eg:
MAIN
DEFINE key INTEGER
DEFINE name CHAR(10)
PREPARE s1 FROM "UPDATE customer SET name=? WHERE customer_num=?"
EXECUTE s1 USING name, key
FREE s1
END MAIN
大量执行INSERT(PUT…FLUSH)
当大量插入数据时,比EXECUTE更快的方式时使用PUT...FLUSH
语法:
PREPARE prepared_id FROM INSERT_sql_statement
DECLARE cursor_id [WITH HOLD] FOR prepared_id
OPEN cursor_id
PUT cursor_id FROM variable_list
FLUSH cursor_id
CLOSE cursor_id
FREE cursor_id
FREE prepared_i
eg:
MAIN
DEFINE i INTEGER
DEFINE rec RECORD
key INTEGER,
name CHAR(30)
END RECORD
DARABASE stock
PREPARE is FROM "INSERT INTO item VALUES (?,?)"
DECLARE ic CURSOR FOR is
BEGIN WORK
OPEN ic
FOR i=1 TO 100
LET rec.key = i
LET rec.name = "Index:" ,i
PUT ic FROM res.*
IF i MOD 50 = 0 THEN
FLUSH ic
END IF
END FOR
CLOSE ic
COMMIT WORK
FREE ic
FREE is
END MAIN
阵列(ARRAY)
阵列就是数组,与数组不同的是,阵列从下标为1开始,并可以定义动态阵列。
固定阵列
语法:
ARRAY [ intconst [,intconst [,intconst] ] ] OF datatype
动态阵列
语法:
DYNAMIC ARRAY [ WITH DIMENSION rank ] OF datatype
阵列可使用的方法
阵列相关练习
# 练习一:定义固定阵列和动态阵列
MAIN
DEFINE a1 ARRAY[10] OF INTEGER # 长度为10,类型为INTEGER的固定阵列
DEFINE a2 DYNAMIC ARRAY OF INTEGER # 定义类型为INTEGER的动态阵列
DEFINE i INTEGER
LET i = 12
LET a1[50] = 123456
LET a2[5000] = 123456
LET a2[500+i] = 123456
END MAIN
# 练习二:getLength()方法
MAIN
DEFINE a1 ARRAY[10] OF INTEGER
DEFINE a2 DYNAMIC ARRAY OF INTEGER
DISPALY a1.getLength()
DISPLAY a2.getLength()
END MAIN
# 练习三:clear()方法
MAIN
DEFINE a ARRAY[20] OF INTEGER
DISPLAY a.getLength()
CALL a.clear()
DISPLAY a.getLength()
END MAIN
# 练习四:appendElement()方法
MAIN
DEFINE a DYNAMIC ARRAY OF INTEGER
LET a[10] = 10
CALL a.appendElement
LET a[a.getLength()] = a.getLength()
DISPLAY a.getLength()
DISPLAY a[10]
DISPLAY a[11]
END MAIN
# 练习五:insertElement()方法
MAIN
DEFINE a DYNAMIC ARRAY OF INTEGER
LET a[10] = 11
CALL a.insertElement(10)
LET a[10] = 10
DISPLAY a.getLength()
DISPLAY a[10]
DISPLAY a[11]
END MAIN
# 练习六:deleteElement()方法
MAIN
DEFINE a DYNAMIC ARRAY OF INTEGER
LET a[10] = 9
CALL a.deleteElement()
DISPLAY a.getLength()
DISPLAY a[9]
END MAIN
# 练习七:二、三维阵列
MAIN
DEFINE a2 DYNAMIC ARRAY 2 OF INTEGER
DEFINE a3 DYNAMIC ARRAY 3 OF INTEGER
LET a2[50][100] = 123456
LET a2[51][1000] = 123456
DISPLAY a2.getLength() # 51
DISPLAY a2[50].getLength() # 100
DISPLAY a2[51].getLength() # 1000
LET a3[50,100,100] = 12456
LET a3[51,101,1000] = 12456
DISPLAY a3.getLength() # 51
DISPLAY a3[50].getLength() # 100
DISPLAY a3[51].getLength() # 101
DISPLAY a3[50,100].getLength() # 100
DISPLAY a3[51,101].getLength() # 1000
CALL a3[50].insertElement(10) # 添加空白数据到50,10
CALL a3[50,10].insertElement(1) # 添加空白数据到50,10,1
END MAIN
DISPLAY ARRAY
将阵列通过TABLE或TREE等元件显示
控制属性
事件触发后执行的控制段
DISPLAY ARRAY eg1(ARRAY显示到TABLE):
DATABASE ds
MAIN
DEFINE cnt INTEGER
DEFINE arr DYNAMIC ARRAY OF RECORD
gen01 CHAR(8),
gen02 CHAR(8),
gen03 CHAR(6)
END RECORD
OPEN WINDOW f1_w WITH FORM "custlist"
DECLARE c1 CURSOR FOR SELECT gen01,gen02,gen03 FROM gen_file
LET cnt = 1
FOREACH c1 INTO arr[cnt].*
LET cnt = cnt + 1
END FOREACH
CALL arr.deleteElement(cnt)
LET cnt = cnt – 1 #此處也可使用 LET cnt = arr.getLength( ) 取得實際筆數
DISPLAY ARRAY arr TO srec.* ATTRIBUTES(COUNT=cnt) #定義於畫面檔結構內
ON ACTION print
DISPLAY "Print a report"
END DISPLAY
END MAIN
DISPLAY ARRAY eg2(ARRAY显示到TREE):
DEFINE tree DYNAMIC ARRAY OF RECORD
name STRING, #名字〆有顯示的欄位
pid STRING, #父節點資料〆畫面使用幽靈欄位﹝Phantom﹞
id STRING, #本節點資料〆畫面使用幽靈欄位﹝Phantom﹞
hasChildren BOOLEAN, #是否有下層節點資料〆畫面使用幽靈欄位﹝Phantom﹞
description STRING #說明〆有顯示的欄位
END RECORD
DATABASE ds
MAIN
DEFINE cnt INTEGER
DEFINE arr DYNAMIC ARRAY OF RECORD
gen01 CHAR(8),
gen02 CHAR(8),
gen03 CHAR(6)
END RECORD
OPEN WINDOW f1_w WITH FORM "custlist"
DECLARE c1 CURSOR FOR SELECT gen01,gen02,gen03 FROM gen_file
LET cnt = 1
FOREACH c1 INTO arr[cnt].*
LET cnt = cnt + 1
END FOREACH
CALL arr.deleteElement(cnt)
LET cnt = cnt – 1 #此處也可使用 LET cnt = arr.getLength( ) 取得實際筆數
DISPLAY ARRAY arr TO srec.* ATTRIBUTES(COUNT=cnt) #定義於畫面檔結構內
ON ACTION print
DISPLAY "Print a report"
END DISPLAY
END MAIN
ERP T100
Genero 技術手冊 9-6
MAIN
DEFINE id INTEGER #節點值
OPEN WINDOW f1_w WITH FORM "custlist"
CALL expand(0)
DISPLAY ARRAY tree TO sr_tree.* ATTRIBUTE(UNBUFFERED)
ON EXPAND(id) #展開子節點
CALL expand(id)
ON COLLAPSE(id) #收合子節點
CALL collapse(id)
END DISPLAY
END MAIN
FUNCTION collapse(p) #收合
DEFINE p INT
DEFINE id STRING
LET id = tree[p].id
WHILE p < tree.getLength()
IF tree[p + 1].pid != id THEN EXIT WHILE END IF
CALL collapse(p + 1)
CALL tree.deleteElement(p + 1) #此節點下的資料,全部用 deleteElement 砍掉
END WHILE
END FUNCTION
FUNCTION expand(p) #展開
DEFINE name, id, pid STRING
DEFINE p, i INT
IF p = 0 THEN #只是給名字,若為根節點命名為 Root,子節點則為 Node1.1
LET pid = 0
LET name = "Root"
ELSE
LET pid = tree[p].id
LET name = "Node"
END IF
FOR i = 1 TO 4 #如果是從資料庫抓取展開資料,此處是 FOREACH 迴圈即可
LET p = p + 1
CALL tree.insertElement(p) #插入子節點
LET id = pid || "." || I #生成子欄位節點值
LET tree[p].id = id
LET tree[p].pid = pid #抓取父節點值
LET tree[p].name = name || " " || i
IF i MOD 2 THEN
LET tree[p].hasChildren = TRUE
ELSE
LET tree[p].hasChildren = FALSE
END IF
LET tree[p].description = "This is node " || tree[p].name #抓取說明值
END FOR
END FUNCTION
CLEAR SCREEN ARRAY
清除指定页面的阵列数据
语法:
CLEAR SCREEN ARRAY screen-array.*
eg:
#利用 CLEAR 指令逐筆刪除
FOR i=1 TO <screen-array-length>
CLEAR screen-array[i].*
END FOR
#利用 CLEAR SCREEN ARRAY 整批移除
CLEAR SCREEN ARRAY screen-array.*
对话框(DIALOG)
将CONSTRUCT与INPUT指令封装起来,方便使用。因为单独使用CONSTRUCT和INPUT时,如果想切换不同的指令,必须结束前一项功能,才能进入另外
一项,比较麻烦。
DIALOG封装的指令
INPUT、DISPLAY ARRAY、INPUT ARRAY、CONSTRUCT、SUBDIALOG
语法
DIALOG [ ATTRIBUTE ( { display-attribute | control-attribute } [,...] ) ]
BEFORE DIALOG
AFTER DIALOG
ON IDLE idle-seconds
ON ACTION action-name
END DIALOG
ps:
1. DIALOG不支持INT_FLAG,如果需要中断程序需要配合ON ACTION,在ACTION中使用EXIT DIALOG或ACCEPT DIALOG指令
2. 如果在DIALOG只打算使用一个封装的指令,请不要使用DIALOG
eg:
SCHEMA stores
DEFINE p_customer RECORD LIKE customer.*
DEFINE p_orders DYNAMIC ARRAY OF RECORD LIKE order.*
FUNCTION customer_dialog()
DIALOG ATTRIBUTES(UNBUFFERED, FIELD ORDER FORM)
INPUT BY NAME p_customer.* # sub-DIALOG
AFTER FIELD cust_name
CALL setup_dialog(DIALOG)
END INPUT
DISPLAY ARRAY p_orders TO s_orders.* # sub-DIALOG
BEFORE ROW
CALL setup_dialog(DIALOG)
END DISPLAY
ON ACTION close # Action for DIALOG
EXIT DIALOG
END DIALOG
END FUNCTION
ui.Dialog方法