Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:MUMPS СУБД. Практика применения и опыт программирования.pdf
X
- •Предисловие
- •Введение
- •Среда исполнения
- •Команды
- •Команды присваивания
- •Условные команды
- •Команды передачи управления
- •Команды ввода-вывода
- •Служебные команды
- •Постусловия
- •Операторы
- •Переменные
- •Числа и строки
- •Функции
- •$DATA
- •$GET
- •$ORDER
- •$NEXT
- •$QUERY
- •$NAME
- •$QLENGTH
- •$QSUBSCRIPT
- •$ASCII
- •$CHAR
- •$EXTRACT
- •$PIECE
- •$LENGTH
- •$REVERSE
- •$FIND
- •$TRANSLATE
- •$JUSTIFY
- •$FNUMBER
- •$TEXT
- •$RANDOM
- •$VIEW
- •$SELECT
- •$STACK
- •Списковые функции
- •Битовые функции
- •Модули
- •Рутины
- •Передача параметров
- •Неопределенные значения
- •Шаблоны
- •Косвенность
- •Косвенность имени
- •Косвенность индексов
- •Косвенность метки
- •Косвенность аргумента
- •Косвенность шаблона
- •Интерпретатор
- •Голая ссылка
- •Очередность выполнения
- •Очередность вычисления выражений
- •Очередность вычисления имен
- •Стекование $test
- •Комментарий
- •Стандарт и расширения
- •Глобалы
- •B-дерево
- •Кодирование индексов
- •Размер блока
- •Кеширование блоков
- •Структуры
- •Индексация
- •Группировка
- •Каноничность индексов
- •Маппинг
- •Индексация данных
- •Общие принципы
- •Механизм поддержки индекса
- •Простой индекс
- •Составной индекс
- •Покрывающий индекс
- •Кластерный индекс
- •Хеш-индекс
- •Битмап индекс (bitmap)
- •Битслайс индекс (bitslice)
- •Нормирование значений
- •Выборки по индексу
- •Многоиндексная выборка (zig-zag)
- •Дифференциальное индексирование
- •Индексация длинных атрибутов
- •Межтабличный индекс
- •Индекс с условием на вставку
- •Индекс на вычисляемый атрибут
- •Индекс поиска по фрагменту
- •Индексация для шаблона (like)
- •Индексация уникального атрибута
- •Массовое перестроение индексов
- •Операции с древовидными индексами
- •Операции с битовыми индексами
- •Сортировка по индексу
- •Статистики и кардинальность
- •Конкурентный доступ
- •Параллельность выполнения
- •Блокировки
- •Функция $INCREMENT
- •Транзакции
- •Блокировки в транзакциях
- •Функция $BIT
- •Дедлоки
- •Обработка ошибок
- •Состояние ошибки
- •ZTRAP
- •GT.M
- •MiniM
- •ETRAP
- •Определение
- •$ETRAP
- •$ECODE
- •$ESTACK
- •Ошибки в обработчике ошибок
- •$STACK()
- •Трассировка
- •BREAK
- •MiniM Debugger
- •Serenji Debugger
- •Внешний мир
- •Общие принципы
- •Терминальный интерфейс
- •Сокеты
- •HTTP клиент
- •Вебсервер на MUMPS
- •WebLink
- •Проблемы HTTP
- •Поверх HTTP
- •Подключаемые DLL (SO)
- •Файлы
- •Внешние процессы
- •Порты
- •Практика применения
- •Терминальный режим
- •Редакторы рутин
- •Экспорт и импорт
- •Препроцессор
- •Формат $HOROLOG
- •Опции устройств
- •$X и $Y
- •Возврат результатов
- •Возврат по значению ($$)
- •Возврат по ссылке
- •Запись в предопределенную переменную
- •Возврат значений косвенно
- •Итеративный возврат
- •Потоковый возврат
- •%Z - рутины
- •Планирование файлов
- •Память и сборка мусора

