пятница, 7 декабря 2007 г.

Кодировка подключения и DDL в FB 2.1

> Кстати ты в курсе что в последних файрах если ты подключился в
> NONE то DDL операторы выполнять противопоказано? По крайней мере некоторые

Почему:
выполняем в NONE:

create procedure AAA
as
begin
-- тут был вася
end

В каком чарсете запишется вася в RDB$PROCEDURE_SOURCE? Правильно, в
WIN1251. А должен быть в юникоде. И если теперь подключиться в cp1251,
то получишь ошибку транслитерации.

--
Дмитрий Еманов

понедельник, 26 ноября 2007 г.

Проблема кодировок в post-commit svn

Возникла в нашей команде задача оповещения о чужих коммитах. Для командного общения активно используем гугловскую группу, поэтому идущий в поставке svn механизм рассылки пост-коммитов подходил на 100%.

Но сходу механизм не заработал - письма, при запуске скрипта самим svn не приходили, а при отладочных запусках из консоли - приходили, но со слетевшей, в utf, кодировкой(svnlook выдавал русские комvентарии в консоль юникодом).

Вторая проблема решилась небольшим переписыванием скрипта commit-email.pl:
установкой нужной локали
$ENV{'LC_ALL'} = 'russian';
и заданием нужной кодировки в хидерах писем(было UTF-8)
push(@head, "Content-Type: text/plain; charset=koi8-r\n");

Первая - добавил в post-commit скрипт переход в каталог, в котором он сам и расположен

REPOS="$1"
REV="$2"
cd /home/.../hooks/
/home/.../hooks/commit-email.pl "$REPOS" "$REV" "plaincad-dev@googlegroups.com" --diff n >1 2>2

суббота, 10 ноября 2007 г.

Рестор БД под 2.1 с гранатами для non-ascii пользователей

Натолкнулся на неприятную особенность - из-за некорретной работы с unicode версий ФБ менее 2.1, при ресторе БД, в которой даны какие-то права пользователям, имя которого содержит, к примеру, русские символы, рестор останавливается:

gbak: restoring privilege for user ДЕНИС
gbak: ERROR:arithmetic exception, numeric overflow, or string truncation
gbak: ERROR: Cannot transliterate character between character sets
gbak: ERROR: At trigger 'RDB$TRIGGER_9'
gbak:Exiting before completion due to errors

Ситуация конечно редкая, для заведения таких прав до версии 2.1 нужна недюжинная фантазия.

Если такой грант давать в 2.1 - то все работает штатно.

суббота, 29 сентября 2007 г.

Неоднозначность в запросах с сортировкой и distinct

Такой вот запрос, в FB2 отрабатывает, но данные возвращает в случайном порядке.
select distinct(t.f1) from table1 t order by t.id

Как подсказал Дима Кузьменко:
сначала идет distinct, потом order.
то есть. набор выливается в sort, удаляются повторы.
Затем набор сортируется по атрибуту order.
как оно этот атрибут возьмет - зависит от того, как на диске
или в индексе легло.
план в 2.0 - PLAN SORT (SORT ((table1 NATURAL)))

А вот Oracle(как выяснилось и PostgreSQL) с такими запросами посылает(после чего и поднялся вопрос).
http://ora-01791.ora-code.com/
ORA-01791: not a SELECTed expression
Cause:
There is an incorrect ORDER BY item. The query is a SELECT DISTINCT query with an ORDER BY clause. In this context, all ORDER BY items must be constants, SELECT list expressions, or expressions whose operands are constants or SELECT list expressions.
Action:
Remove the inappropriate ORDER BY item from the SELECT list and retry the statement.


Для экспериментов:
CREATE TABLE TABLE1 (
ID INTEGER NOT NULL,
F1 VARCHAR(10)
);

