Разработка для Microsoft SQL Server: Unix way

Привет, Хабр!

Средние и крупные проекты, в которых целиком, либо значительная часть бизнес-логики реализована в хранимых процедурах СУБД, имеют ряд неудобств по управлению кодом модулей. А именно:
  • Отсутствие управления версиями и отслеживание изменений кода;
  • Сложности при синхронизация тестовой и рабочей инфраструктуры;
  • Скудность средств по поиску, навигации и обзору кода.

Да, есть коммерческие продукты, решающие эти проблемы полностью или частично, однако, на взгляд автора, делают это не эффективно и не элегантно. В виду этого, реализовано отображение модулей и структуры БД на файловую систему, с помощью FUSE (Filesystem in Userspace), в проекте SQLFuse. Теперь последователи Unix way смогут пройти и здесь.

Рассмотрим последовательность действий для монтирования опытной БД.

Подготовка к монтированию


Для сборки и монтирования понадобятся следующее ПО:
  • Модуль FUSE ядра Linux;
  • Драйвер FreeTDS;
  • Необходимый софт для сборки. Обычно называется в популярных дистрибутивах Linux как base-devel, включающий в себя комплятор gcc, средство make и т.п.;
  • GNU Bison и Flex.

Убедитесь, что модуль ядра FUSE загружен:
modprobe -a fuse

После того, как софт установлен, необходимо клонировать репозитарий git:
git clone https://github.com/AlexandrMov/SQLFuse.git

Сборка проекта выполняется командами:
make clean
make


Настройка


Если компиляция и сборка прошла успешно, далее необходимо настроить конфигурационный файл sqlfuse.conf, который находится в директории conf, клонированного репозитория:
  # глобальная группа параметров, применяются ко всем профилям
  [global]
  # количество сеансов
  maxconn=1
  # наименование приложения, передаваемое при подключении к SQL Server
  appname=SQLFuse

  # пользовательский профиль подключения
  [AdventureWorks2008R2]
  # имя или адрес хоста/экземпляра SQL Server
  servername=192.168.6.50
  # база данных
  dbname=AdventureWorks2008R2
  # профиль авторизации, определённый в sqlfuse.auth.conf
  auth=advauth

Параметр auth ссылается на имя группы, определённое в файле sqlfuse.auth.conf:
  # пользовательский профиль авторизации
  [advauth]
  # логин пользователя
  username=fuse
  # пароль пользователя
  password=123

Вместо параметра auth в файле sqlfuse.auth.conf допускается определение username и password в файле sqlfuse.conf. Этого не сделано нарочно, так как автор параноик при редактировании профилей подключений, кто-нибудь может подсмотреть пароль пользователя.
При указании экземпляра сервера, например, SQLServer\SQLEXPRESS, символ "\" можно не экранировать. Это верно и для параметра username, если необходимо авторизоваться через Active Directory.

Не забудьте про то, что БД AdwentureWorks2008R2 должна быть подключена, и выбранный пользователь имеет все необходимые права для модификации модулей SQL Server.

Известные проблемы


Если у Вас возникают проблемы с кодировками, то попробуете использовать параметры to_codeset и from_codeset задающие направление конвертирования:
from_codeset=UTF-8
to_codeset=CP1251

При возникновении это ошибки:
Heterogeneous queries require the ANSI_NULLS and ANSI_WARNINGS options to be set for the connection. This ensures consistent query semantics. Enable these options and then reissue your query.
Используете параметр ansi_npw=true для принудительного включения опций QUOTED_IDENTIFIER, ANSI_NULLS, ANSI_WARNINGS, ANSI_PADDINGS в состояние ON:

Монтирование


Создадим папку advworks в корне клонированного репозитория SQLFuse и смонтируем в неё нашу БД:
mkdir advworks
./sqlfuse -o profilename=AdventureWorks2008R2 ./advworks

Можно воспользоваться опцией -d, чтобы иметь возможность следить за ошибками, выдаемые SQL Server:
./sqlfuse -d -o profilename=AdventureWorks2008R2 ./advworks &> ./advworks.log &


Основные действия над модулями


Приведу для примера несколько простых действий над объектами сервера.
  • Просмотр и навигация по структуре БД в MidnightCommander:



  • Создание нового поля в таблице Person.Person и его удаление:
    echo "COLUMN TestColumn NVARCHAR(50) NOT NULL" > ./Person/Person/TestColumn
    rm ./Person/Person/TestColumn
    

  • Копирование процедуры из схемы HumanResources в схему dbo:
    cp ./HumanResources/uspUpdateEmployeeLogin ./dbo/uspUpdateEmployeeLogin

  • Поиск процедуры по наименованию во всех схемах:
    find ./ -maxdepth 2 -iname *Employee* -type f -print

