Добавил:
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 - рутины
- •Планирование файлов
- •Память и сборка мусора

1.1. КОМАНДЫ 31
Нужно отметить, что при выполнении тела цикла сама переменная
цикла может принять и неопределенное значение при выполнении команд kill или new. В этом случае при очередной итерации цикла производится ее чтение и генерируется не ошибка доступа к неопределенной
переменной (код M6), а специально зарезервированная ошибка доступа
к неопределенной переменной цикла (код M15).
Для трехаргументной формы for условие окончания итерации проверяется каждый раз перед выполнением команд цикла. При этом команда
поступает в зависимости от знака приращения итерации - если приращение положительное, то цикл прекращается если значение переменной
цикла стало больше конца цикла и если приращение отрицательное, то
цикл прекращается если значение переменной цикла стало меньше конца цикла. В целом, синтаксис команды for в трехаргументной форме
определен наиболее ожидаемым для разработчиков образом.
Интересно, что для двухаргументной и трехаргументной формы параметры цикла (приращение и окончание) командой for вычисляются
строго однократно, перед первым выполнением цикла и далее изменение
значений входящих в эти выражения, не влияют на выполнение for команда будет строго пользоваться вычисленными первоначально значениями.
Одной из наиболее интересных особенностей команды for в языке
MUMPS является возможность указать несколько аргументов, как было
упомянуто ранее. Аргументы применяются последовательно к переменной цикла, один за другим. При этом разные аргументы могут иметь
разную форму - одноаргументную, двухаргументную и трехаргументную.
Пример трех аргументов для команды for, и все три в одноаргументной
форме:
USER>for i="abc","def","qwe" w i,!
abc
def
qwe
USER>
Вариант комбинирования различных форм:
USER>for i="abc","def",1:1:5,"qwe" w i,!
abc
def
1
2
3

32 ГЛАВА 1. СРЕДА ИСПОЛНЕНИЯ
4
5
qwe
USER>
Возможность указать подряд несколько одноаргументных форм через
запятую иногда приводит к тому, что разработчики считают это отдельной формой команды for, выполняющей итерации по перечисленному
списку:
USER>for i="abc","def","qwe" w i,!
abc
def
qwe
USER>
На самом деле это не так, это несколько одноаргументных форм, и
вместе с ними возможно смешивание любых других форм команды for
кроме, конечно, вечного цикла.
Что еще интересно, все три условные команды языка MUMPS, if, else
и for, являются строго стандартными, различные реализации языка не
отклоняются от стандартного их определения и к ним не были добавлены
другие условные команды.
Кроме того, что команда for может быть прервана безаргументной командой quit или генерацией ошибки, нормальный ход выполнения цикла,
естественно, может быть прерван безусловным переходом к явно указанной строке. В этом случае исполняющая система MUMPS отменяет
текущий контекст выполняемых циклов и выполнение команд продолжается вне контекста цикла. Разумеется, после безусловного перехода
по goto никакие итерации в текущем контексте более не имеют смысла, но сохраняются изменения локальных переменных, использованных
в качестве переменных цикла.
Это общее правило для любых языков програмирования, допускающих безусловный переход в контексте цикла, за исключением перехода
в тот же контекст. Но для строчно-ориентированных интерпретаторов
понятие перехода в тот же контекст цикла не поддерживается.
В отношении условных команд (if, else, for) действует специальное
синтаксическое правило языка - для них не допускается использование
постусловий. Кроме того, для команды for синтаксически не допускается косвенное задание аргумента. Косвенность допускается лишь для
вычисления имени переменной цикла, начального значения, приращения

