Добавил:
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. КОМАНДЫ 21
где используются уже более осмысленные и значимые идентификаторы.
При использовании макросов препроцессора (в зависимости от того,
поддерживается ли препроцессор в используемой MUMPS системе или
нет) код может быть приведен к намного более легко воспринимаемому:
#define DATE(%v) $p(%v,4,"~")
...
s $$$DATE(rec)=$h
w $$$DATE(rec)
Что интересно, существуют реализации MUMPS, в которых трактовка левосторонних функций была расширена и в качестве аргумента
им разрешено принимать не только локальную или глобальную переменную, но и указывать другую левостороннюю функцию. В частности,
такая возможность была реализована в системе StarMUMPS. В ней разрешено рекурсивное левостороннее присваивание, например, так:
s $p($p(var,delim1,pos1),delim2,pos2)=expr
В этом случае система оперирует подстрокой, выделенной разделителем delim1 из подстроки переменной var, выделенной разделителем
delim2, и, при необходимости, выполняет дополнение в обеих подстроках. Но такой функционал не входит в стандарт и не поддерживается
современными распространенными реализациями MUMPS.
Для копирования переменной с поддеревом нужно указать не значение, а переменную, из которой необходимо скопировать. Копирование
выполняет команда merge.
merge var1=var2
В правой и левой части можно указать переменные с индексами, в
этом случае будет копироваться соответственно в поддерево и из поддерева.
У команды merge есть две особенности, важные для систем баз данных. Первая состоит в том, что если в переменной указанной в левой
части уже было поддерево, то оно не будет предварительно удалено.
Например, если есть переменная
USER>s a(1,1)="a11",a(1,2)="a12"
USER>s b(3,1)="b31"
то при копировании поддерева

22 ГЛАВА 1. СРЕДА ИСПОЛНЕНИЯ
USER>m a(1)=b(3)
часть поддерева a, не существующая в поддереве b, будет сохранена,
та часть которая есть в обоих, будет перезаписана, а та часть которая
отсутствует в a но присутствует в b, будет добавлена к a:
USER>m a(1)=b(3)
USER>w
a(1,1)="b31"
a(1,2)="a12"
b(3,1)="b31"
Поэтому, при использовании команды merge и при необходимости
иметь строгую копию, разработчики на MUMPS должны убедиться, что
ход выполнения программы не создает в пременной, указанной слева,
посторонних записей.
Второй особенностью команды merge является отношение к неопределенным значениям. Если в поддереве источнике копирования нет записей, то они не будут копироваться. И не будут копироваться никакие
записи, если такой переменной вообще не существует. В этом случае
команда merge вообще ничего не делает. И, если переменной указанной
слева, не существовало, то она и не будет создаваться.
USER>k
USER>m a(1)=b(2)
USER>w
USER>
Здесь предварительно были удалены все локальные переменные, затем присваивается поддерево b(2) в поддерево a(1), но поскольку поддерева b(2) не существовало, то поддерево для a(1) не создается и переменной a по-прежнему не существует. Команда merge, таким образом,
при обращении к неопределенным переменным не генерирует ошибку.
Что интересно, команда merge по стандарту языка не допускает копирование поддерева в то же самое поддерево. Если переменные a и b
являются по отношению к друг другу поддеревьями, то команда merge
генерирует ошибку о невозможности выполнить такую операцию:
USER>m a(1)=a(2)
USER>m a(1)=a(1,2)
<COMMAND>