Таким образом, управление и навигация по модулям становится как по обычным директориям с файлами: возможно применение систем управления версиями, патчей и любимых редакторов кода, то есть вся философия Unix налицо и для SQL Server.
имейте ввиду, что операция усечения (truncate) пока не поддерживается, — это значит, выполнить команду
echo " NOT NULL" >> TestColumn
не получится. Хотя и заблокировано на уровне файловой системы операция, но всё же не рекомендовал выполнять это, так как может привести к пересозданию колонки и потере данных!

Всегда сохраняйте оригиналы модулей перед редактированием!

Если вы ошиблись в описании модуля или произошёл разрыв соединения, файловая система вернёт ошибку -EFAULT («Не верный адрес»).

Поддерживаемые модули


На момент, когда писался пост, SQLFuse поддерживал следующие модули для чтения/записи:
  • Хранимые процедуры, функции;
  • Ограничения CHECK, DEFAULT;
  • Колонки и триггеры.

Только для чтения доступны схемы, таблицы, представления. Не отображаются совсем ограничения FOREIGN KEY, PRIMARY KEY и индексы. Когда появится больше свободного времени допишу и этот функционал.

Пришлось немного упростить синтаксис T-SQL, во избежания путаницы и более гибкого управления модулями. Все осталось прежним, за исключением того, что в определении ограничений и колонок убрана избыточность в описании таблицы. Определения будут выглядеть следующим образом:
  • Колонки:
    /*ALTER TABLE Person.Person ADD/ALTER/DROP*/ COLUMN TestColumn DATETIME -- ...
  • Ограничение CHECK:
    /*ALTER TABLE Person.Person ADD/DROP*/ WITH CHECK CONSTRAINT CK_Test CHECK -- ...
  • Ограничение DEFAULT:
    /*ALTER TABLE Person.Person ADD/DROP*/ DEFAULT (GETDATE()) FOR (TestColumn) -- ...

В частях, где закомментированы указания о таблице назначения, SQLFuse сделает подстановку необходимого кода автоматически, исходя из местоположения файла модуля. Имя модуля, которое определено в тексте файла, не играет никакой роли, оно будет заменено на имя файла, схемы и/или таблицы по необходимости. В текстах модулей не может быть несколько пакетов команд, т.е. GO

Эпилог или что дальше?


По мере поступления свободного времени, в планах реализовать:
  • Поддержку ограничений и индексов, а также манипуляцию с таблицами, представлениями и схемами;
  • Логирование команд SQL и вывод их через канал или просто файл;
  • Сохранение резервных копий при манипуляции с модулями, поддержка отката при ошибках;
  • Описать в следующем посте формирование определений таблиц, и преобразование структуры в скрипты SQL.

Кого заинтересовала идея и кто хочет принять участие в разработке, — милости просим: весь исходный код доступен под лицензией GPLv3. Автор будет рад любым замечаниям и предложениям.

P. S. Могу рассказать про опыт разработки файловой системы пользовательского режима на FUSE, если кому интересно.

Источники данных


Share post

Comments 8

    0
    Клёвая идея! Надо будет поиграться на досуге.
      0
      Одна из проблем, которую мы встретили с использованием FreeTDS это очень маленькое выставленное по умолчанию значение
          	text size = 65536
      

      Поэтому если вы храните в базе файлы больше 64к, они будут приходить обрезанными, ровно до 64к.
        0
        Спасибо, за замечание. Текст модулей берётся из вывода хранимой процедуры sp_helptext, либо генерируется из метатаблиц, поэтому врядли удастся столкнуться с этим ограничением.
          0
          Немного не об этом. Это ограничение на размер результата выполнения запроса с помощью freetds.
            +1
            Этот параметр отвечает лишь за «значение по-умолчанию» объема памяти для работы с blob-ами. Данные свыше этого объема будут обрезаны.
            В пределах сессии (или свойствах коннекшна) можно изменить манипулируя опцией set textsize, узнать текущий лимит — опрашивая переменную @@textsize
        0
        А для Postgre есть что-нибудь подобное?
          0
          Насколько я знаю нет, к сожалению. Может быть, найдутся энтузиасты и помогут с реализацией для PostgreSQL.
            0
            Гм… мне тут как раз надо курсовик по программированию выбрать :D.

        Only users with full accounts can post comments. Log in, please.