1.1. КОМАНДЫ 33
и условия окончания итерации. Задание же структуры цикла косвенно
не поддерживается.
Стандарт на язык в отношении команд цикла for предусматривает, что
в качестве переменных цикла могут быть использованы исключительно локальные переменные. Автор пока не встретил веских оснований,
почему бы в качестве переменной цикла не использовать глобальную
переменную. Формально, для виртуальной машины при исполнении команды for нет существенных отличий, с какой именно переменной надо
выполнить действия, с локальной или глобальной. Но в настоящее время
язык определен именно таким образом, и все MUMPS системы запрещают использовать в качестве переменной цикла что-либо иное, кроме
локальной переменной.
Этот запрет поддерживается даже если переменная цикла задана косвенно. Такой код
USER>f ^i=1:1:2
приведет к синтаксической ошибке времени трансляции, а такой
USER>s n="^i"
USER>f @n=1:1:2
к синтаксической ошибке времени выполнения.
Но язык не ограничивает множество имен для переменной цикла
только неиндексированными локальными переменными, и разработчики могут свободно использовать также индексированные локальные переменные. При этом все MUMPS системы вычисляют имя переменной
цикла (даже если в качестве индексов указаны волатильные выражения)
однократно, и далее используют только его.
То же самое правило об однократном вычислении (при начале выполнения цикла) распространяется на начальное значение, приращение
и значение окончания цикла. Даже если они заданы волатильными выражениями, команда for будет использовать только те значения, которые
были получены при их первом вычислении.
1.1.3 Команды передачи управления
Для изменения последовательного хода программы используются команды передачи управления. К таким относятся команды, действие которых
приводит к смене текущей строки исполнения без возврата или с возвратом управления на следующую команду.

34 ГЛАВА 1. СРЕДА ИСПОЛНЕНИЯ
В целом, все, что исполняет MUMPS система, задается либо совокупностью имеющихся рутин, либо интерактивно введенной строкой, либо
косвенным исполнением. Каждая из рутин представляет собой текст,
рассматриваемый как последовательность строк. В принципе, для строчно - ориентированной машины исполнения не имеет значения, на какую
из других имеющихся строк (в этой же рутине или в другой) передать
управление.
Для того чтобы можно было указать строку рутины, есть в любом
случае наиболее простой способ - это указать ее номер, например рутина
ˆABC, строка 14.
Но такой способ неудобен в случае если рутины модифицирутся и номера строк могут измениться со временем. Для того чтобы указать определенную строку, ей приписывается так называемая метка. В MUMPS
для описания метки не требуется никаких деклараций или отдельного
синтаксиса - просто если строка рутины начинается не с пробельного
символа, то первое слово строки и есть метка.
При исполнении строки с меткой сама метка не содержит никаких
указаний исполняющей системе MUMPS за исключением того, что именует строку, в которой она находится.
Для того чтобы передать управление на другую строку, нужно указать рутину (можно не указывать если это текущая рутина), метку, либо
смещение относительно начала рутины, либо метку плюс смещение относительно метки.
Механизм использования меток в MUMPS используется и для организации безусловного перехода и для перехода на подпрограмму с возвратом из нее. Одна и та же метка может быть использована в обоих
случаях. Отношение к метке и ее значение определяется в отличие от
других языков не тем, как она описана, а тем, как она вызвана. При
трансляции рутины транслятор еще не знает, как будет использована
строка с меткой, поэтому готов выполнить вызов любой строки, обеими
вариантами.
Собственно, самих подпрограмм в понимании других языков программирования, как самостоятельной цельной единицы трансляции, в
MUMPS не существует. Будут ли строки рутины работать как просто
последовательный набор строк или как подпрограмма, определяет разработчик.
Автору доводилось работать с прикладными системами, написанными
на MUMPS, часть рутин которых организована в виде логически связанного списка. Каждая из рутин (кроме последней) в последней своей
строке содержит команду безусловного перехода на первую строку следующей рутины. В итоге весьма большое количество кода выполняется

1.1. КОМАНДЫ 35
последовательно. При разработке реально больших систем, где даже с
применением столь компактного языка, как MUMPS, объем кода может
оказаться очень большим, и такие возможности языка были использованы весьма грамотно. В любом случае, язык MUMPS не будет навязывать
какой-либо стиль и лишать каких-либо возможностей.
Если после имени метки разработчик ставит в круглых скобках перечень аргументов через запятую, то такая метка становится меткой с
параметрами и ее надо вызывать строго как подпрограмму, с передачей
параметров. При вызове исполняющая система MUMPS сопоставляет
переданные фактически параметры объявленным формальным параметрам таким образом, что следующие после метки команды (неважно в
этой же строке или в следующей) уже исполняются в контексте, в котором эти формальные параметры являются локальными переменными.
Если метка была объявлена с параметрами, то на нее нельзя перейти безусловным переходом, поскольку исполняющая машина (интерпретатор) MUMPS не знает как и что сопоставить этим параметрам как
локальным переменным нового контекста, при безусловном переходе не
создается новый контекст или фрейм на стеке.
К командам, передающим управление, в языке MUMPS относятся:
1. HALT - команда останавливает процесс, после выполнения этой
команды процесс завершает работу и далее никакие команды не
выполняются.
2. DO - управление передается либо на указанную метку как на подпрограмму, либо на последующий блок строк.
3. QUIT - управление возвращается из подпрограммы либо прерывается выполнение цикла.
4. XECUTE - команда выполняет свой аргумент как последовательность строк.
5. GOTO - управление передается безусловным переходом на указанную строку.
Команда HALT (H) останавливает процесс полностью, все локальные переменные процесса пропадают, и память занятая процессом освобождается. Все устройства ввода-вывода, которые были открыты закрываются, и все блокировки, установленные процессом, снимаются. Если
команда выполнилась, то дальнейшие команды в этой или последующей
строке не выполняются.