6.2. ТЕРМИНАЛЬНЫЙ ИНТЕРФЕЙС 411
строку данных и, при необходимости, восстановление режима отображения эха на экране (повтор, показ введенных символов). Эти переключения выполняются неявно. Кроме того, для терминальных устройств
поддерживается специальная обработка входного потока данных таким
образом, чтобы сигнал от нажатия Ctrl+C распознавался корректно и
приводил к прерыванию по ошибке.
Кроме того, после возврата управления после исполнения введенной
команды терминальные режимы могут проводить дополнительные действия по обработке ошибок по умолчанию, обычно это вывод диагностического сообщения в зависимости от типа и версии MUMPS системы.
К терминальным интерфейсам относятся способы ввода, комбинирующие ввод с клавиатуры в качестве входного потока для чтения и вывод
на экран в качестве потока записи. Это могут быть в зависимости от
типа MUMPS системы либо специальные программы, как терминал в
Cach´e, либо консоль в понимании операционной системы, либо телнетинтерфейс, либо реальный физический терминал, подключенный по последовательному каналу.
При использовании MUMPS систем разработчики пользуются терминальным интерфейсом как основным для выполнения подпрограмм или
запуска служебных утилит и первое, что разработчик ищет при использовании новой MUMPS системы или системы новой версии - это способ
запуска предпочтительного для него терминала. Это может быть или
встроенная консоль или телнет клиент. При запуске такой программы в
MUMPS системе для ее обслуживания автоматически запускается новый процесс. Для выхода из программы и завершения процесса (но не
завершения работы сервера в целом) используется команда HALT (H).
В отношении терминальных интерфейсов поддерживается соглашение о специальной трактовке управляющих последовательностей команды WRITE:
Команда Действие
WRITE # Очищает экран полностью и позиционирует ка-
ретку ввода в левый верхний угол.
WRITE ! Перевод строки с прокруткой экрана при необ-
ходимости.
WRITE ?N Позиционирование каретки вправо по горизон-
тали до указанной позиции.
В определенном смысле, в качестве терминала могут быть использованы также электрические печатающие машинки, вывод в этом случае
производится на бумагу и команда WRITE # приводит к переходу на

412 ГЛАВА 6. ВНЕШНИЙ МИР
следующую страницу.
Также, для терминальных устройств поддерживается буквальная трактовка системных переменных $X и $Y. Они возвращают текущее положение каретки на экране и присваивание значений этим переменным
перепозиционирует каретку на экране в указанное место. Применение
терминальных устройств при использовании MUMPS систем было столь
важно (и остается и сейчас), что специально для них в язык были введены эти системные переменные. Думается, что при появлении в будущем устройств ввода-вывода, сравнимых по важности с терминальными, для них также могут быть введены специальные и стандартные
системные переменные, возвращающие характеристики состояния отображения, вместо набора отдельных системных функций.
При использовании стандартных терминальных устройств экран представляется как матрица символов 80x25. При выполнении команд записи терминальному устройству передается последовательность символов,
которую он использует для отображения - либо выводит на экран, либо
изменяет характеристики отображения на экране, режим показа символов. Размер экрана 80x25 это обычный размер по умолчанию, но во
многих терминальных клиентах этот размер может быть изменен.
К первой группе передаваемых последовательностей от сервера к клиенту относятся печатные символы, отображаемые как есть, выводимые
последовательно с переносом вывода на следующую строку, если текущая строка закончена. Это основной режим вывода данных, используемый для терминальных устройств. Например, набор команд вывода строк
и комбинирование с форматом перевода строки производит вывод вполне
читаемого текста.
Ко второй группе относится набор эскейп последовательностей. Эскейп последовательность состоит в целом из символа ESC, за которым
следуют опции и последовательность завершается распознаваемым символом. От символа ESC (десятичный код 27, шестнадцатеричный 1B)
отсчитывается следующий за ним символ. Если это символ окончания
последовательности, то терминал выполняет команду соответствующую
этому символу, иначе до символа завершения распознает значения параметров команды.
Набор поддерживаемых эскейп последовательностей зависит от типа устройства. Обычно устройства поддерживают наборы эскейп последовательностей VT, самым распространенным по применению из них
является набор команд VT-100. Различные телнет-клиенты могут поддерживать как определенный набор эскейп последовательностей, так и
несколько, и переключаться с одного на другой. Полные списки управляющих последовательностей приведены в соответствующих справочни-

