Категории

понедельник, 7 апреля 2014 г.

Запуск и адаптация МАРК-SQL 1.5.4 для MySQL 5.x

Столкнулся с проблемой, АИБС "МАРК-SQL" для школьных библиотек 1.5.4 не работала с MySQL, а разработчики заверяли, что программа не совместима с MySQL.
Решил проанализировать запросы, которые ходят между программой и сервером при помощи MySQL-Proxy [2].
И сразу увидел некорректный запрос с использованием зарезервированного слова "SEPARATOR":
SELECT TAG,SUBTAG,FLAGS,SEPARATOR,CAPTION FROM TAG
После добавления обратных кавычек к зарезервированному слову SEPARATOR [1] запрос выполнился в MySQL без проблем:
SELECT TAG,SUBTAG,FLAGS,`SEPARATOR`,CAPTION FROM TAG
Значит для нормальной работы программы АИБС "МАРК-SQL" для школьных библиотек 1.5.4 нужно ловить каждый запрос, и если требуется, экранировать зарезервированные слова MySQL на лету. С этой задачей вполне успешно справится MySQL-Proxy [2] с поддержкой lua [4] скриптов.
После установки, запуска MySQL-Proxy и подключения lua скрипта:
function MyDebug(str)
        -- enable\disable debug messages print to stdout.
        local dbg = 0
        if dbg == 1 then
                print('[DEBUG] ' .. str)
        end
end

function read_query(packet)
        local file = io.open('/var/log/mysql-proxy.log', 'a')
        local q = string.sub(packet, 2)

        MyDebug('Orig. Query: ' .. q)
        file:write('Orig. Query: ' .. q .. '\n')

        -- Таблица зарезервированных слов MySQL.
        -- http://dev.mysql.com/doc/mysqld-version-reference/en/mysqld-version-reference-reservedwords-5-7.html

        q = string.gsub(q, '(SEPARATOR)', '`%1`')
        q = string.gsub(q, '(INT%d)', '`%1`')

        -- Исправление поискового запроса (захардкоженного в marcp.exe) и регистронезависимый поиск.
        local _,_,str1,str2,str3 = string.find(q,"SELECT TERM,CNT FROM (.-) WHERE TERM%s*>=%s*('.-')%s(.*)") -- TODO: проверить всегда ли передаются кавычки в поле WHERE TERM >= ''.
        if str1 ~= nil and str2 ~= nil and str3 ~= nil then
                MyDebug('str1: ' .. str1); MyDebug('str2: ' .. str2); MyDebug('str3: ' .. str3)
                str2 = string.gsub(str2, "^'", '') -- Delete start '.
                str2 = string.gsub(str2, "'$", '') -- Delete end '.
                MyDebug('Fixed str2: ' .. str2)
                q = string.format("SELECT TERM,CNT FROM %s WHERE LOWER(TERM) LIKE LOWER('%s%%') %s",str1,str2,str3)
        end

        -- Исправляем кавычки в запросе.
        q = string.gsub(q, 'SELECT CODE,NAME FROM%s+"(.+)"%s*(.*)', 'SELECT CODE,NAME FROM `%1` %2') -- Del start '.

        MyDebug('Fixed query: ' .. q .. '\n')
        file:write('Fixed query: ' .. q .. '\n')
        file:close()

        proxy.queries:append(2, string.char(proxy.COM_QUERY) .. q, {resultset_is_needed = true})

        return proxy.PROXY_SEND_QUERY
end

function read_query_result(inj)
        if inj.id == 1 and inj.resultset.rows ~= nil then
                local file = io.open('/var/log/mysql-proxy.log', 'a')
                for row in inj.resultset.rows do
                local i = 1
                local fields = {}
                while row[i] do
                        if row[i] == row then break end
                                file:write('Response field: ' .. inj.resultset.fields[i].name .. ' => ' .. row[i] .. '\n')
                                i = i + 1
                        end
                end
                file:close()
                return proxy.PROXY_IGNORE_RESULT
        end
end

В ходе экспериментов для подключения к БД был получен такой конфиг dns.ini для работы с MySQL:
Универс|DRIVER=MySQL ODBC 5.2 Unicode Driver;NO_SSPS=1;MULTI_STATEMENTS=1;AUTO_RECONNECT=1;LOG_QUERY=0;IGNORE_SPACE=1;COMPRESSED_PROTO=1;NO_PROMPT=1;CHARSET=cp1251;DATABASE=marcsql;SERVER=192.168.4.26;PORT=4040;UID=marcsql;PASSWORD=password;
Описание некоторых опций:
  • NO_SSPS=1; - Включение подстановок на стороне клиента, а не сервера (т.е. запросы в которых есть знаки "?").
  • COMPRESSED_PROTO=1; - Включение сжатия (немного повышается скорость работы с большими результатами запросов).
  • NO_PROMPT=1; - Отключение окна запроса, при переподключении к БД.
  • CHARSET=cp1251; - Кодировка в которой будет идти обмен между сервером и клиентом (программа для Windows и работает в cp1251).
  • BASE=marcsql; - Имя базы.
  • SERVER=192.168.4.26; - Адрес сервера MySQL-Proxy.
  • PORT=4040; - Порт на котором работает MySQL-Proxy.
  • UID=marcsql; - Логин, для подключения к БД.
  • PASSWORD=password; - Пароль, для подключения к БД.
Но на этом рано останавливаться, нужно еще привести в порядок запросы в файлах программы да и самой программе объяснить, что мы будем использовать MySQL, а не MS Access: Добавляем в конец информацию о MySQL в bin/db.ini:
[Mysql]