36 ГЛАВА 1. СРЕДА ИСПОЛНЕНИЯ
Команда DO (D) имеет две формы - можно указать метку в рутине
(с возможным смещением) для вызова в качестве подпрограммы либо
безаргументная форма, при которой последующий блок строк рассматривается как подпрограмма. Например
do label^rtn
передает управление на рутину rtn начиная с метки label, и в новом
контексте создается стековый фрейм. Если в вызванном коде будет выполнена команда quit, то эта команда вернет управление на команду,
следующую после команды do, обратившейся к метке. В этом случае
вызов соответствует вызову подпрограммы или процедуры.
Чтобы передать параметры подпрограмме, нужно чтобы вызываемая
метка принимала параметры и чтобы вызывающий код передал их. Параметры в обоих местах указываются в круглых скобках. Если есть подпрограмма
label(param)
write "param = ",param,!
quit
то ее можно вызвать с передачей параметров:
do label^rtn(789)
В вызываемом коде команды следующей в строке после метки уже
работают в контексте нового стекового фрейма и параметр param уже является локальной переменной с областью видимости от текущего уровня
стека и далее.
Если подпрограмма была вызвана командой DO, то от подпрограммы
не ожидается возврат значения и команда QUIT должна быть использована в безаргументной форме, иначе при выполнении кода система
генерирует ошибку. Если требуется вызов подпрограммы с возвращаемым значением, то для возврата значения должна быть использована
аргументная форма команды quit и метка должна быть вызвана как пользовательская функция, с указанием символов $$ перед именем метки.
В этом случае метку можно использовать как часть вычисляемого выражения произвольной сложности. Например, функция вычисляющая куб
числа:
CUBE(value)
quit value*value*value
должна быть вызвана с указанием вызова пользовательской функции:

1.1. КОМАНДЫ 37
set result=123+$$CUBE^rtn(789)+456
Если подпрограмма вызывалась как пользовательская функция с ожиданием возврата, то управление из нее должно возвращаться командой
quit с аргументом. Значение аргумента вычисляется как выражение и
возвращается в место вызова. Если такая функция прерывается и управление возвращается безаргументной формой команды quit, то система
генерирует ошибку.
В других языках есть возможность указать неименованные части
функции как блок операций, исполняемых цельно, например в языке
C++ все что ограничено фигурными скобками исполняется как единый
последовательный контекст:
funcname( int param)
{
// code block 0
...
if(param == 2)
{
// code block 1
...
for(int i = 1; i < 4; i++)
{
// code block 2
...
}
}
else
{
// code block 3
...
}
return;
}
В языке MUMPS, как в строчно - ориентированном, нет возможности
указать границы блока при трансляции текста рутины. В других аналогичных строчно - ориентированных языках могут быть использованы,
например, синтаксические конструкции NEXT, являющиеся не столько
командами, сколько операторными скобками ораничения блока команд
или операторов.
В языке MUMPS, как строчно-ориентированном, вместо этого применяется специальный маркер в начале строки, символ точка. Если строка
начинается с точки, это означает что строки с равным числом точек
в начале, и идущие последовательно, образуют один уровень вложения