INSERT INTO TABLE1 (ID, F1) VALUES (1, 'q');
INSERT INTO TABLE1 (ID, F1) VALUES (2, 'w');
INSERT INTO TABLE1 (ID, F1) VALUES (3, 'e');
INSERT INTO TABLE1 (ID, F1) VALUES (4, 'r');
INSERT INTO TABLE1 (ID, F1) VALUES (5, 't');
INSERT INTO TABLE1 (ID, F1) VALUES (6, 'q');
INSERT INTO TABLE1 (ID, F1) VALUES (7, 'w');
COMMIT WORK;

Блокировка файла базы при XNET подключении с использованием событий

>> 2) Сервер после отключения ничего не держит.
> Неправдачка ваша.
> При XNET подключении с использованием событий именно держит.

События - ключевой момент. Там поток их доставки ждёт 5 сек
до полного отруба.

--
Хорсун Влад

воскресенье, 9 сентября 2007 г.

Хитрый способ починки БД с помощью nbackup

>04.09.2007 12:17:06 INFO: Analyzing database low-level structures...
> 04.09.2007 12:17:06 INFO: Process database file #1 of 1 files.
> 04.09.2007 12:20:01 INFO: Actual PageCount: 238816 found in database
> 04.09.2007 12:20:01 ERROR: Found 6168 undefined pages.
>
> Насколько это страшно ?

VK>> Если это ОДС 11.1 и все 6168 undefined pages в конце БД, то это
VK>> совершенно не страшно.
VK>> Сделай бекап 0-го уровня nbackup'ом, пофикси его им же для
VK>> превращения в БД, и сравни с р-ром оригинала. Потом прогони
VK>> FirstAID на полученной копии
>
> Влад, а можешь пару слов про низкий уровень процесса?
> Nbackup их восстановит правильно или отбросит?

FB 2.1, работая с родным форматом ОДС 11.1, по-умолчанию расширяет файл БД
относительно большими кусками, а не по-странично как раньше. Соответственно в
конце файла, как правило, есть страницы, которые никогда не были использованы.
В PIP есть отметка о том, сколько страниц было реально использовано. nbackup
читает эти отметки и не включает в бекап эти страницы.

--
Хорсун Влад

Различия в работе с savepoint в Firebird и Interbase

Kovalenko Dmitry wrote:
>
> Родился вопрос. А в стандарте SQL (99) вроде как прописано понятие
> точек сохранения (SAVEPOINT).

Так точно.

> А прописано ли в нем что делать с точкой B в таком случае?
>
> 1. savepoint A;
> 2. savepoint B;
> 3. savepoint A;
> 4. в этой точке у нас savepoint B (по-стандарту) существует или нет?

Стандарт лишь говорит, что должен удалиться старый сейвпойнт А и
создаться новый с тем же именем.

> в IB savepoint "B" будет изничтожен

Судя по всему, IB неявно выполняет RELEASE SAVEPOINT A (который по
стандарту уничтожает все сейвпойнты от А до настоящего времени), в то
время как FB выполняет наше расширение: RELEASE SAVEPOINT A ONLY,
которое удаляет только данный сейвпойнт. Отсюда и разница.

Я считаю наше поведение правильным.

--
Дмитрий Еманов

воскресенье, 2 сентября 2007 г.

Мега связка Perl+Oracle

DBD-Oracle-1.19\README.win32.txt
1)...
8) Enough Downloading and installing go have a coffee.

А перед этим мы скачали все что только можно от МС(Microsoft Visual Studio 2005,Windows SDK, Microsoft .Net framework 1.1) - опенсорс, мля.

PS не нужно воспринимать сей пост серьезно
PSS хотя...

понедельник, 16 июля 2007 г.

Странности перла

Что вы подумаете должен вернуть ниже приведенный код?

bbb?
неа
b0b

Спасибо другу-перловику - он удержал мой мозг на месте:
There is a single iterator for each hash, shared by all each(), keys(), and values() function calls in the program; it can be reset by reading all the elements from the hash, or by evaluating keys HASH or values HASH