1.1. КОМАНДЫ 23
Здесь в первом случае переменные a(1) и a(2) не являются друг по
отношению к другу поддеревьями и команда merge выполняется без
ошибки, а во втором случае переменная a(1,2) является поддеревом для
переменной a(1) и команда merge генерирует ошибку.
Для присваивания неопределенного значения в языке предназначена
команда kill. Команда удаляет указанную переменную, в результате она
становится переменной с неопределенным значением. В языке MUMPS
нет отдельного понятия, что переменная существует но не имеет значения, если у переменной нет значения то она не хранится и не существует.
Поведение команды kill определено на момент ее окончания - если
переменная существовала, то будет удалена, если не существовала, то
команда ничего не делает. Команда может быть применена к локальным и глобальнм переменным. В зависимости от реализации MUMPS
системы может дополнительно поддерживаться применение команды к
структурной системной переменной, например в реализации MiniM команда
kill ^$JOB(jobnumber)
принудительно завершает процесс с номером jobnumber.
Применение команды kill к чему-либо кроме локальной или глобальной переменной, вообще говоря, не входит в стандарт, и к таким возможностям нужно относиться внимательно. В зависимости от ситуации
такой случай может означать ошибку, в частности, если при использовании косвенной формы команды в прикладной системе предполагается,
что команда должна генерировать ошибку если аргумент не является ни
локальной ни глобальной переменной.
У команды kill поддерживается безаргументная форма - в этом случае команда применяется ко всем локальным переменным, которые существуют.
Кроме того, у команды kill поддерживается исключающая форма: если в качестве аргумента указаны имена локальных переменных перечисленные в круглых скобках, то команда применяется ко всем локальным
переменным кроме указанных. При этом указанные в скобках переменные не затрагиваются и они не могут быть указаны с индексами. Например
kill (a,b,c)
удаляет все локальные переменные кроме a, b и c.
Если команде kill указывается переменная с индексами, то команда
удаляет только указанное поддерево. Если указано имя без индексов, то
удаляется дерево переменной целиком.

24 ГЛАВА 1. СРЕДА ИСПОЛНЕНИЯ
В отношении этого совмещенного поведения команды kill стандартом было предусмотрено предложение реализовать дополнительно еще
две команды, kvalue (kv) и ksubscripts (ks), соответственно для удаления только указанного имени не затрагивая поддерева и для удаления
только поддерева не затрагивая указанного имени. В реализации MiniM
эти команды поддерживаются, но другими современными реализациями
MUMPS пока еще не поддерживаются. Поэтому при их использовании
нужно убедиться, будут ли команды работать на выбранной системе,
либо понадобится ли их заменить на комбинацию других команд.
Другая команда, не имеющая прямой задачи сделать значение переменной неопределенным, но делающая это побочно, это команда new.
Команда new объявляет, что локальная переменная в случае, если
впоследствии будет создаваться, то ее область видимости должна начинаться от текущего уровня стека. Если переменная с таким же именем уже существовала на другом уровне стека, то она перестает быть
видимой и все дальнейшие операции выоплняются с новым положением локальной переменной. В случае, если переменная с этим именем
уже была объявлена на этом же уровне стека, то она удаляется. В любом случае, непосредственно после команды new, эта переменная имеет
неопределенное значение.
Исключением является расширенная инициализирующая форма команды new, реализованная в системе MiniM - для переменной можно
указать значение, которое она должна получить:
new var=expr
при этом команда эквивалентна двум командам:
new var set var=expr
Это расширение, хотя и является практичным, не входит в стандарт языка MUMPS и в настоящее время не поддерживается другими
MUMPS системами.
У команды new стандартно поддерживается безаргументная форма. В
случае, если команде не указано ни одно имя, это означает что вообще
все локальные переменные далее имеют область видимости начиная с
текущего уровня стека.
Кроме того, у команды new стандартно поддерживается исключающая форма:
new (var1,var2,...)

1.1. КОМАНДЫ 25
В этом случае команда применяется не к перечисленным именам переменных, а ко всем, кроме перечисленных, в том числе еще не созданным. Для того, чтобы применить команду new только к определенным
именам, их надо просто перечислить через запятую без взятия в скобки:
new var1,var2,var3,...
Команда new не удаляет данные локальных переменных, существовавших ранее, на другом уровне стека, и при возврате управления на
предыдущий уровень стека действие команды отменяется, и видимость
локальных переменных полностью восстанавливается.
Что интересно, в языке MUMPS, если для локальной переменной
не объявлялось начало области видимости командой new, то видимость
этой переменной всеобщая, и ее можно изменять и читать на любом
уровне стека.
Команда new, что может показаться современным разработчикам на
MUMPS странным, появилась в стандарте языка MUMPS далеко не
сразу, а только в 1990-м году. Вполне возможно, что до сих пор находятся в эксплуатации модули, при разработке которых предполагалась
общая область видимости имен локальных переменных. Вполне возможно, что при модернизации таких программ с использованием современной
команды new разработчик может внести ошибку, поскольку отдельным
фрагментам может понадобиться именно общая область видимости. Хотя при современных разработках команда new используется наоборот,
как практически стандартное соглашение об изолировании переменных,
изменяемых подпрограммой.
Кроме стандартной команды new многие современные реализации
MUMPS поддерживают дополнительную расширенную команду znew.
Ее отличие от стандартной команды new в том, что, создав для локальной переменной область видимости от текущего уровня стека, команда
создает точную копию оригинальной переменной. Дальнейшие операции
с этой переменной изменяют лишь ее, и при возврате на предыдущий
уровень стека все выполненные изменения, естественно, пропадают. Команда относится к нестандартной, но многие реализации ее поддерживают. В случае ее использования в разработке, конечно, нужно проверить
поддерживается ли она на целевой MUMPS системе.
Формально говоря, команда чтения из текущего устройства (read)
также выполняет присваивание переменной в качестве побоного эффекта, но отнесена к командам ввода-вывода. Для нее основным действием
является ввод, а присваивание - это лишь побочный, но необходимый
результат.

