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

7.5. ФОРМАТ $HOROLOG 481
s Year=Y,Month=M,Day=D+1
q
А вариант кодирования значений года, месяца и дня в соответствующее значение по отсчету системной переменной $HOROLOG на языке
MUMPS может быть таким:
IsLeapYear(Y)
q (Y#4=0)&((Y#100)!’(Y#400))
ENCODE(year,month,day)
n ret,i,MonthDays
s ret=day,MonthDays="31,28,31,30,31,30,31,31,30,31,30,31"
i $$IsLeapYear(year) s $p(MonthDays,",",2)=29
f i=2:1:month s ret=ret+$p(MonthDays,",",i)
s i=year-1
q ret+(i*365)+(i\4)-(i\100)+(i\400)-672046
Приведенные функции кодирования и декодирования дат по шкале
$HOROLOG оперируют также и отрицательными значениями по шкале
$HOROLOG и используются на языке C в системе MiniM. В случае если
применяемая MUMPS система по каким-либо причинам не поддерживает работу с отрицательными значениями дат по шкале $HOROLOG, но
это необходимо в прикладной задаче, то могут быть использованы эти
функции на языке MUMPS.
Конечно, внутри системы исполнения MUMPS нет специальных маленьких и очень точных часов, и отсчет времени системная переменная
$HOROLOG производит по текущему времени, установленному на компьютере. В случае перевода даты и времени на компьютере переменная
будет возвращать значение по новому отсчету. Поэтому, строго говоря,
прикладная программа не должна полагать, что одно событие произошло
действительно позже другого, если значение $HOROLOG стало для него
больше. Но на практике именно так и поступают.
Многие современные реализации MUMPS поддерживают расширенные системные функции $ZDATE, $ZDATEH, $ZTIME, $ZTIMEH или
аналогичные для преобразования значения даты и времени между различными форматами. Для них опорным является формат $HOROLOG.
Например:
USER>f i=1:1:14 w i,": ",$zd($h,i),!
1: 03/26/2012
2: 26 мар 2012
3: 2012-03-26
4: 26/03/2012
5: мар 26, 2012

482 ГЛАВА 7. ПРАКТИКА ПРИМЕНЕНИЯ
6: мар 26 2012
7: мар 26 2012
8: 20120326
9: Март 26, 2012
10: 1
11: Пн
12: понедельник
13: 26 Март 2012
14: 26.03.2012
Кроме того, многие библиотеки функций написанные на MUMPS,
входящие в большие программные пакеты, также оперируют форматом
даты и времени, заданном переменной $HOROLOG.
Точка отсчета времени переменной $HOROLOG ведется по локальному времени. При этом компьютеры, находящиеся в различных часовых
поясах, в один и тот же момент времени имеют различные показания
$HOROLOG. Для выравнивания общего отсчета по UTC нужно дополнительно применять отсчет часового пояса по расширенным системным
переменным $ZTIMEZONE и $ZTIMESTAMP. В зависимости от реализации MUMPS такие переменные могут отличаться именем или тот же
функционал может быть выполнен в виде системных функций. Особенно
важно использование единого времени по UTC при объединении в единую систему территориально удаленных серверов, а также при передаче
в единый центр данных из территориально удаленных серверов.
7.6 Опции устройств
Одним из препятствий для полной переносимости программ, написанных на MUMPS, между различными реализациями, является различная
поддержка опций устройств.
Стандарт отводит поддержку типов устройств и их опций самим производителям реализаций. Это приводит к тому, что в различных MUMPS
системах одни и те же операции, например, открыть файл - прочитать
строки - закрыть файл, выполняются различным кодом. Код отличается не только различным соглашением об именовании устройств, но и
различным синтаксисом указания, что является опцией.
Опции устройства (или параметры устройства) указываются после
имени устройства и могут перечисляться через двоеточие. Синтаксически опция указывается согласно стандарту 1995-го года (ныне действующий) так:
deviceparameters := | deviceparam |
| ( [ [ deviceparam ] : ] ... deviceparam |

7.6. ОПЦИИ УСТРОЙСТВ 483
deviceparam := | expr |
devicekeyword := name
deviceattr := name
| devicekeyword |
| deviceattr = expr |
Синтаксически это позволяет указать, например, такие способы:
use filedev:(truncate)
use filedev:(mode="w")
При этом стандарт ставит транслятор в неоднозначное положение,
как отличить в записи опции (на диаграмме это deviceparam) ключевое слово опции, имя локальной переменной и выражение как результат
сравнения локальной переменной с другим выражением. При этом стандарт перечисляет альтернативу deviceparam := expr первой, отдавая ей
приоритет, но в expr как раз входит, как альтернатива, имя локальной
переменной.
В рекомендации стандарта, а не в сам стандарт, входит другой вариант определения devicekeyword и deviceattr:
devicekeyword := [ / ] name
deviceattr := [ / ] name
Применение слеша для указания имени опции или ключевого слова
уже позволяет транслятору определить точно, что это именно имя опции,
а не локальная переменная и что это имя опции со значением параметра,
а не выражение сравнения.
Примеры, приведенные выше, уже выглядят так:
use filedev:(/truncate)
use filedev:(/mode="w")
При этом сложилась ситуация, что среди современных реализаций
MUMPS есть такие, которые поддерживают первый вариант, и те, которые поддерживают второй. К первым относится, в частности, GT.M, ко
вторым Cach´e и MiniM.
В силу сложившихся особенностей различных систем и для обспечения совместимости с имеющимися разработками разработчики прикладных программ должны применять методы изолирования кода, если
необходимо выполнять программы на различных MUMPS системах. К
ним относятся, например, такие:

484 ГЛАВА 7. ПРАКТИКА ПРИМЕНЕНИЯ
1. Вынос операций с устройствами в мнемоники.
2. Выполнение операций с устройствами в команде xecute при выборе
надлежащего синтаксического варианта.
3. Поддержка различных библиотечных рутин для устройств для различных реализаций MUMPS.
Кроме различного синтаксиса опций, различные MUMPS системы,
даже поддерживающие одинаковый способ синтаксического указания
имени опции, поддерживают устройства ввода-вывода по-разному и с
разными именами опций и трактовкой их значений.
7.7 $X и $Y
Системные переменные $X и $Y были введены в язык в качестве встроенных и стандартных системных переменных с самого начала, и по своему назначению отражают положение каретки ввода на терминальных
устройствах. При эксплуатации MUMPS систем эти переменные, при
этом, разработчики используют с большой осторожностью.
Системные переменные $X и $Y доступны и на запись и на чтение.
При записи в них MUMPS система принимает меры к установке позиции
каретки в указанное положение. Синтаксически эта операция выглядит
так:
set $X=12
set $Y=5
При этом язык на логическом уровне не специфицирует отличие физического поведения таких переменных для различных терминальных
устройств. В зависимости от реального физического способа отображения и типа терминального устройства MUMPS система выполняет
действия, соответствующие этому типу устройства. В частности, для
Windows консоли выполняется позиционирование консольного курсора
SetConsoleCursorPosition
используя функционал WinAPI, а для телнет клиентов выполняется отсылка команд позиционирования в виде эскейп-последовательности.
Для терминальных устройств иного типа, например, для принтеров и
терминалов, выполняется передача специфических для них команд позиционирования каретки.

7.7. $X И $Y 485
В зависимости от типа такого терминального устройства содержание
эскейп-последовательности для позиционирования также, в принципе,
может отличаться, хотя большинство терминальных протоколов по базовым эскейп-последовательностям совпадают.
При разработке под терминальные устройства при использовании
переменных $X и $Y разработчики, безусловно, должны проверить,
как именно выполняется управление позиционированием на всех типах
устройств, с которыми необходимо работать.
Более сложный вопрос стоит с чтением системных переменных $X и
$Y. Проблема в том, что MUMPS системе не всегда может быть известно, где реально находится каретка ввода на терминальном устройстве
после того, как была выполнена какая-либо из команд. Вообще говоря,
MUMPS система может гарантировать корректный пересчет координат
лишь при выполнении команды write с выводом строки, состоящей из
печатных символов.
Все остальные случаи вывода уже не гарантируют корректного значения $X и $Y для произвольно взятого терминально-ориентированного
устройства. К таким операциям относятся операции управления форматом
write !
write #
write ?NN
операции вывода отдельного символа, даже если это код печатного символа
write *code
и операция вывода с помощью эскейп-последовательностей или мнемоник, например
write /MNEMNAME(params)
В этих случаях, вообще говоря, система может лишь гарантировать,
что управляющая последовательность была передана отображающему
устройству.
При выполнении операций управления терминальным устройством
через мнемоники или через явную передачу эскейп-последовательностей,
вообще говоря, перед каждой мнемоникой стоит задача выполнить опеределенное действие, например удалить строку. При этом не для каждой такой мнемоники может быть гарантировано, как именно данный
тип терминального устройства спозиционирует каретку по выполнению

486 ГЛАВА 7. ПРАКТИКА ПРИМЕНЕНИЯ
операции. Хотя для большинства мнемоник, косвенно меняющих или могущих изменить положение каретки, такое определение дано для эскейппоследовательности.
Существует довольно большое число типов терминальных устройств,
отличающихся в деталях протокола управления, набором поддерживаемых эскейп-последовательностей и побочным эффектом позиционирования каретки при выполнении команд управления. И, зачастую, для корректной работы с различными типами устройств, прикладные программы, ориентированные на сложный терминальный вывод, поддерживают
специальную библиотеку с настройками действий, которые необходимо
выполнить в зависимости от типа терминального устройства.
Вообще говоря, MUMPS система может поддерживать отсчет координат $X и $Y даже для нетерминальных устройств, например для текстовых файлов. Но и в этом случае не выполняется пересчет положения
условной каретки при выводе кода символа.
Положение с чтением значений $X и $Y во многом сходно с чтением значения $TEST. Общая практика состоит в том, что фрагмент кода
не должен полагаться на значение такой системной переменной, если
не он привел к изменению значения. И, для того, чтобы использовать
переменные $X и $Y на чтение, разработчики предварительно выполняют явное позиционирование, и лишь затем код выполняется в условиях
относительно корректного позиционирования и корректного отсчета по
координатам терминального устройства.
Таким образом, разработчики, при необходимости использования значений $X и $Y на чтение, должны в любом случае протестировать поведение кода для различных терминальных устройств, которые предстоит
эксплуатировать и проверить, после каких команд вывода они могут полагаться на корректное значение $X и $Y, а после каких нет.
7.8 Возврат результатов
При планировании прикладных систем разработчики на MUMPS имеют
возможность выбирать из множества вариантов, как именно вычисляющая функция или алгоритм будут возвращать результат.
Первое, на что нужно обратить внимание при выборе метода - это
поддерживаемое используемыми MUMPS системами ограничение на длину строки. В случае если результат вычисления гарантированно укладывается в этот лимит, то обычно применяется функция, возвращающая
значение, и вызываемая через $$.

7.8. ВОЗВРАТ РЕЗУЛЬТАТОВ 487
При выборе варианта в виде возврата одной строки остается определиться, будет ли применено структурирование результата - будет ли
строка одним цельным значением, или следует применить структурирование в виде строки с разделителями (для $PIECE()) или в виде списка
(для $LIST()).
Если результат вычислений не укладывается в поддерживаемое системой ограничение по длине, или необходимо иное структурирование,
то разработчики должны выбирать из более сложных случаев. Приведем
основной список возможностей вернуть результат вычисления алгоритмом:
1. Возврат по значению ($$).
2. Возврат по ссылке в локальную переменную.
3. Запись в предопределенную переменную.
4. Возврат значений в переменную, имя которой передается косвенно.
5. Итеративный возврат.
Теперь рассмотрим варианты возврата значений и их особенности
подробнее.
7.8.1 Возврат по значению ($$)
Для возврата по значению используется вызов вычисляющей функции
в контексте возврата ($$) и возврат вычисленного значения командой
QUIT. Простой пример возврата одной строки по значению:
ByValue(param) ; k w $$ByValue^RETURN(123) w
n ret
s ret="Calculate, param = "_param
q ret
При вызове просто выполняется команда QUIT с аргументом:
USER>k w $$ByValue^RETURN(123) w
Calculate, param = 123
USER>
К подводным камням такого возврата можно отнести поддерживаемое
используемой MUMPS системой ограничение на длину строки и возможность вызова без контекста возврата командой DO. Для второго случая

488 ГЛАВА 7. ПРАКТИКА ПРИМЕНЕНИЯ
у программистов есть системная переменная $QUIT, при ее равенстве 1
возврат командой QUIT с аргументом необходим, а если значение 0, то
возвращать не следует, нужна команда QUIT без аргумента.
К договоренности по формату вызова в этом случае также нужно отнести ожидаемое структурирование возвращаемой строки: будет ли это
цельное значение, строка с разделителями или список. В разработках
при применении строки с разделителями можно встретить два варианта: использование предопределенного разделителя и запись используемого разделителя первым символом возвращаемой строки. Второй вариант встречается намного реже, но обеспечивает корректную работу
кода в случае смены разделителя и возможность для вызываемой функции использовать наиболее подходящий разделитель в зависимости от
специфики данных.
В случае использования списковой структуры (для $LIST()) нужно
обязательно проверить, поддерживается ли такой функционал в целевой
MUMPS системе или ее версии.
Возрат по значению обычно используется для возврата атомарных
или структурированных простым способом значений, если объем возврата небольшой и при развитии системы и предъявляемы к ней требований
этот объем также не выйдет за пределы ограничения на длину строки.
7.8.2 Возврат по ссылке
Для возврата результата вычисления по ссылке вычисляющей функции
передается ссылка на локальную переменную (через точку). Могут быть
переданы также несколько ссылок, на несколько переменных. Простой
пример такой передачи с использованием структурирования по индексам:
RunByRef ; k d RunByRef^RETURN w
n a,b
d ByRef(.a,.b)
w
q
ByRef(param1,param2)
s param1(1)="param1 1"
s param1(2)="param1 2"
s param2(1)="param2 1"
s param2(2)="param2 2"
q
При выполнении кода вызывающая функция передает ссылки на свои
локальные переменные (фактические параметры), а вызываемая в них
записывает, используя свои имена формальных параметров:

7.8. ВОЗВРАТ РЕЗУЛЬТАТОВ 489
USER>k d RunByRef^RETURN w
a(1)="param1 1"
a(2)="param1 2"
b(1)="param2 1"
b(2)="param2 2"
USER>
Возврат значений по ссылке можно свободно комбинировать с воз-
вратом по значению.
К подводным камням такого способа относится ограничение на общий объем памяти, занимаемый локальными переменными процесса и
невозможность передать ссылку на глобал, так как этот вариант не поддерживается синтаксически.
При таком способе может быть применено произвольное структурирование вычисленных результатов: цельная строка, строка с разделителями, список, структурирование по индексам, а также могут быть использованы несколько разных локальных переменных.
К плюсам или минусам (в зависимости от ситуации) может быть отнесено то, что перед вызовом вычисляющей функции в передаваемые
локальные переменные уже могут быть записаны некоторые значения
и они будут доступны вычисляющей функции. В случае если вызываемой функции необходимо гарантировать, что весь возврат в переменную
принадлежит ей, перед записью нужно удалить из этой переменной все
значения:
ByRef(param1,param2)
k param1,param2
s param1(1)="param1 1"
...
Возврат по ссылке обычно используется тогда, когда необходимо передать больше чем одно атомарное значение, или необходимо структурировать ответ по индексам, но возвращаемый объем заведомо умещается
в области локальных переменных процесса.
7.8.3 Запись в предопределенную переменную
Запись в предопределенную переменную применяется из-за возможностей языка MUMPS видеть все созданные ранее по стеку локальные
переменные, если они не были экранированы командой NEW. Многие
разработки на языке MUMPS, выполнявшиеся много лет назад, использовали такую возможность как за неимением команды NEW, так и для
организации взаимодействия без передачи параметров на стеке.

490 ГЛАВА 7. ПРАКТИКА ПРИМЕНЕНИЯ
Для вычисляющей функции просто резервируется набор имен пере-
менных (локальных или глобальных), в которые ожидается возврат.
Для современных методик программирования такой способ выглядит
несколько архаично, но, тем не менее, имеет свои плюсы - возможно
применять произвольное структурирование.
Как пример можно привести фрагмент кода работы с датами, который
часто приводится как демонстрационный по языку MUMPS:
7 S %=%H>21608+%H-.1,%Y=%\365.25+141,%=%#365.25\1
S %D=%+306#(%Y#4=0+365)#153#61#31+1,%M=%-%D\29+1
S X=%Y_"00"+%M_"00"+%D Q
;
YX D YMD S Y=X_% G DD^%DT
YMD D 7 S %=$P(%H,",",2) D S K %D,%M,%Y Q
Здесь даже не используются параметры меток и возврат по значению,
код просто использует текущие локальные переменные на чтение или
на запись. С тем же успехом он мог бы использовать и глобальные
переменные. Фактически, в этом случае вызываемые метки являются
частью общего вычисляющего алгоритма.
К плюсам такого способа относится практически полное отсутствие
каких-либо ограничений, а к недостаткам - необходимость согласовывать вызывающий и вызываемый код по именам локальных переменных
и несколько большая трудность чтения такого кода современными программистами.
Предопределенные переменные с точки зрения классического MUMPS
используются всегда, поскольку язык сам по себе определен как строчноориентированный и структурирование кода на функции это лишь взгляд
программиста, а в самом языке нет таких синтаксических конструкций,
как функция, содержащая собственные переменные функции.
7.8.4 Возврат значений косвенно
Для косвенного возврата значений вызываемой функции передается имя
(или несколько имен) локальных или глобальных переменных. Вызываемая функция для записи результата использует это имя косвенно.
В качестве демонстрационного примера приведем такой вариант:
RunIndir ; k d RunIndir^RETURN w
n var
s var("data")="123"
d Indir($na(var))
w
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