Интересно, чего стоит этот пустой keys(%$f___ed_hash);

my $f___ed_hash = {
1=>'a',
2=>'b',
3=>'c'
};

sub eb___ya_sub {
keys(%$f___ed_hash);
while (my ($n,$w)=each(%$f___ed_hash)){
if($n==2) {
return $w;
}
}
}

print &eb___ya_sub;
print &eb___ya_sub;
print &eb___ya_sub;

вторник, 26 июня 2007 г.

Долговременная очередь в таблице Oracle

Возникла задача организации долговременной очереди, используемой несколькими параллельными конкурирующими обработчиками, которые, в общем случае, могут находиться на разных машинах.
Доп требование к очереди - ее архивное хранение и ограничение по используемой СУБД - Oracle.

Путей решения виделось несколько:
1. Использование готового решения от Оракл - AQ
2. Создание сервера приложений - эдакого контроллера очереди, посредством которого доступ к данным будет сериализован
3. Использование механизма конкурентного доступа и блокировок самой СУБД.

По ряду обстоятельств(технические сложности работы а AQ и полнейшее с ним незнакомство, трудоемкость создания доп слоя...) был выбран третий путь(учитывая FB-шное прошлое он показался более близким, чтоль:)

Суть метода в том, что обработчик помечает пакет записей заблокированными на обработку - в это время никто не должен иметь к ним доступа, а после обработки блокировка снимается и сообщения помечается обработанным.

В FB такое можно сделать посредством подобной селективной процедуры, привычно ставя блокировку холостым апдейтом.

CREATE PROCEDURE QUERY_SEL(row_count integer) RETURNS (ID_row INTEGER)
AS
begin
for select first(:row_count) sq.id_row,
from query sq
where sq.id_send_state=1
into :id_row do
begin
update sgt_query sq set sq.id_mess_state=2
where sq.id_row=:id_row;
suspend;
when any do
begin
row_count = row_count +1;
end
end
end

Оракл оказался богаче - недокументированный for update skip locked; подходил идеально(похоже это и есть механизм реализации AQ), но слушая Кайта с негодованием отметаем подобный "ugly hack" и пытаемся сделать это вручную, посредством pipeline функции.

Столкнувшись с невозможностью запуска апдейтов внутри селекта, познакомился с автономными транзакциями.
Выделив апдейт(блокировку) в отдельную процедуру задача в общих чертах решилась.

create or replace procedure sgt_queue_lock(
row_count in integer default 10,
locker_id_ in integer )
as
lockedCount integer := 0;
ERROR_LOCK EXCEPTION;
PRAGMA EXCEPTION_INIT(ERROR_LOCK, -54);
PRAGMA AUTONOMOUS_TRANSACTION;
begin
-- receive all unlocked and unsended messages and lock them
-- from competitive lockers
for r1 in (select id_mess from SGT_QUEUE t where t.ID_mess_STATE=1
for update nowait)
loop
begin
-- long time lock for processing time
update SGT_QUEUE t set t.ID_mess_STATE=2,t.LOCKER_ID=locker_id_
where t.ID_mess=r1.id_mess;
lockedCount := lockedCount+1;

if(row_count=lockedCount) then
exit;
end if;

-- if row is locked - skip it
exception when error_lock then
null;
end;
end loop;
commit;
end sgt_queue_lock;

Конечно оборачивание всего в функцию необязательно, но чем меньше вариантов использования для прикладников - тем лучше, не так ли?