26 ГЛАВА 1. СРЕДА ИСПОЛНЕНИЯ
1.1.2 Условные команды
Исполнение команд в программе на MUMPS выполняется построчно,
и внутри строки слева направо. Для управления выполнением программы в зависимости от некоторых условий в языке MUMPS определены
условные команды.
К условным командам относятся команды if, else и for.
Команды if в безаргументной форме и else (имеет только безаргументную форму) проверяют значение системной переменной $test. По
определению операций, эта переменная может быть установлена множеством способов. Например, при неудаче получения блокировки в течении
определенного таймаутом времени. Поэтому в программах MUMPS часто можно встретить команды if или else как-бы не относящиеся ни к
какому явно вычисляемому условию.
Аргументная команда if вычисляет значение аргумента как число и
если результат 0, то взводит системную переменную $test в значение 0,
иначе взводит $test в значение 1. И выполнение команд продолжается в
зависимости от результата.
У команды else есть особенность - для нее синтаксически недопустимо указание аргумента, поэтому после нее должно быть обязательно 2
пробельных символа.
Для строчно-ориентированных интерпретаторов условные команды
распространяются либо на всю последующую после команды строку, либо на набор команд ограниченных операторной скобкой then - else - end.
В языке MUMPS используется первый вариант и отсутствует синтаксическая конструкция then. Это весьма важная для понимания работы
системы особенность. Если условный оператор выполнился, то команды
расположенные далее в строке, также выполняются, а если не выполнился, то интерпретатор не выполняет дальнейшие команды, а переходит к
следующей строке либо продолжает выполнять цикл, если условная команда находится в цикле.
В частности, в языке MUMPS нет смысла располагать команду else
после команды if на той же строке, например так:
if a write 1 else write 2
Если значение переменной a в этом примере не равно 0, то выполняется команда write 1, после чего команда else проверяет значение $test
взведенное командой if и не выполняет команду write 2. Это как-бы ожидаемое поведение. Но если значение переменной a равно 0, то команда if
не передает управление на последующие команды, расположенные в той

1.1. КОМАНДЫ 27
же строке, и управление в этом случае не будет передано на команду
else.
Правильным вариантом вышеприведенного примера будет такой:
if a write 1
else write 2
Формально говоря, в предложения комитета по стандартизации MDC
входит предложение реализовать команду then как явно стекующую системную переменную $test, но в настоящее время ни одна MUMPS система такую команду не поддерживает, и программы на MUMPS её не
используют.
Системная переменная $test сохраняет свое значение до следующего изменения, и её, конечно, можно использовать для передачи информации, но так обычно не поступают. Традиционно, если в программах
требуется проверка переменной $test, то она взводится непосредственно
перед проверкой. Поэтому операции, косвенно взводящие значение $test,
но игнорирующие полученное значение, не влияют на ход выполнения
программ.
Это используется многими разработчиками для вызова системных
или пользовательских функций с игнорированием возврата. Вызов функции в этом случае выполняется командой if, но результат сравнения игнорируется, и далее в строке не ставятся никакие команды. В языке
MUMPS, если функция возвращает значение, то оно должно быть использовано как результат выражения, и если не используется, то MUMPS
система генерирует либо синтаксическую ошибку для системных функций, либо ошибку времени исполнения при выполнении команды возврата значения.
Нужно отметить, что аргументная форма команды if взводит значение $test, безаргументная форма команды if не взводит, но проверяет, и
команда else не взводит, но проверяет значение $test. Если необходимо
взвести значение переменной $test, то можно написать просто
...
if 1
...
; $test=1
...
или
...
if 0

