Столкнулся с проблемой, АИБС "МАРК-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
файл, который был скопирован на сервер и залит в БД. На этом все.
Ссылки по теме:
Comments
comments powered by Disqus