create or replace function queue_get
(row_count integer, locker_id integer)
return queue_table_type PIPELINED
as
suspendedCount integer := 0;
out_rec queue_type := queue_type(null,null,null,null);
begin
-- долговременно и монопольно блокируем пакет записей для
-- обработки определенным процессом
BEGIN
-- проверяем, есть ли еще необработанные/не отосланные сообщения в очереди
-- если есть - то новых блокировать не будем
-- из-за отсутсвия exists проверям наличие записей очень извратно
select 0 into suspendedCount from SGT_QUEUE t
where t.LOCKER_ID=locker_id and
t.ID_MESS_STATE=2 and rownum=1;
EXCEPTION WHEN NO_DATA_FOUND THEN
begin
SGT_QUEUE_LOCK(row_count,locker_id);
end;
END;

-- выше использовали как временную заглушку
suspendedCount := 0;
-- выбираем записи помеченные на обработку для этого процесса
-- (не провайдера, а именно процесса)
for r1 in (select id_MESS, MESS_DATA from SGT_QUEUE t
where t.LOCKER_ID=locker_id and t.ID_MESS_STATE=2
order by t.MESS_PRIORITY DESC,t.RECEIVE_TIME ASC)
loop
out_rec.id_mess := r1.id_mess;
out_rec.mess_data := r1.mess_data;

PIPE ROW(out_rec);

suspendedCount := suspendedCount+1;
if(row_count=suspendedCount) then
exit;
end if;

end loop;
return;
end queue_get;

Из недостатков видится не максимальная скорость работы, но учитывая то, что записи на обработку будут забираться пакетно - особой проблемы это не составит.
Может кто еще какие сложности/ошбики видит?

Да, как оказалось, подобные вопросы встречаются регулярно :)

Выбрать первую незаблокированную запись из таблицы, как?
http://www.sql.ru/forum/actualthread.aspx?tid=389300&hl=aq

Таблица oracle как очередь
http://www.sql.ru/forum/actualthread.aspx?tid=309047&hl=aq

Параллельная работа с записями.
http://www.sql.ru/forum/actualthread.aspx?tid=307911&pg=-1&hl=aq

Select for update - как получить незаблокированные данные
http://www.sql.ru/forum/actualthread.aspx?tid=264566&pg=-1&hl=aq

Таблица-буфер. Уникальная выборка строк для каждого процесса.
http://www.sql.ru/forum/actualthread.aspx?tid=239337&hl=aq

четверг, 14 июня 2007 г.

Нет в Oracle exists

Нет в оракле конструкции exists в pl/sql, подобной той, что есть в Firebird/Interbase
if exists(select..) then
приходится извращаться через:
select count(1) into from table where rownum=1
EXCEPTION WHEN NO_DATA_FOUND THEN
code;

Надеюсь rownum=1 дает хоть какой-то выигрыш в скорости(exists достаточно быстрая операция, в отличии от count).

PS
Прикольно - казалось бы логичное ограничение в rownum=1, может сработать не всегда - когда таблица партиционирована, используется каунт и включен параллелизм - может идти фуллскан по всей таблице. Горе от ума, что говорится.
Правда до версии 10g r1 (Relevant for Oracle until 10g r1)
"Selecting ROWNUM = 1 with 100.000 PIO"
http://www.db-nemec.com/Selecting_ROWNUM_1.html

четверг, 29 марта 2007 г.

Очень кратко и по русски, что нового в Firebird 2.1

  • триггеры на сист операции - коммит/роллбек, коннект/дисконнект
  • глобальные временные таблицы
  • рекурсивыне запросы и соответственно common table expressions("общие табличные выражения" из SQL-99) http://en.wikipedia.org/wiki/Common_table_expressions
  • давно ожидаемый мною агрегат для строк, который черти-когда сделал OlegLOA - LIST
  • update or insert и merge(более навороченный u or i ) - http://en.wikipedia.org/wiki/Merge_%28SQL%29
  • домены в пскл, для чего добавлен признак валидности процедур и триггеров
  • таблицы мониторинга - активные запросы, пользователи и т.п. соответственно отмена(прибитие) долгоиграющих запросов(из другого соединения)
  • оптимизация сетевого трафика
  • номер строки и позиция в стеке ошибки пскл

и не мало чего еще