28 ГЛАВА 1. СРЕДА ИСПОЛНЕНИЯ
...
; $test=0
...
Команда for устроена более сложно. Также как и команды if и else
она распространяет свое действие на команды, размещенные после нее
в этой же строке, но, в отличие от них, использует собственные правила итерации в зависимости от формы команды. В одной строке могут
быть несколько команд for, в этом случае расположенные левее будут
содержать в своем цикле расположенные правее.
Важно отметить, что если команды if и else управляются системной переменной $test, то команда for не реагирует на значение $test и
управляется собственными правилами итерации и окончания цикла.
Команда for продолжает выполнение последующих за собой команд.
Если команды расположенные на строке выполнились, то управление передается не на следующую строку, а последней выполнявшейся команде
for и команда проверяет собственное условие завершения, и при необходимости, итерации. При переходе на следующую строку контекст цикла
отменяется, независимо от того, произошло ли прерывание цикла или
переход выполнен по команде goto.
Например, при выполнении кода
write "start",!
for i=1:1:5 write i," : ",i*i,!
write "end",!
после вывода квадрата числа не будет производиться переход на следующую строку. Вместо этого управление передается на команду for, и
если ее итерации закончены, то только тогда управление перейдет на
следующую строку.
У команды for в языке MUMPS есть несколько форм - безаргументная, одноаргументная, двухаргументная и трехаргументная. При этом,
если есть аргументы, то должна быть указана переменная цикла и аргументы указываются через запятую не для команды, а для переменной
цикла.
Безаргументная форма команды for не имеет ни условия окончания
цикла, ни итерации переменной цикла. Выполнение вечного цикла может быть прервано лишь командой quit, командой goto, либо генерацией
ошибки. При этом команда for одновременно налагает требование на
команду quit, если она присутствует в теле цикла: допускается только
безаргументная форма quit и она трактуется как прерывание текущего
исполняемого контекста цикла, а не как возврат из подпрограммы.

1.1. КОМАНДЫ 29
Если команда quit выполнилась в цикле, который вложен в другой, то
прерывается только этот внутренний, не затрагивая выполнения внешнего:
USER>f i=1:1:2 f j=3:1:5 q:j=4 w i,":",j,!
1:3
2:3
Традиционным идиоматическим оборотом для безаргументной формы
for является итерация по перечислению, например, значений индексов.
Вариант для общего примера:
USER>s a(123)="",a(456)="",a(789)=""
USER>s n="" f s n=$o(a(n)) q:n="" w n,!
123
456
789
Здесь используется не переменная итерации цикла, а просто обычная локальная переменная, которая принимает значения индексов. Вечный цикл прекращается командой quit если следующий индекс пустая
строка. Для понимания примера важно, что команда for использована
в безаргументной форме из-за того, что мы самостоятельно проверяем
условие окончания и команда quit использована в безаргументной форме,
поскольку из цикла не допускается возврат значения. Безаргументные
формы обеих команд обозначены двойными пробелами.
Одноаргументная форма for указывается одним значением для переменной цикла:
for var=expr
При этом команда for выполнит итерацию однократно, предварительно присвоив переменной var значение вычисленного выражения expr.
Например:
USER>for i="a" w i
a
USER>
У одноаргументной формы for нет итераций и условия окончания,
она выполняется строго однократно. В качестве значения итерации может быть указано любое выражение, никаких сравнений или арифметических действий с ним в одноаргументной форме команда for не будет
выполнять.

30 ГЛАВА 1. СРЕДА ИСПОЛНЕНИЯ
Двухаргументная форма команды for задается начальным значением переменной цикла и приращением. При каждой итерации переменная цикла будет получать указанное приращение. Для двухаргументной
формы нет условия окончания итераций и цикл будет выполняться пока
не будет прерван командой quit, командой goto или генерацией ошибки.
Пример:
USER>for i=1:2 w i q:i>7
13579
USER>
Для двухаргументной формы переменная итерации уже всегда используется как число, даже если начальное значение было задано как
строка:
USER>for i="a":2 w i q:i>7
02468
USER>
Переменная цикла может быть изменена на любой итерации, и команда for всегда использует строго текущее ее значение, прибавляя значение итерации именно к тому значению, которое досталось команде
после очередной итерации:
USER>for i=1:2 w i,! s i=i+0.5 q:i>7
1
3.5
6
8.5
USER>
Трехаргументная форма команды for имеет дополнительно третье значение, условие окончания цикла, задаваемое после значения итерации
через двоеточие:
USER>for i=1:1:5 w i,!
1
2
3
4
5
USER>
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