38 ГЛАВА 1. СРЕДА ИСПОЛНЕНИЯ
блока строк. Если нужно организовать блок в блоке, то ставится две
точки, и так далее. При использовании безаргументной формы команды
DO интерпретатор переходит в режим перехода от строки к строке с
учетом числа точек в начале строки. Если начали выполнять от уровня
с числом точек N, то все последующие строки идущие подряд с числом
точек N + 1 считаются принадлежащими блоку. Как только интерпретатор встречает строку у которой число точек меньше или равно N это
означает что выполняемый блок строк закончен. Если при этом интерпретатор встречает строки с числом точек больше N + 1, то они просто
пропускаются. Например
write "begin",!
if a=1 do
. write "in block",!
. s a=0
write "end",!
Здесь две строки
. write "in block",!
. s a=0
образуют неименованный блок строк, выполняемый безаргументной формой команды do как подпрограмма. При переходе от строки
. s a=0
к следующей интерпретатор обнаруживает, что число точек стало меньше чем у выполняемого блока и выполняет неявную команду quit в безаргументной форме, и управление возвращается к команде, следущей
за командой do. В строке после команды do в данном случае ничего
не указано, и интерпретатор переходит к следующей строке. Но в ней
число точек больше чем число точек текущего контекста (0), поэтому
обе строки с точками просто пропускаются и интерпретатор переходит
непосредственно к выполнению команды после строк с точками
write "end",!
После команды do в этом примере также могут стоять команды. Нужно лишь учесть, что для вызова блока строк как подпрограммы нужна
именно безаргументаня форма команды DO, поэтому необходимо два
пробела:

1.1. КОМАНДЫ 39
write "begin",!
if a=1 do write "after do",!
. write "in block",!
. s a=0
write "end",!
Нужно отметить, что в системе Cache старших версий поддерживается расширенный синтаксис, который включает как свободное форматирование пробелов по контексту, допускающем их, так и применение фигурных скобок для ограничения области действия синтаксических конструкций. В частности, безаргументная команда DO и некоторые другие
в этих условиях могут быть применены не к последовательности строк с
точками, а к поледовательности команд, ограниченной фигурными скобками.
Команда GOTO (G) выполняет просто переход. Исполняющая система MUMPS начинает выполнять первую команду находящуюся на указанной строке. Строка может иметь метку, но не может иметь у метки
параметры. Если при выполнении команды GOTO действовал контекст
цикла, то он отменяется. Контекст стека полностью сохраняется. Вызываемый код может вызвать команду quit, которая вернет управление.
В отношении команды перехода GOTO язык MUMPS не имеет ограничений как в других языках. Например, в языке C или Pascal переход
возможен только в пределах той же самой функции, в языке Assembler
переход возможен на метку только в пределах команд ассемблерного модуля, но не в другой ассемблерный модуль, ассемблерные вставки в коде
C / C++ могут как допускать, так и не допускать переход ассемблерной
командой в контекст другой функции в зависимости от транслятора. В
случае с MUMPS свобода перехода полная, включая возможность вычислять смещение как выражение и применять косвенные формы фрагментов метки.
Для перехода действует только одно единственное ограничение - смещение относительно метки, если оно указано, не должно быть отрицательным числом, таковы требования стандарта языка MUMPS.
Примеры команд GOTO:
; Routine R01
func(param)
s value=123
i +param goto param+param^R02
continue
w value
...

40 ГЛАВА 1. СРЕДА ИСПОЛНЕНИЯ
; Routine R02
param
1 w "handler of 1",! goto continue^R01
2 w "handler of 2",! goto continue^R01
3 w "handler of 3",! goto continue^R01
...
Как и положено в компьютерной литературе, этот пример мало похож
на более-менее осмысленный, но показывает примерные возможности организации переходов. Из текста первой рутины производится переход к
строкам второй, и обратно из второй к строке в первой. При этом можно
вычислять смещение для строки перехода. В синтаксической конструкции
goto param+param^R02
goto означает команду, первое вхождение param означает имя метки,
второе вхождение param означает величину смещения в строках относительно метки, и R01 означает имя рутины, в которой эти строки нужно
найти.
Кроме того, что в языке MUMPS можно организовывать переходы
произвольным образом, добавлением постусловий как для команды, так
и для аргумента, можно организовывать также переходы по условию.
В частности, следующие синтаксические конструкции не в точности,
но приблизительно эквивалентны, за исключением взведения системной
переменной $TEST:
i +param goto param+param^R02
g:param param+param^R02
g param+param^R02:param
Команда XECUTE (X) имеет только аргументную форму, и при выполнении команды значение аргумента используется как последовательность команд. Выполнение команды xecute приводит к выполнению команд из аргумента как если бы в текущей рутине существовала метка с
именем не равным ни одной имеющейся метке:
uniqlabel
xecutearg
quit
Перед непосредственно выполнением команд, входящих в аргумент,
команда XECUTE создает новый стековый фрейм. После выполнения
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
