SPM или собственный предметный макроязык над процедурным расширением SQL

Внимание

В статье рассказывается о предыдущей версии SPM (1.x). Описание текущей улучшенной и более простой в использовании версии SPM 2 находится здесь.

Предыстория

В ходе моих проектов приходилось и приходится писать много серверного кода в виде хранимых процедур и сценариев на процедурном расширении SQL соответствующей СУБД (в основном это MS SQL). К сожалению, при больших объемах такого кода (тысячи и десятки тысяч строк) возникает необходимость в инструменте, который бы мог:

  • группировать исходный код в виде файлов и вести проект из нескольких файлов;
  • транслировать код на сервер БД с диагностикой возможных ошибок;
  • допускать метапрограммирование, то есть использование несложного макроязыка (функциональная декомпозиция в декларативном языке SQL как правило неэффективна прежде всего с точки зрения производительности да и сам T-SQL до выхода версии MS SQL 2000 не допускал функций, определяемых пользователем);

В результате был создан инструмент, получивший название SPM (Stored Procedures Macroprocessor).

Первая версия поддерживала только MS SQL. Однако вскоре пришлось работать с InterBase и Sybase, поэтому была введена поддержка для них. Но энтропия увеличилась, появились некие специфичные настройки, инструмент "стал толстым". Поэтому я принял решение сделать SPM практически универсальным за счет работы с СУБД через ODBC.

Поскольку, кроме хранимых процедур существуют еще их "ближайшие родственники" в виде триггеров (процедура, работающая по событию, происходящему с таблицей БД) и, на некоторых серверах БД, функций, то начиная с версии 1.4.1 SPM поддерживает разработку этих процедурных объектов. С версии 2.0.3 поддерживаются также проекции (view).

В связи с тем, что мне требовались все более и более изощренные макросы, я решил более не тратить времени на развитие собственного велосипеда, а взять за основу готовый макропроцессор GNU m4, оставив за SPM только функции менеджера файлов проекта и транслятора кода на сервер.

Рис.1. Принципы работы SPM

Макроязык

Подробное описание макроязыка и настроек m4 приводятся на его основном сайте . По умолчанию, SPM использует минимально необходимые опции для запуска макропроцессора, но вы можете добавить к ним свои, используя параметр Options в файле проекта.

Примеры макроопределений

Простой макрос:

define({RC_ERROR}, {-1})
define({RC_SUCCESS}, {0})

Макрос с параметрами, вызывающий другой макрос:

define({ReturnIfError}, {if ($1 != RC_SUCCESS) return RC_ERROR})

Макрос с параметрами, вызывающий другой макрос с параметрами.

