28 июл. 2010 г.

Как удалить все записи

Приведенная команда позволяет удалить все документы, которые не заблокированы ссылочной целостностью или триггерами:
execute block
as
  declare variable id integer;
begin
  for select id from gd_document into :id
  do begin
    delete from gd_document where id=:id;
    when any do begin end
  end
end
Очевидно, что вместо gd_document можно указать, например, gd_contact и почистить справочник клиентов.

НЕ ИСПОЛЬЗУЙТЕ НА РАБОЧИХ БАЗАХ КЛИЕНТОВ!

PS: И, да, у нас полумиллионный посетитель на сайте!

24 июл. 2010 г.

Pascal forever

Apple has opened sources of their MacPaint and QuickDraw applications. Naturally, it had been done in Pascal with some assembler insertions. The sources are available from this Computer History Museum page.

14 июл. 2010 г.

Посадили дерево

В наших интервальных деревьях всю жизнь была ошибка. Интервалы перекрывались в следующем случае: есть два элемента A и B, имеющих одного родителя. A расположен левее B. Пусть B имеет два дочерних элемента C и D, примыкающих друг к другу, причем C расположен левее D и интервал C уже D. Тогда, при перемещении D в A, в процессе расширения интервалов вправо, интервал C будет перекрываться с A и B.

KISS

Компоненты IBX имеют жутко навороченный механизм трассировки SQL команд: монитор, хук к нему, интерфейс к хуку и две нити, для чтения и записи лога. Вероятно была попытка сделать монитор, который бы минимально тормозил текущие операции (отсюда раздельная запись и чтение в обособленных нитях), и позволял бы менять движки как перчатки (отсюда хук и интерфейс, кстати достаточно бесполезный, так как объявляется в самом модуле монитора и завязан на объявления прочих объектов из этого модуля).

Некоторое время в Гедымине присутствовал механизм трассировки запросов, основанный на стандартном мониторе. Позже он был выкинут, так как отловить все ошибки во взаимодействии читающих и пишущих нитей не удалось и монитор хоть и изредка, но кидал AV.

Новый механизм был создан за два дня, буквально следуя принципу KISS — Keep It Simple Stupid. В его основе объект истории SQL запросов (TgdcSQLHistory) и копия интерфейса борландовского SQL монитора. Везде, где надо, через условную компиляцию мы подменили обращение к модулю IBSQLMonitor.pas на IBSQLMonitor_Gedemin.pas.

Лог трассировки находится в SQL редакторе на соответствующей вкладке. Там же — чек-бокс для включения/выключения и кнопка очистки. Трассировку можно также активировать параметром командной строки /trace.

7 июл. 2010 г.

Жорсткая праўда беларускага інтэрнэту

Адзін з найбуйнейшых айчынных правайдэраў, Деловая Сеть, мае канал у 750 Мбіт/с на... 6 000 кліентаў. Які тут анлім. Калі ўсе разам пойдуць у сеціва атрымаецца па 125 Кбіт/с на брата. У іншых "незалежных" правайдэраў каналы яшчэ вузейшыя. І ўсе разам яны ўпіраюцца ў ліміт знешнега каналу нашага горача любімага манапаліста Белтэлекома, які ў заходнім накірунку складае менш за 16 Гбіт/c. Калі падзяліць на колькасць карыстальнікаў сеціва (4 млн), дык кожнаму дастанецца ажно па 4 (Чатыры!) Кбіт/с.

1 июл. 2010 г.

Дело было не в бобине

Десять лет мы наблюдали редкие-редкие нарушения вложенности по LB, RB на базах наших клиентов. До сих пор считалось, что проблема в незащищенности полей со значениями границ от случайной записи. Однако, тесты выявляют нарушение вложенности и в стерильных лабораторных условиях, когда поля LB, RB уж точно никем сторонним не заполняются.


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

Будем искать.

Первый самостоятельно написанный EXECUTE BLOCK

EXECUTE BLOCK (id INTEGER = :id) 
  RETURNS (companykey INTEGER) 
AS 
  DECLARE VARIABLE ct INTEGER;
BEGIN 
  ct = 4; 
  companykey = 0; 

  WHILE (:ct = 4 AND NOT :companykey IS NULL) DO 
  BEGIN 
    companykey = NULL; 

    SELECT id, parent, contacttype 
    FROM gd_contact 
    WHERE id = :id 
    INTO :companykey, :id, :ct; 
  END 

  SUSPEND; 
END 
Возвращает организацию для заданного подразделения. Хотя, конечно, все можно было сделать простым запросом:
SELECT c.id 
FROM gd_contact c JOIN gd_contact d
  ON c.lb < d.lb AND c.rb >= d.rb
WHERE d.id = :ID AND c.contacttype = 3