Выполнить запрос к FB из консоли можно при помощи утилиты isql.
Оказалось, что линуховый isql штатными средствами этого не умеет (выньдовый, к стати, умеет цуко).
Погуглив вдоволь, нашел 2 варианта решения. Первый, быстрый и универсальный: не зависит от текста запроса и количества строк в результате запроса. Второй, рассчитан только на элементарные тексты запросов и "долгий" , при большом количестве строк в результате запроса.
Итак, вот, собственно, оба решения:
Вариант 1. Воспользоваться утилитой odbcsql (спасибо hellcat) :
Утилиту можно скачать здесь. Утилита кросс-платформенная. Не чувствительна к битности ОС. Инструкция по установке и необходимые драйвера в комплекте.
Принцип работы с qdbcsql такой:
$odbcsql DSN=mydatabaseDSN Query.sql Output.xml Error.log
где
DSN=mydatabaseDSN - DSN или строка подключения к БД
Query.sql - файл, в котором лежит текст SQL-запроса, который необходимо выполнить
Output.xml - файл, в который необходимо положить результат запроса (в формате XML)
Error.log - файл, в котором будут лежать логи
Вариант 2. Добавляем в БД две хранимых процедуры (stored procedure):
XML_GENERATOR_FIELDS:
SET TERM ^ ; CREATE PROCEDURE XML_GENERATOR_FIELDS( FIELDS VARCHAR(1024), SQL_RIGHT VARCHAR(1024)) RETURNS ( RECORD INTEGER, XML_TEXT VARCHAR(1024)) AS declare variable i integer; declare variable len integer; declare variable c char(1); declare variable field varchar(100); BEGIN /* lenght fields */ len = char_length(fields); /* loop in fields string */ i = 1; field = ''; /* clear field */ while (i <= len) do begin /* current char */ c = substring(fields from :i for 1 ); /* if comma, select values of current field */ if (c = ',') then begin /* trim fields */ field = trim(:field); /* order by record in the sp (xml_generator) */ record = 0; /* values of current field */ for execute statement cast( 'select ' || :field || ' from ' || :sql_right as varchar(1024)) into :xml_text do begin /* formatting the xml line */ /* <field>value</field> */ xml_text = '<' || :field || '>' || :xml_text || '</' || :field || '>'; /* order by in xml_generator */ record = record + 1; suspend; end /* clear field */ field = ''; end else /* char by char... */ field = field || c; /* next char */ i = i + 1; end END^ SET TERM ; ^
XML_GENERATOR:
SET TERM ^ ;SET TERM ^ ;
CREATE PROCEDURE XML_GENERATOR(
PHEADER VARCHAR(1024),
PSQL VARCHAR(1024))
RETURNS (
XML_TEXT VARCHAR(1024))
AS
declare variable field varchar(30);
declare variable fields varchar(1024);
declare variable fields_begin smallint;
declare variable fields_end smallint;
declare variable from_end smallint;
declare variable sql_end smallint;
declare variable sql_right varchar(1024);
declare variable i integer;
declare variable records integer;
declare variable table_name varchar(30);
BEGIN
/* uppercase and trim psql parameter */
psql = upper(trim(psql));
/* extract fields from psql parameter */
fields_begin = position(' ',:psql)+1;
fields_end = position(' FROM ', psql);
fields = substring(psql from :fields_begin
for :fields_end-:fields_begin) ||
','; /* for extract the last field */
/* extract table name, where, order by, etc... */
from_end = fields_end + 6;
sql_end = char_length(psql)-from_end+1;
sql_right = substring(psql from :from_end for sql_end) || ' ';
/* extract only table name for "all fields" and */
/* open/close tags in xml */
table_name = substring(sql_right from 1
for position(' ',sql_right)-1);
/* if fields = '*', fields = "all fields" of the table */
if (fields = '*,') then
begin
fields = '';
for select trim(rdb$field_name) from rdb$relation_fields
where rdb$relation_name = :table_name order by rdb$field_id
into :field do fields = fields || :field || ',';
end
/* if pheader xml isnull... */
if (:pheader is null) then
pheader = '<?xml version="1.0" encoding="UTF-8" ?>';
/* returns pheader to client... */
xml_text = :pheader;
suspend;
/* open table */
xml_text = '<' || :table_name || '>';
suspend;
/* record count... */
execute statement
cast('select count(*) from ' || :sql_right as varchar(1024))
into :records;
/* fields from another stored procedure */
/* loop first to last record */
i = 1;
while ( i <= records ) do
begin
/* open record */
xml_text = '<RECORD>';
suspend;
/* fields and values in another stored procedure */
for select xml_text from xml_generator_fields(:fields, :sql_right)
where record = :i into :xml_text do
suspend;
/* close record */
xml_text = '</RECORD>';
suspend;
/* next record */
i = i + 1;
end
/* close table */
xml_text = '</' || :table_name || '>';
suspend;
END^
SET TERM ; ^
Собственно эти две процедуры генерируют нам на выходе результат запроса уже в готовой XML схеме.
Выгружаем результат запроса в XML:
Создаем SQL-скрипт и пишем в него запрос:
$touch Script.sql
$echo "SELECT XML_TEXT FROM XML_GENERATOR('<?xml version="1.0" encoding="windows-1251" ?>',' select a from ADMINUSERS' )"
Здесь, параметр 1 ('<?xml version="1.0" encoding="windows-1251" ?>') - это загаловок нашего XML-файла, а параметр 2 (' select a from ADMINUSERS') - это интересующий нас запрос
Далее даем шыйд команду на выполнение нашего запроса и сохранение его результатов в файл:
$isql MixPos -b -x0x0A < Script.sql > Result.xml
где
- "MixPos" - это DSN для нашей БД
- параметр "-b" отключает лишние комментарии командной строки isql, чтоб остался только результат запроса без дополнительной служебной информации
- параметр "-x0x0A" заменяет разделитель колонок в результате запроса на "Enter"
- "Script.sql" - это файл, где лежит тест запроса
- "Result.xml" - это необходимы нам XML-файл, куда вернется результат запроса
Проверим выполнение:
$isql MixPos -b -x0x0A < Script.sql > Result.xml
Получим такой вот Result.xml:
<ADMINUSERS>
<RECORD>
<ADMIN_ID>1</ADMIN_ID>
<PASSWD>********</PASSWD>
<PUBLISHED>P</PUBLISHED>
<LOGIN>admin</LOGIN>
</RECORD>
</ADMINUSERS>
Комментариев нет:
Отправить комментарий