| Комментарии обозначаются знаками | { комментарий }, | или знаком # - до конца строки, | или знаком -- (два знака минус) до конца строки. |
1. Объекты SQL 2. Переменные 4GL 3. Программные
Имя базы данных простая переменная функция
Имя таблицы переменная типа "запись" отчет
Имя столбца массив метка
Имя индекса
Имя псевдотаблицы
Имя синонима
( database-name простые переменные function )
( table-name переменная типа запись report )
( column-name массивы label )
( index-name )
( view-name )
( synonim-name )
4. Имена операторов 5. Объекты экранного обмена.
и курсоров
window
statement-id - изготовленный оператор form
cursor-name - курсор screen-field
screen-record
screen-array
Организация программы
MAIN FUNCTION REPORT
Объявления переменных
DEFINE GLOBALS
Присвоения
LET INITIALIZE
Программные
CALL EXIT GOTO RETURN FOR LABLE CASE WHILE RUN IF CONTINUE SLEEP
Перехват прерываний
WHENEVER DEFER
Динамическое создание операторов
PREPARE EXECUTE FREE
Манипуляция "курсором"
DECLARE OPEN FOREACH PUT CLOSE FETCH FLUSH
Экранный обмен
MENU OPEN FORM DISPLAY ARRAY OPTIONS DISPLAY FORM SCROLL OPEN WINDOW CLOSE FORM INPUT ARRAY CURRENT WINDOW DISPLAY PROMPT CLEAR INPUT ERROR CLOSE WINDOW CONSTRUCT MESSAGE
Генерация отчетов
START REPORT OUTPUT TO REPORT FINISH REPORT
INTEGER CHAR(n) DATE
SMALLINT DECIMAL(m,n) DATETIME ед_врем1 TO ед_врем2
REAL MONEY(m,n) INTERVAL ед_врем1 TO ед_врем2
FLOAT
где ед_врем1, ед_врем2 - единицы
измерения времени
{YEAR,MONTH,DAY,HOUR,MINUTE,SECOND,FRACTION(n)}
DEFINE simw char (200), j,i,k INTEGER, ff FLOAT
# Здесь объявлены символьная переменная simw длиной 200 байт,
# целые i,j,k, и ff - восьмибайтовое с плавающей точкой
DATABASE zawod
DEFINE doljno RECORD
# объявляется запись doljno, состоящая из 4 простых переменных
dolzn CHAR(20), # должность
zarplmin LIKE kadry.zarplata,
zarplmax money(16,2), # зарплата
vakansii int # вакансии
END RECORD # Здесь заканчивается объявление записи doljno
# Переменную можно оъявить с ключевым словом LIKE column_name.
# переменная zarplmin получает такой же тип, что и столбец
# zarplata таблицы kadry из базы данных zawod
DEFINE rrr RECORD LIKE kadry.*
# Переменную типа запись тоже можно объявить с ключевым словом
# LIKE. Здесь объявлена запись rrr, содержащая элементы, имею-
# щие те же самые названия и те же самые типы что и столбцы
# таблицы kadry
Элементами записи могут быть
массивы. Можно обьявить массив
элементов типа RECORD.
DEFINE zap RECORD
a LIKE kadry.tabnom,
b array[8] OF REAL
END RECORD,
massiw ARRAY[2,15] OF RECORD
kolwo INT,
tip CHAR(8)
END RECORD
# massiw объявлен как массив записей. Каждая запись состоит
# из двух простых элементов - kolwo и tip
# присвоить значение элементу массива можно так: LET massiw[1,i+2].kolwo = zap.a + LENGTH(massiw[1,i+2].tip)
SELECT kadry.* INTO strkt.* FROM kadry WHERE kadry.tabnom=i+j SELECT * INTO strukt.b THRU strkt.e FROM kadry
DATABASE zawod GLOBALS DEFINE zap RECORD LIKE kadry.* DEFINE ext_count INT . . . END GLOBALS
GLOBALS "progrglob" . . .
FUNCTION stroka(rec) DEFINE rec RECORD i int, st char(256) END RECORD RETURN st clipped,"автопробега" END FUNCTION . . . MAIN . . . CALL stroka(rec1.*) RETURNING simw . . . LET simw=stroka(7,"Привет участникам ") # Если функция возвращает одно значение, то ее имя мож- # но использовать в выражениях. MESSAGE simw . . . END MAIN
На экране пользователь увидит:
ѓЃѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹‚ ѓЉ Привет участникам автопробега ѓЉ ѓЉ ѓЉ ѓЉ ѓЉ ѓЉ ѓЉ ѓѓѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹„
Оператор безусловного перехода действует в пределах модуля.
GOTO metka . . . LABEL metka: . . .
CASE
WHEN iscreen=1
current window is w1
WHEN iscreen=2
current window is w2
let iscreen=1
OTHERWISE
current window is SCREEN
END CASE
CASE (a+b) # Другой формат оператора CASE
WHEN 1
message "a=",a
WHEN 2
message "b=",b
END CASE
IF str = "завершить" OR y<0 then exit program # Не забывайте в конце каждого условного # оператора ставить end if. end ifОператор цикла.
FOR I= i1 TO 23
let a[i]=0
if b[i]=100 then
EXIT FOR
END IF
END FOR
Цикл "пока".
WHILE ff > 3 or nn="проба" PROMPT "Введите число " for n let i=n+1 message "А у меня ",i,", больше. Вы проиграли." SLEEP 5 RUN "rm *" WITHOUT WAITING END WHILE
DEFINE stroka char(200)
MAIN
. . .
LABEL METK2:PROMPT "введите оператор языка SQL: " FOR stroka
WHENEVER ERROR CONTINUE # Включить режим "В случае
# ошибки продолжить выполнение
# программы"
PREPARE st1 FROM stroka # Изготовить оператор из
# символьной строки
EXECUTE st1 # Выполнить изготовленный оператор
IF status<0 then error "ошибка номер ", status, " в вашем операторе" goto metk2 end if whenever error stop # Восстановить режим # "В случае ошибки прервать # выполнение программы" . . . end main
В системную переменную status помещается код выполнения каждого оператора 4GL (status=0 если все нормально, status<0 если произошла ошибка). Переменная status может проверяться после любого оператора программы и в зависимости от ее значения могут предприн
name="7">Курсоры
DATABASE zawod
DEFINE zap RECORD LIKE kadry.*
DECLARE curs1 CURSOR FOR
select * from kadry where datarovd>"9/25/1973"
# в цикле FOREACH выводим на экран все строки таблицы kadry,
# в которых столбец datarovd содержит дату после 25 сентября
# 1973 года.
FOREACH curs1 INTO zap.* # Берем очередную строку и по-
# мещаем ее в запись zap
MESSAGE zap.* # Выводим запись zap на экран
PROMPT "Еще ?" FOR CHAR c
END FOREACH # Конец цикла FOREACH
В следующем примере строки выбираемые из таблицы kadry через курсор curs2 помещаются в массив z1 (но не более 100 строк).
DATABASE zawod
DEFINE z1 ARRAY[100] OF RECORD LIKE kadry.*, counter int
DECLARE curs2 CURSOR FOR SELECT * FROM kadry
WHERE datarovd<"9/26/1973" open curs2 for counter="1" to 100 fetch curs2 into z1[counter].* # взять очередную строку и поместить ее в следующий элемент # массива z1 if status="notfound" then # если выбранные сроки кончились, закончить цикл exit fo
Этот пример демонстрирует еще одно использование переменной
status. Если оператор fetch пытается взять сроку из курсора когда тот уже пуст, то значение переменной status устанавливается равным символической константе notfound, имеющей значение 100. Поэтому можно проверять значение status после оператора
fetch и если оно равно 100, то прекратить чтение строк из опустевшего курсора.
В данном примере пользователь сам должен ввести условия, по которым будут найдены строки в таблице ceh. Он, например, может ввести: "nomerceh>15 and nomerceh<23". Программа прицепит это условие к строке, в которой записан select оператор, полу
define z2 array[100] of record like ceh.*,
counter int, simw char(200)
prompt "допишите оператор select * from ceh where " for simw
if length(simw)=0 then
let simw="true"
end if
let simw="select * from ceh where ", simw clipped
prepare st2 from simw
declare cs2 for st2
let counter=1
foreach cs2 into z2[counter].*
let counter=counter+1
if counter>100 then
exit foreach
end if
end foreach
let counter=counter-1
message "В массив z2 прочитано ",counter, " записей"
OPEN WINDOW wind1 AT 2,30 WITH 10 ROWS, 40 COLUMNS
ATTRIBUTE(BORDER, REVERSE, MESSAGE LINE FIRST)
# текущим окном является wind1
. . .
OPEN WINDOW wind2 AT 5,15 WITH FORM "schoolp"
ATTRIBUTE(GREEN,PROMPT LINE LAST,
MESSAGE LINE LAST, FORM LINE FIRST)
# текущим окном является wind2
CLEAR WINDOW wind1
. . .
CURRENT WINDOW IS wind1
# текущим окном является wind1
OPEN FORM form1 from "schoolp" # Инициализировать форму form1
# Взяв ее описание из файла
# schoolp.frm
DISPLAY FORM form1 # Вывести форму form1 в текущее окно
# т.е. в wind1
В результате работы этих операторов на экране терминала появится приблизительно такая картинка:
ѓ'ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ' ѓљ ѓ'ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ' окно ѓљ ѓљ ѓљ значение равно 8 ѓљ ...ѓwind1 ѓљ ѓљ ѓ'ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ' ѓљ ѓљ цех [ 2] [литейный ] ѓљ ѓљѓщѓ‹ѓ„ ѓљ ѓљ ѓљ таб.номер [26 ] ѓљ ѓљ окно ѓљ ѓљ ѓљ фамилия [Петров У.Е. ] ѓљ ѓљ ...ѓ wind2 ѓљ ѓљ ѓљ должность [бригадир ] ѓљ ѓљ ѓЉ ѓљ ѓљ ѓљ зарплата [$340 ] ѓљѓщѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ‹ѓ„ѓљ ѓљ ѓљ дата рождения [31.12.1952] ѓљ ѓљ ѓљ ѓљ ѓљ ѓљ ѓљ ѓљ ѓљ ѓ"ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ" ѓљ ѓљ 789 ѓљ ѓљ ѓљ ѓ"ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ" ѓљ ѓљ ѓљ нет таких ѓљ ѓ"ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ"
В результате работы фрагмента программы
let sta_return=podtwervdenie(" В самом деле решили закончить? ")
...
function podtwervdenie(stroka)
define stroka char(38) , kod_wozwr int
open window podtwervdenie AT 11,10 WITH 4 rows, 39 columns ATTRIBUTE(border)
display stroka at 4, 2 attribute (reverse)
menu " "
command key("Y") " Yes " "Действительно Да."
let kod_wozwr=1
exit menu
command key("N",ESC) " No " "Нет, вернуться обратно."
let kod_wozwr=0
exit menu
command key("A") " Abort " "Отменить. И кончить."
let kod_wozwr=-1
exit menu
end menu
close window podtwervdenie
return kod_wozwr
end function
на экране в текущем окне появится такое меню
+---------------------------------------+
| : Yes No Abort |
|Действительно Да. |
| |
| В самом деле решили закончить? |
+---------------------------------------+
OPTIONS MESSAGE LINE 23,
HELP FILE "h4gl.txt", HELP KEY CONTROL-T,
DISPLAY ATTRIBUTE(REVERSE, UNDERLINE)
let ttmm=CURRENT message "Московское время ", ttmm error "Данных больше нет, прочитанно ", n, " строк"
Оператор ERROR делает тоже, что и MESSAGE, только со звонком и с атрибутом REVERSE. Сообщение выводится на 24-ю строку экрана.
PROMPT "Да или нет ?" FOR answer
ON KEY (CONTROL-U)
LET answer=wozderv()
EXIT PROMPT
END PROMPT
Можно включить в PROMPT контрольные блоки, выполняющиеся при нажатии заданных клавиш. Если в данном примере во время ввода пользователь нажмет клавишу CTRL-U то выполнятся операторы из ON KEY предложения: будет вызвана функция wozderv() а затем прерван оператор PROMPT, не завершив ввода.
Оператор DISPLAY выводит данные в поля экранной формы.
DISPLAY a,b,zap[i].nomerceh TO pole1,fscr.* ATTRIBUTE(BOLD)
Если имена выводимых переменных совпадают с именами экранных полей в текущей экранной форме, то можно применить ключевое слово BY NAME.
DISPLAY BY NAME fio, dolvnostx
Оператор INPUT используется для ввода значений через поля экранной формы. Можно предусмотреть дополнительные действия при вводе. Для этого в оператор можно включить контрольные блоки AFTER, BEFORE, ON KEY.
INPUT kadr.* FROM fio, dolvnostx, nomerceh
BEFORE FIELD nomerceh
message "Сегодня обслуживаются цеха 5 и 6"
sleep 2
message ""
AFTER FIELD nomerceh
IF kadr.nomerceh > 6 then
MESSAGE "Нет такого цеха, повторите"
NEXT FIELD NOMERCEH
ENF IF
END INPUT
DATABASE zawod
. . .
let nc= wyborceh()
. . .
FUNCTION wyborceh() # Выбор цеха, для внесения изменений
DEFINE counter int
DEFINE ceharr ARRAY[25] OF RECORD # массив для хранения
nomerceh int, # номерцеха данных из таблицы
nameceh char(20) # название цеха ceh
END RECORD
# Открыть окно с рамкой и вывести в него экранную форму cehform
OPEN WINDOW cehwind AT 4 ,6 WITH FORM "cehform"
ATTRIBUTE(BORDER)
# Объявить курсор для выбора содержимого из таблицы ceh
DECLARE cehcurs CURSOR FOR
SELECT * FROM ceh ORDER BY nomerceh
# Выполнить запрос и все выбранные строки поместить в програм-
# ный массив ceharr
LET counter = 0
FOREACH cehcurs INTO ceharr[counter+1].*
LET counter = counter + 1
IF counter >=25 THEN EXIT FOREACH END IF
END FOREACH
# счетчик counter равен фактическому числу строк выданных в
# курсор
MESSAGE "Выберите цех и нажмите CR"
# Вывести в экранный массив cehscreen в экранной форме cehform
# counter первых строк из программного массива ceharr
call set_count(counter)
DISPLAY ARRAY ceharr TO cehscreen.*
ON KEY (CONTROL-M) EXIT DISPLAY
END DISPLAY
# Прервать показ экранного массива при нажатии клавиши CR
# закрыть окно с экранной формой cehform
CLOSE WINDOW cehwind
let counter=arr_curr() #номер строки массива,
#на котором нажато CR
RETURN ceharr[counter].nomerceh #номер цеха,
#на котором нажато CR
END FUNCTION
А это пользователь увидит на экране:
ѓ'ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ' ѓљ номер цех ѓљ ѓљ [3 ] [токарный ]ѓљ ѓљ [4 ] [гараж ]ѓљ ѓљ [5 ] [конюшня ]ѓљ ѓљ [6 ] [столовая ]ѓљ ѓљ [ ] [ ]ѓљ ѓљ Выберите цех и нажмите CR ѓљ ѓ"ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ›ѓ"
DATABASE zawod
SCREEN
{
номер цех
[f00] [f001 ]
[f00] [f001 ]
[f00] [f001 ]
[f00] [f001 ]
[f00] [f001 ]
}
TABLES
ceh
ATTRIBUTES
f00 = ceh.nomerceh;
f001 = ceh.nameceh;
INSTRUCTIONS
screen record cehscreen[5] (ceh.*)
END
В секции DATABASE указана база данных; в секции SCREEN задана картинка, которая будет рисоваться на экране; В TABLES указываются таблицы, в ATRIBUTES указываются имена экранных полей, (и, возможно, их атрибуты) а в INSTRUCTIONS объявлен экранный массив В качестве примера ниже приводится функция, реализующая простейший калькулятор. Возвращает значение вычисленного выражения. Скомпилируйте ее самостоятельно и посмотрите отладчиком, как она работает.
function kalkulator() # Калькулятор define wyravenie, kalkulator char(64), kolichestwo int define stroka_kalkulatora char(200) define beep char(1) let beep=ascii 7 open window kalkulator at 2,2 with form "kalkulator" attribute(border, form line first) input by name wyravenie, kalkulator without defaults before field kalkulator let stroka_kalkulatora= "select count(*),",wyravenie," from systables" whenever error continue prepare kalkulqtor_operator from stroka_kalkulatora if status<0 then display beep to kalkulator display "Неправильное выражение" to kalkulator next field wyravenie end if declare kalkulator cursor for kalkulqtor_operator foreach kalkulator into kolichestwo, kalkulator if status<0 then display beep to ka Использованная в подпрограмме экранная форма должна быть описана в файле kalkulator.per и откомпилирована при помощи компилятора form4gl.DATABASE formonly SCREEN { Калькулятор. Чтобы закончить нажмите ESC [wyravenie ] [kalkulator ] } ATTRIBUTES wyravenie =formonly.wyravenie; kalkulator=formonly.kalkulator; ENDНазад || Оглавление || Вперед
Используются технологии uCoz