define({CallProc},
{
if ProcExists($1)
exec $2 $3
}
define({ProcExists}, {exists(select * from sysobjects where name=$1 and type='P')}

SQL-проект

SQL-проект - это совокупность исходных и промежуточных файлов, содержащих любой процедурный код. SQL-проект ассоциирован с понятием модуля - выделенного набора объектов БД и сценариев их инициализации. Поэтому SPM может генерировать SQL-скрипты для установки или удаления модуля на сервере БД.

Макропроцессор SPM работает только с файлами SQL-проекта (далее просто "проект"). Любой проект содержит файл метаинформации, то есть сведения о других файлах, входящих в его состав и другую служебную информацию. В нашем случае главным файлом проекта может являться любой файл с расширением *.prj, который имеет следующую структуру, подобную структуре обычного INI-файла Windows:

Секция

Элементы

Назначение

M4Info Содержит информацию о макропроцессоре m4
Application Имя исполняемого файла и полный путь к нему (например, C:utilsm4m4.exe). Если m4 находится в каталоге, указанном в PATH, то путь можно не указывать.
Options Дополнительные опции для запуска m4, например для вывода отладочной информации.
LogonInfo Содержит информацию о параметрах соединения с сервером БД
ConnectionString Строка для ODBC-соединения
LogonFile Имя файла (допускается относительный и абсолютный пути), который содержит другую секцию LogonInfo. В этом случае все предыдущие параметры игнорируются и берутся из этого файла.

Использование данного параметра удобно для нескольких проектов, имеющих одни и те же настройки соединения с сервером.

ServerInfo Содержит специфичные для данного сервера БД параметры
ProcedurePrefix Префикс владельца процедуры (необязательный, только MS SQL). Если не указан, процедура создается с префиксом текущего пользователя
BatchTerminator Параметр BatchTerminator (необязательный)
Определяет символ окончания фрагмента SQL-скрипта. Данный символ делит скрипт на логически независимо исполняемые части. SPM интерпретирует данную лексему в файле, как явно указанное окончание объявления текущего объекта (неявным окончанием является начало объявления другого объекта или конец файла)
CheckZeroSeverity Параметр CheckZeroSeverity (Необязательный)
Определяет, является ли сообщение с приоритетом "0" ошибкой или информационным сообщением для данного сервера
0 - не является ошибкой, 1 - является (по умолчанию)
SourceFiles Содержит список исходных файлов кода
Count Число исходных файлов (необязательный элемент, если его не указывать число будет ограничено 100000)
FileN Имя N-го файла (допускается относительный и абсолютный пути)

Для облегчения возможной последующей вставки файлов N можно задавать с шагом от 1 до 999.

IncludePaths Содержит список путей к файлам макроопределений
Count Число путей (необязательный элемент, если его не указывать число будет ограничено 100000)
PathN Спецификация N-го пути (допускается относительный и абсолютный варианты)
InstallFiles Содержит список файлов, которые используются для генерации SQL-скрипта установки модуля. Он создается простым слиянием файлов File1..FileN в один файл с именем _Install.sql
Count Число файлов в секции (необязательный элемент, если его не указывать число будет ограничено 100000)
FileN Имя N-го файла (допускается относительный и абсолютный пути)
UninstallFiles Аналогично секции InstallFiles создается SQL-скрипт для удаления модуля с именем _Uninstall.sql
Count Число файлов в секции (необязательный элемент, если его не указывать число будет ограничено 100000)
FileN Имя N-го файла (допускается относительный и абсолютный пути)
PostExec SQL-команды, которые будут выполнены после успешной трансляции всего проекта
PostCmd SQL-команда в одну строку. Имеет приоритет перед файлом (см. PostCmdFile), т.е. если задана команда, то файл не выполняется.
PostCmdFile Имя файла сценария из одной и более строк с команадами. Внутри нельзя использовать batch terminator.

Пример файла проекта Sample.prj.

[M4Info]
Application=C:utilsm4m4.exe
Options=

[LogonInfo]
LogonFile=logon.cfg

[ServerInfo]
ServerType=0

[SourceFiles]
FilesCount=1
File1=Sample.sqm

[IncludePaths]
Count=1
Path1=..common

[InstallFiles]
Count=3
File1=_Create_objects.sql
; Файл _CreateProcs.sql создается автоматически и содержит
SQL-скрипт
; создания всех процедур проекта
File2=_CreateProcs.sql
File3=_Init_objects.sql

[UninstallFiles]
Count=2
; Файл _DeleteProcs.sql создается автоматически и содержит
SQL-скрипт
; удаления всех процедур проекта
File1=_DeleteProcs.sql
File2=_Destroy_objects.sql

Файл logon.cfg:

[LogonInfo]
ConnectionString=DRIVER={SQL
Server};SERVER=MY_SERVER;UID=sa;PWD=123;DATABASE=pubs;Network=DBMSSOCN;

Примеры ConnectionString для разных СУБД

СУБД ConnectionString
MS SQL 7/2000/2005 DRIVER={SQL Server};SERVER=MY_SRV;UID=sa;PWD=;DATABASE=pubs;Network=DBMSSOCN;
Interbase 6 DRIVER={XTG Systems InterBase6 ODBC driver};SERVER=MY_SRV;DB=MY_SRV:D:IB6employee.gdb;UID=SYSDBA;PWD=masterke
Sybase ASE 12 DRIVER={Sybase ASE ODBC Driver};SRVR=MY_SRV;UID=sa;PWD=;DB=master;

Файлы проекта

В проект входят файлы двух типов: исходные и производные.

Исходные файлы - это файлы макроопределений (должны иметь расширение *.sqh) и файлы кода на процедурном расширении SQL с возможным (но не обязательным) применением макроязыка (должны иметь расширение *.sqm).

Производные файлы - это файлы, образующиеся после макроподстановок в исходных файлах *.sqm (они получают то же имя, но с расширением *.sql) и их одноименные предыдущие копии с расширением *.bak. SPM создает также SQL-файлы установки/удаления модуля и создания/удаления процедур при использовании опции /build (см. ниже).

Кроме вышеперечисленных типов, SPM создает также файл Error.log, если в процессе работы выявились ошибки. Файлы Lexemes.dmp, Parcemap.dmp и Stack.dmp являются служебными и создаются только в отладочной версии SPM.

Как он работает

SPM работает по следующему сценарию.

  1. Для всех sqm-файлов выполняется вызов макропроцессора m4 с выводом результата в одноименный файл, но с расширением *.sql. Если в процессе работы произошли ошибки, они выводятся в файл Error.log и на этом работа прекращается.
  2. Осуществляется последовательная трансляция объектов (хранимых процедур, триггеров, функций и проекций (view)) из полученных sql-файлов. Если в процессе работы произошли ошибки, они выводятся в файл Error.log и на этом работа прекращается. Для MS SQL Server используется его расширения интерфейса ODBC, которые показывают подробные сведения о месте и содержании ошибки в транслируемом коде.
  3. SPM возвращает статус завершения своего выполнения. Если произошли ошибки, то статус равен "1", если все в порядке, то нулю. Это можно проверять в командных файлах, например так:
    if errorlevel 1 goto errors_occured
    echo все нормально
    goto end
    :errors_occured
    echo произошли ошибки
    :end

Как запустить

Макропроцессор m4 включен в дистрибутив. Вы также можете загрузить m4 с сайта GNU utilities for Win32, где он входит в комплект UNIX-утилит для Windows.

Необходимо распаковать дистрибутив и добавить каталог bin, где находятся SPM.exe и m4.exe в переменную среды PATH, либо, что не всегда является хорошей практикой, просто скопировать содержимое bin в один из каталогов, путь к которому уже указан в PATH.

Для работы с сервером БД вам необходимо установить ее клиентскую часть и ODBC-драйвер. Для MS SQL Server драйвер ODBC не требует наличия установленной клиентской части.

SPM тестировался только для следующих серверов:

  • MS SQL 6.5, 7, 2000 и 2005
  • Sybase ASE 12.0 и 12.5
  • InterBase 6 / FireBird

Однако, никаких принципиальных ограничений по использованию, с любым другим сервером нет, за исключением требования наличия установленного ODBC драйвера.

Перейдите в каталог SQL-проекта (в котором лежит главный файл проекта *.prj). Выполните из командной строки запуск:

spm[.exe] <файл проекта> [опции]

или, для получения информации о версии программы:

spm[.exe] /ver

Расширение *.prj для файла проекта указывать необязательно.

Опции запуска приведены ниже в таблице.

Опция Назначение
/script SMP только обрабатывает исходные файлы, не транслируя результаты на сервер.
/all SPM транслирует все процедуры на сервер независимо от того, изменялся текст в файлах или нет (аналог Rebuild All в различных средах разработки)
/ver SPM выводит информация о своей версии, все другие опции и названия файла проекта игнорируются, никаких действий не производится
/build SMP создает SQL-скрипты для установки и удаления модуля (файлы _Install.sql и Uninstall.sql, соответственно). В процессе создания скриптов будут созданы также файлы _CreateProcs.sql и _DeleteProcs.sql, содержащие , соотвественно, полные SQL-скрипты для создания и удаления всех процедур/триггеров/проекций проекта.
/debug SMP определяет макро SPM_DEBUG, который можно использовать для условной трансляции Например: ifdef({SPM_DEBUG}, {SELECT 'Debug mode' AS mode})
/m4:<M4 command line option> Передает в M4 параметр командной строки. Можно задавать более одной опции /m4

Как настроить MultiEdit для работы с SPM

Предполагается, что на Вашем компьютере установлен MultiEdit 8 для Windows. Последовательность действий по настройке может быть следующей.

  1. В меню "Tools" выбираем пункт "Customize...". В открывшемся дилоговом окне переходим на закладку "Customize" и нажимаем кнопку "Filename extensions...".
  2. В открывшемся диалоге редактирования добавьте в поле "Extension(s)" к расширению SQL еще SQM и SQH.
  3. Нажмите кнопку "Compiler/Program setup...". В открывшемся диалоге нажмите "Insert". В поле "Description" напишите, например, "SPM macroprocessor". В поле "Command" введите название командного файла для запуска компиляции, например "compile.bat". Использование командного файла с одним названием позволит производить запуск SPM из MultiEdit независимо от названия проекта. Далее необходимо установить следующие значения опций: "Working directory" - "Source file", "Exe Type" - "Win32 console", "Show" - "Normal" и установить флаги "Save all files" и "Reload file". После этого нажимаем кнопку "..." для выбора "Program Type".
  4. В открывшемся диалоге нажимаем "Insert". Заполняем поля: "Type" - "SPM", "Exe file" - "spm.exe", в группе "Error" поле "File" - "error.log". Остальные поля не заполняем. Нажимаем "ОК".
  5. В диалоге "Compiler/Program type" выбираем созданный "SPM" и нажимаем "Select".
  6. В диалоге "Compiler/Program Type" нажимем "OK".
  7. В диалоге "Compiler/Program" выбираем созданный "SPM macroprocessor" и нажимаем "Done".
  8. В диалоге "Edit Filename Extension Setup" нажимем "OK". Если у вас уже были открыты файлы, то на появившийся вопрос "Reset extension configuration in currently loaded files" (перустановить конфигурацию для загруженных файлов) отвечаем утвердительно "Yes".
  9. В диалоге "Filename extension setup" нажимаем "Close".
  10. В диалоге "Customize" нажимаем "ОК".

Теперь, если выбрать пункт "Execute compiler..." из меню "Tools" (он также настраивается на горячую клавишу, я предпочитаю общую настройку для Multi Edit - "Borland IDE emulation"), то будет произведен вызов командного файла compile.bat, который запустит SPM с именем текущего проекта, в каталоге которого вы редактируете файлы. Если в процессе работы SPM произошли ошибки, то внизу откроется окно, в котором Вы увидите содержимое файла error.log. Если этого не произошло в первый раз автоматически, надо открыть окно просмотра ошибок нажав на панели статуса в правом нижнем углу самую правую кнопку.

Как настроить FAR Manager

Для работы с FAR потребуется установленный модуль Colorer. Открываем файл C:\Program Files\Far\Plugins\Colorer\hrc\proto.hrc, находим в нем элемент <prototype name="sql" и значение

<filename>/\.sql$/i</filename>

меняем на

<filename>/\.(sql|sqh|sqm)$/i</filename>

Перестартуем FAR, теперь файлы с макросами имеют подсветку SQL-синтаксиса

Как скомпилировать

В состав дистрибутива входят все необходимые сторонние исходные файлы и библиотеки, так что больше ничего вам загружать и устанавливать не придется. Для компиляции вам потребуется MS Visual C++ 7 из состава VS.Net. Файлы проекта включены в дистрибутив. Для компиляции в IDE просто откройте проект и постройте исполняемый файл.

По умолчанию строится версия с англоязычным интерфейсом. Если вы хотите изменить язык на русский, то просто добавьте в опции препроцессора директиву RUSSIAN. Это можно сделать в диалоге "Project settings": на закладке "С/С++" выберите из списка категорию "Preprocessor" и в поле "Preprocessor definitions" добавьте RUSSIAN.

Пример

Хороший способ ознакомиться с SPM - тестовый пример. Пример, сделаный для MS SQL 7/2000, предполагает наличие демонстрационной базы данных pubs на сервере. Примеры для Interbase и FireBird 1 используют демонстрационную БД employee.gdb.

Информация об изменениях и версиях

В дистрибутив помимо исходных файлов и исполняемого модуля (EXE) включаются файлы:

version.txt содержит номер версии SPM
changes.txt содержит последовательный хронологический лист регистрации изменений
template.prj
template.ru.prj
содержит шаблон файла проекта
license.txt лицензионная информация

Загрузить

Загрузить дистрибутив SPM (версия 2.0.16)

Прикрепленный файлРазмер
SPM_full.zip326.63 кб