ScriptPath=..\sql\Mysql
CreateTempTable=CREATE TABLE &Table&TabSuf(DOC_ID INTEGER PRIMARY KEY)
DictQuery=SELECT TERM,CNT FROM &Table
В файле DbmsParams.ini:
[Mysql]

$VARCHAR=VARCHAR
$COUNTER=INT AUTO_INCREMENT
$DOUBLE=FLOAT
$LONGTEXT=TEXT
$LONGBINARY=TEXT
$MIDTEXT=TEXT
$TEXT=TEXT
$DBPREF_=marcsql.
$COLUMN=
$TOP1000=
$ALTERCOLUMN=ALTER COLUMN
Добавляем информацию о возрастном маркере в EditMap.ini:
[333a]
EditForm=TECombo
ComboValues=0+  Для дошкольного возраста,6+  Для младшего школьного возраста,12+ Для среднего школьного возраста,16+ Для старшего школьного возраста,18+ Для взрослых
TagValues=Для дошкольного возраста,Для младшего школьного возраста,Для среднего школьного возраста,Для старшего школьного возраста,Для взрослых
Separator=,
OnlyFormEdit=Yes
DefaultMenu=NO

[200e]
EditForm=TECombo
ComboValues=[0+],[6+],[12+],[16+],[18+]
TagValues=[0+],[6+],[12+],[16+],[18+]
Separator=,
OnlyFormEdit=Yes
DefaultMenu=NO
Добавляем редактор LibreOffice в файле marc.ini в секцию [Editors]:
[Editors]

LibreOffice=swriter.exe
Изменяем файл phase.ini под потребности нашей школы:
[Книги]

CreateTags=245anpbco,100ae,700ae,653a,520a,020ac,090ax,084a,110a,260abc,440a,650a,200e,300ab,333a,952be,526cde,250a,998а,773b,773d,773t,773g,013ddee
EditTags=245,100,700,653,520,020,090,084,110,200,260,440,650,300,333,952,526,250,998,773
ViewTags=100a,100e,700a,700e,245a,245b,245o,245p,245n,260a,260b,260c,300a,300b,333a,440a,020a,020c,650a,090a,090x,084a
ShowAllTags=YES
RecType=a
BibLevel=m
В файле RdrData.ini, в секции [Common] исправляем запрос LastReaderQuery:
LastReaderQuery=SELECT RDR_ID FROM &ReadersPrefREADERS ORDER BY LEN(RDR_ID) DESC, RDR_ID DESC LIMIT 1
Теперь SQL файлы, заходим в каталог sql:
Была проблема при удалении записей из таблиц словарей, исправляется в файле delidx.sql: Ищем строку:
DELETE FROM &Table WHERE CNT=0;
Заменяем её на:
DELETE FROM &Table WHERE CNT<=0;
Исправляем проблему с удалением данных из таблицы METAIDX ищем в файле dropdict.sql строку:
DELETE FROM METAIDX WHERE NAME='&Table.TERM'
Заменяем её на:
DELETE FROM `METAIDX` WHERE `NAME` = '&Table.`TERM`';
DELETE FROM `METAIDX` WHERE `NAME` = '&Table.TERM';
Теперь создаем каталог Mysql и копируем все файлы из каталога Access в созданный каталог Mysql (напоминаю, мы должны быть в каталоге sql). Другими словами мы должны получить копию папки sql/Acess, но по адресу sql/Mysql. И приводим в порядок файлы в каталоге sql/Mysql: Файл crdict.sql приводим к такому виду:
INSERT INTO METAIDX(`NAME`,`TYPE`,`MAXLEN`,`TAGS`,`CAPTION`,`SEP`) VALUES('&Table.`TERM`','&Type',&MaxLen,'&Taglist','&Caption','&Sep');

CREATE TABLE &Table (
 `IDX_ID` INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
 `TERM` VARCHAR(&MaxLen),
 `CNT` INTEGER);

CREATE TABLE `&TableX` (
 `IDX_ID` INTEGER NOT NULL,
 `DOC_ID` INTEGER NOT NULL,
 FOREIGN KEY(`IDX_ID`) REFERENCES `&Table`(`IDX_ID`));

CREATE INDEX &TableXB ON &TableX(`DOC_ID`);
CREATE INDEX &TableXC ON &TableX(`IDX_ID`);
Файл rebuild.sql приводим к такому виду:
DROP TABLE IF EXISTS `IDXTEMP`;

CREATE TABLE `IDXTEMP` (`DOC_ID` INTEGER, &Term Text);
$BUILD;
$Инициализация таблицы индексов;
DELETE FROM &TableX;
DELETE FROM &Table;
$Заполнение таблицы индексов;
INSERT INTO &Table(&Term,CNT) SELECT &Term, Count(&Term) FROM IDXTEMP GROUP BY &Term;
$Заполнение таблицы перекрестных ссылок;
INSERT INTO &TableX(IDX_ID,DOC_ID) SELECT &Table.IDX_ID,IDXTEMP.DOC_ID FROM &Table,IDXTEMP
WHERE IDXTEMP.&Term=&Table.&Term;
$Удаление временной таблицы;
DROP TABLE IDXTEMP;
На этом изменения в файлах программы окончены. Пришло время конвертировать базу, я конвертировал при помощи BullZip Access To MySQL[6], на выходе получил .sql файл, который был скопирован на сервер и залит в БД. На этом все.

1. Reserved Words in MySQL 5.0
2. Download MySQL Proxy
3. Download Connector/ODBC
4. 20.1 – Pattern-Matching Functions
5. MySQL On air. Мониторим SQL запросы
6. Access To MySQL
7. MySQL и MarcSQL
8. Версия АИБС "МАРК-SQL" для школьных библиотек находится в свободном доступе для российских школ.

Комментариев нет:

Отправить комментарий