6.2. ТЕРМИНАЛЬНЫЙ ИНТЕРФЕЙС 413
ках.
Некоторые эскейп-команды, иллюстрирующие их применение:
EscB Переместить каретку на одну строку вниз.
Esc[ValueB Переместить каретку на Value строк вниз.
При выполнении таких последовательностей на экране форматирует-
ся:
USER>w 123,$c(27),"B",456
123
456
USER>w 123,$c(27),"[3B",456
123
456
USER>
Общий принцип применения эскейп последовательностей прост, и по
сути, выполняется передача специального символа (ESC), при необходимости символа начала списка параметров, значения параметров и управляющего символа команды.
Передача нужного набора последовательностей обычно оформляется
в виде библиотек соответствующих функций. При использовании таких
библиотек разработчики могут управлять экраном и отображением на
нем в разнообразных режимах псевдографики, управлять цветом символов и фона, организовывать псевдо - оконный терминальный интерфейс,
отображать на экране разнообразные управляющие элементы ввода (рамки, заголовки, кнопки, строки ввода, списки).
По умолчанию MUMPS системы поддерживают набор так называемых мнемоник, которые по сути и являются такими функциями, применяющимися к текущему устройству вывода. Мнемоника используется
в командах чтения и записи как параметр команды, содержит имя и
опционально собственные параметры, например:
W /CUP(5,12)
Из-за разнообразия наборов эскейп последовательностей и типов терминальных устройств разработчики зачастую поддерживают также наборы управляющих последовательностей, описывающие устройство. Такие
наборы хранятся в глобалах и при необходимости выполнения действия
библиотека читает из глобала необходимую для текущего типа устройства последовательность и выполняет ее. Если используется программа

414 ГЛАВА 6. ВНЕШНИЙ МИР
с такими настройками, то подключение к ней еще одного типа терминального устройства становится простым делом - достаточно следовать
инструкции на программу в части как описать или определить нужные
последовательности.
Что интересно, различные терминальные устройства могут также
возвращать различные последовательности символов для служебных и
управляющих клавиш (Ctrl, Shift, Alt, F1-F12 и др.). На эти последовательности также может производиться настройка в зависимости от типа
устройства.
Много лет назад, при появлении первых MUMPS систем в России
(это была система MSM фирмы Micronetics), Рустем Османов, талантливый программист, разработал терминальную библиотеку под названием
%WM. В нее входили функции чтения символов, управление выводом и
организация примитивов - псевдоокна с рамками и заголовками, разнообразные управляющие элементы. На основе этой библиотеки был написан терминальный менеджер рутин и глобалов в стиле двухпанельного
Norton Commander, и эта программа работала на множестве терминальных устройств, включая различные телнет - клиенты. Также эта библиотека использовалась, и сейчас используется, в прикладных разработках.
После того, как Рустем Османов ушел от нас, эту библиотеку использовали и модернизировали несколько различных фирм и в настоящее время существует несколько независимых форков этого проекта,
пошедших различными путями развития и в некоторых случаях уже не
совместимые друг с другом.
Независимо от библиотеки %WM, но на основе тех же принципов
(Рустема Османова) и полностью с нуля другой талантливый программист, Андрей Вологдин, разработал аналогичную псевдооконную библиотеку %aWM и построил на ней как двухпанельный менеджер рутин
и глобалов AltNC, так и несколько прикладных разработок. Библиотека
%aWM отличается полнотой поддержки самых различных MUMPS систем, операционных систем и терминальных устройств. При появлении
новой MUMPS системы эта разработка (%aWM) может быть портирована на нее достаточно просто и разработчики могут достаточно быстро
получить сильный и гибкий инструмент.
Терминальные приложения отличаются от привычных в настоящее
время двухуровневых клиент - серверных и трехуровневых с использованием промежуточных серверов приложений. Перед пользователем экран с псевдографикой, достаточно крупные шрифты, и клавиатурный
ввод. На экране размещается объем информации, необходимый для выполнения операции ввода, переход от одного управляющего элемента к
другому выполняется обычно нажатием клавиши Enter.

6.2. ТЕРМИНАЛЬНЫЙ ИНТЕРФЕЙС 415
Отсутствие необходимости попадать курсором мышки в небольшие
поля и вообще отсутствие использования мыши приводит к существенному увеличению скорости ввода. Операторы, которым приходится вводить множество информации, предпочитают (при наличии альтернативы) именно псевдографические интерфейсы с клавиатурным вводом. Такие интерфейсы, в частности, используются в терминалах кассиров супермаркетов, на рабочих местах банковских сотрудников, при продаже
билетов. Конечно, не все такие программы построены на MUMPS системах, и часть из них построены как толстый клиент, но принципы
отображения информации те же.
Общий объем передаваемой от терминала к серверу и обратно информации столь мал по сравнению с другими способами организации
клиентских мест, что множество терминалов могут обслуживаться как
одним сервером с не самой высокой производительностью, так и связываться по каналам связи с практически произвольной пропускной способностью. Даже если серверу необходимо передать полностью все изображение экрана, в самом наихудшем случае это составляет 25∗80 = 2000
байт значимых данных. При использовании управляющих эскейп последовательностей объем может быть увеличен до примерно 8000 − 10000
байт. Такой объем может быть передан в течении времени реакции оператора по практически любым каналам связи. При этом обычно нет необходимости передавать такие объемы непрерывно, и, в действительности,
за время реакции оператора передаются в сотни раз меньшие объемы,
для обновления только изменяемых позиций.
В терминальных программах нажатие символа обрабатывается на
сервере - каждое нажатие отсылается серверу, в ответ терминалу возвращается инструкция что необходимо вывести на экран. И, фактически,
уже в течении ввода строки в дополнительных управляющих элементах
программа может сразу отображать изменение данных, например, при
организации инкрементального ввода автоматически подбирать по индексу подходящие варианты или альтернативы.
Как следствие технических особенностей терминальных программ,
они отличаются существенно меньшими потребностями вычислительных
ресурсов, пропускной способности каналов связи, уменьшенным временем реакции сервера. При этом эргономика таких программ для операторов ввода практически оптимальна - в большинстве случаев операторам
достаточно использовать малую часть клавиатуры, keypad, с цифрами и
клавишей ввода.
В качестве операционных систем на клиентской стороне могут быть
использованы практически любые, на которых может быть запущена терминальная программа, обычно это или телнет или SSH клиент с шифро-

416 ГЛАВА 6. ВНЕШНИЙ МИР
ванием канала обмена. Поэтому терминально ориентированные программы обладают значительным временем жизни, существенно большим чем
время жизни отдельных версий операционных систем, и существенной
независимостью от аппаратных возможностей клиентских компьютеров
- они могут быть изменены независимо от основной программы. И, кроме того, терминально ориентированные программы всегда работают с
текущей, актуальной версией программы, размещенной на сервере и обновляемой централизованно.
6.3 Сокеты
С появлением в массовом использовании сетевого протокола TCP/IP
он стал использоваться в MUMPS системах также, как и другие типы устройств, в качестве одного из типов, и в настоящее время все
MUMPS системы поддерживают этот тип обмена в качестве одного из
стандартных типов.
Протокол TCP/IP представляет собой протокол доставки пакетов в
определенной последовательности с богатыми возможностями адресации и маршрутизации, поддерживающийся на множестве операционных
систем.
С точки зрения программистов, это протокол передачи байт, двунаправленный, на каждом из концов соединения работает программа,
используя сокет. Доставкой информации (последовательности байт) от
одного сокета до другого занимается сетевая аппаратура и серверное
программное обеспечение.
Для установления соединения между двумя программами необходимо, чтобы одна из них ожидала соединения. Соединение для такой ожидающей программы с точки зрения программистов характеризуется номером порта TCP/IP, в протоколах IpV4 их может быть всего до 65535.
Часть из этих портов зарезервирована RFC для программ определенного
назначения, остальные могут быть использованы на свое усмотрение. В
принципе, с технической точки зрения, резервирование номеров портов
не означает запрета на их использование, это только ожидаемый номер
порта (или порт по умолчанию). Разумеется, все порты могут быть использованы программами на MUMPS, если они уже не заняты другими
процессами.
Другая программа подключается к ожидающей на указанном компьютере и на указанном порту. Далее производятся операции чтения,
записи, и соединение разрывается. В этом сценарии программа, ожидающая подключение, называется сервером, а подключающаяся к нему -

6.3. СОКЕТЫ 417
клиентом.
Все, что передается через сокеты, уже определяется договоренным
протоколом обмена между этими двумя программами. Существует как
множество стандартных протоколов обмена, так и частных, разработанных для применения в определенных программах. Например, протокол
HTTP описывает что должен передать клиент и в каком кодировании,
и что должен ответить сервер. В этом случае обе стороны называются
соответственно HTTP - клиентом и HTTP - сервером.
Большинство протоколов семейства RFC в укрупненном виде построены на одних и тех же принципах - сначала передающая сторона (неважно, будь то клиент или сервер) передает заголовок запроса / ответа, за
ним тело запроса / ответа с его данными. В заголовке описывается кому
передаются данные, что необходимо сделать, как рассматривать способ
кодирования данных, учетная информация о промежуточных серверах,
и другое. При этом практически все протоколы и способы кодирования RFC используют одинаковые соглашения о способах кодирования,
о кодировании времени, о формировании адресов, о шаблонах ответа и
принципах формирования сообщений об ошибках.
Стандарт языка MUMPS не специфицирует точного синтаксиса именования устройств и в каждой из MUMPS систем такой способ именования устройств типа TCP/IP может быть свой собственный.
В качестве примера рассмотрим простенькую программку отправки
сообщения по SMTP протоколу:
send
n dev,str,to,saveio,err s to=15,saveio=$io
; mail message depended magics
n From,To s From="mail@address.here"
n subject s subject="This is mail subject"
n message s message="This is mail message"
s To=From
; server’s depended code
n smtpsrv,computer s smtpsrv="smtp.mail.address.here"
s computer="computernamehere"
; vendor depended code
s dev="|TCP|"_smtpsrv_":25"
o dev:("rwt"):to e s err="open" g err
; common code here
u dev
r str:to i $e(str)’="2" s err="connect" g err
w "HELO ",computer,!
r str:to i $e(str)’="2" s err="helo" g err
w "MAIL From: ",From,!
r str:to i $e(str)’="2" s err="mail" g err
w "RCPT To: ",From,!

418 ГЛАВА 6. ВНЕШНИЙ МИР
r str:to i $e(str)’="2" s err="rcpt" g err
w "DATA",! r str:to i $e(str)’="3" s err="data" g err
w "From: ",From,!,"To: ",To,!
w "Subject: ",subject,!
w message,!
w ".",! r str:to i $e(str)’="2" s err="end" g err
w "QUIT",! r str:to
u saveio c dev
q
err
u saveio c dev
w "failed at ",err,!
w
q
Здесь отдельно собраны магические значения с именами серверов
для отправки сообщения, с адресом SMTP почты и зависимый от производителя код открытия TCP устройства. Устройство типа TCP открывается, делается текущим, в него согласно RFC на SMTP сообщения
записываются данные, читается ответ от принимающего SMTP сервера,
и соединение разрывается.
Это простейший код передачи сообщения. Все более мощные возможности SMTP могут быть добавлены, согласно RFC, по тем же принципам
- запись в устройство и чтение из устройства. К ним относятся кодирование национальных символов, передача сообщения в формате HTML,
передача приложений к сообщению.
Собственно сокеты TCP/IP для программиста различаются на три
большие группы по способу их использования:
1. Клиентский.
2. Серверный с собственным обслуживанием (listen).
3. Серверный с передачей обслуживающему процессу (accept).
Клиентский способ использования состоит в указании к какому серверу необходимо соединиться и по какому номеру порта. Обе характеристики указываются способом, зависимым от производителя MUMPS
системы. Такой клиентский сокет традиционно используется для передачи запроса серверу и получения ответа, либо для повторения этой
операции многократно в рамках одного соединения. После выполнения
задачи клиентская сторона закрывает соединение, а серверная продолжает ожидать дальнейших подключений. В зависимости от организации
серверной стороны она может как обслуживать только одно соединение,

6.3. СОКЕТЫ 419
так и несколько - пока клиентское соединение обслуживается, сервер
может принять и другие входящие соединения. Пример такого простого
клиентского соединения и был приведен ранее, с отсылкой почтового
SMTP сообщения.
Серверный сокет характеризуется лишь номером порта. Процесс открывает этот сокет на своем компьютере на заданном порту и ожидает
входящие соединения. Способ ожидания входящих соединений также
может отличаться для различных MUMPS систем. Часто ожидание входящего соединения для TCP устройства выполняется в виде команды
чтения. Если команда вернула управление, то это означает, что соединение выполнено. Реже операцию ожидания входящих соединений выполняют в виде команды USE со специальной опцией устройства. Если
команда выполнилась, то дается способ проверить было ли выполнение
прервано или было выполнено соединение.
Далее серверные сокеты уже различаются по способу обслуживания
запроса - будет ли выполнять запрос и отвечать командами записи текущий же процесс (второй из перечисленных способов использования)
или эта функция будет передана специально созданному для этих целей
процессу (третий способ).
Для выполнения третьего типа (такую операцию также называют
операцией accept) в MUMPS системах используется команда JOB с опцией передачи сокета новому процессу. Сокет, получивший входящее
соединение на операции accept, как-бы разъединяется на два на стороне
такого серверного MUMPS процесса, и вторая его копия передается в
управление новому дочернему процессу. После этого серверный процесс
также снова может перейти к операции accept и ожидать нового соединения. Способ передачи accepted - сокета новому процессу также зависит
от применяемой MUMPS системы и описывается в документации.
Кроме того, возможен вариант, что в MUMPS системе и операции
listen и accept выполняются в виде мнемоник /LISTEN или /ACCEPT.
Хотя на нижнем уровне API операционной системы запуск нового процесса с передачей сокета существенно зависит от операционной системы,
на уровне среды исполнения MUMPS в рамках MUMPS системы одного
производителя такое расхождение может отсутствовать, и операции могут различаться не между операционными системами, а между MUMPS
системами различных производителей. Поэтому при написании переносимого кода такие операции локализуют, чтобы их можно было легко
заменить и использовать другие.
Серверный сокет обычно используется в интерфейсе подключения
клиентских программ. На стороне MUMPS системы запускается процесс, ожидающий подключения в режиме accept. При подключении кли-

420 ГЛАВА 6. ВНЕШНИЙ МИР
ента процесс при необходимости выполняет действия по проверке прав,
возможности обслуживания, и запускает дочерний процесс с передачей
ему сокета. И уже дочерний процесс обменивается с клиентской программой, принимая запрос и отправляя ответ. Характер и способ обмена
образуют прикладной протокол. В случае если клиентский процесс отсоединился или соединение разорвано по иным причинам, серверный
процесс выполняет действия по завершению работы.
Протокол обмена между клиентом и сервером задается передаваемыми заголовками запроса и параметрами запроса. Обычно для передачи
данных используется один из способов определить конец передачи порции и для разделения одной порции данных от другой:
1. Критерий окончания - специальный символ, например перевод строки или другой.
2. Критерий окончания - тип команды, когда длина параметров опеределяется командой.
3. Критерий окончания - переданная ранее длина.
И в техническом отношении ничто не препятствует применению всех
трех способов в одном протоколе. Например, пусть клиентской программе необходимо передать команду выполнить строку команд. В этом случае возможна такая договоренность:
1. Передать байт "X".
2. Передать два байта, означающих длину последущей строки команд.
3. Передать саму строку на указанную ранее длину.
На серверной стороне процессу остается прочитать байт, и если это
код символа "X" то далее прочитать два байта, считая их длиной строки
команд, и далее прочитать строку на указанную длину.
Также возможно, например, такое соглашение для команды выполнения строки команд:
1. Передать строку "XECUTE", завершающуюся переводом строки.
2. Передать строку команд, завершающуюся переводом строки.
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
