T100学习笔记 - Genero FGL

Genero FGL是一种基于INFORMIX数据的数据库管理语言,它包括客户端和服务器端,能提高执行效率,支持多种操作系统和数据库平台。文章详细介绍了Genero的编译、连接、运行过程,以及其语法特性,如变量定义、数据结构、流程控制、函数和报告结构。此外,还讲解了输入输出、对话框处理、事务处理和错误处理等内容,提供了丰富的示例代码供读者参考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章目录


前言

  1. 负责的说如果你是刚接触T100,可以不用通读全文,看看目录,大概知道有什么就可以了,后期使用的时候来搜索,节省时间。
  2. 关于内容方面,如果发现有什么问题,如果你愿意,可以联系我修改,谢谢。

Genero FGL

是什么?

由Four j's基于INFORMIX数据开发的的数据库管理语言

优点

  1. 分为client与server端,加快执行效率
  2. 通过XML在client与server端传递数据
  3. 支持不同的操作系统与数据库平台
  4. 引入基本对象的概念
  5. 可以在执行阶段控制输出的格式

组成部分

在这里插入图片描述

  1. 页面(Form)与程序(Moudle)组成程序作业(Program)
  2. 程序(Moudle)由函数(Function)与 (Report)组成
  3. 作业(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方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


总结

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值