14 сент. 2013 г.

Список объектов в соответствии с заданными зависимостями

Если в предыдущем примере мы ранжировали заданный список объектов, то следующий пример возвращает упорядоченный в соответствии с иерархией зависимости список объектов, от которых зависит указанный объект.
WITH RECURSIVE 
  ns_tree AS ( 
    SELECT 
      f.filename, 
      CAST((f.xid || '_' || f.dbid) AS VARCHAR(1024)) AS path, 
      l2.uses_xid, 
      l2.uses_dbid 
    FROM 
      at_namespace_file f 
      JOIN at_namespace_file_link l 
        ON l.uses_xid = f.xid AND l.uses_dbid = f.dbid 
      LEFT JOIN at_namespace_file_link l2 
        ON l2.filename = f.filename 
    WHERE 
      l.filename = :filename 
         
    UNION ALL 
     
    SELECT 
      f.filename, 
      (t.path || '-' || f.xid || '_' || f.dbid) 
        AS path, 
      l.uses_xid, 
      l.uses_dbid 
    FROM 
      ns_tree t 
      JOIN at_namespace_file f 
        ON t.uses_xid = f.xid AND t.uses_dbid = f.dbid 
      JOIN at_namespace_file_link l 
        ON l.filename = f.filename 
    WHERE 
      POSITION ((f.xid || '_' || f.dbid) 
        IN t.path) = 0) 
SELECT 
  * 
FROM 
  ns_tree
Таблица at_namespace_file содержит список объектов, а at_namespace_file_link -- связи между ними. Вычисление пути (path) и дополнительная проверка через функцию POSITION позволяют избежать зацикливания на кольцевых ссылках, если такие попадутся в исходных данных.

7 сент. 2013 г.

Firebird 2013 Tour

Firebird Project is glad to announce Firebird 2013 Tour – series of seminars around the world, devoted to Firebird, with members of Firebird Project as speakers.

The first seminar will be in Siegburg (North Rhine-Westphalia, Germany), November 22, 2013.

2 сент. 2013 г.

Удаление гланд автогеном...

Таблицу со строковым первичным ключем подключить к визуальным контролам Гедымина нельзя, так как все они поголовно спроектированы для работы с целочисленными идентификаторами. Выход -- добавить вычисляемую колонку в запрос, которую заполнять хэшем от строкового значения. Встроенная функция Firebird HASH() возвращает 64-х битное целое (тип BIGINT), которое следует сдвигать вправо, пока значение не войдет в допустимый для 32-х битных целых диапазон.

В следующем примере мы генерируем ключи типа INTEGER по наименованиям контактов (что не совсем корректно, так как сами наименования у нас могут быть неуникальными).

select
  cast(iif(log(2, hash(name)) > 30,
    bin_shr(hash(name), 
      cast(log(2, hash(name)) as integer) - 30),
    hash(name)) as integer),
  name
from 
  gd_contact
В некоторых случаях может подойти и заполнение колонки последовательными значениями генератора:
select
  gen_id(my_gen, 1),
  name
from 
  gd_contact

1 сент. 2013 г.

Построение списка зависимых объектов

Замечательная задача для проверки программиста на знание SQL и реляционных БД. Пусть в одной таблице хранится список объектов. Объекты могут зависеть друг от друга. Связи хранятся в другой таблице ввиде пар ключей: объект - объект, от которого зависит данный объект. Требуется построить упорядоченный список, чтобы для любого объекта в нем, все объекты, от которых он зависит, располагались перед ним.

Решение с использованием рекурсивного CTE:

WITH RECURSIVE
  ns_tree AS (
    SELECT
      n.filename AS headname,
      0 AS usescount,
      CAST((n.xid || '_' || n.dbid) AS VARCHAR(1024)) AS path,
      n.filename
    FROM
      at_namespace_file n

    UNION ALL

    SELECT
      t.headname,
      (t.usescount + 1) AS usescount,
      (t.path || '-' || n.xid || '_' || n.dbid) AS path,
      n.filename
    FROM
      ns_tree t
      JOIN at_namespace_file_link l
        ON l.filename = t.filename
      JOIN at_namespace_file n
        ON l.uses_xid = n.xid and l.uses_dbid = n.dbid
    WHERE
      POSITION ((n.xid || '_' || n.dbid) IN t.path) = 0
    )
SELECT
  t.headname, sum(t.usescount)
FROM
  ns_tree t
GROUP BY
  1
ORDER BY
  2
В приведенном запросе at_namespace -- список объектов, а at_namespace_link -- связи между ними. Вычисление пути (path) и дополнительная проверка через функцию POSITION позволяют избежать зацикливания на кольцевых ссылках, если такие попадутся в исходных данных.

Предупрежден -- значит вооружен!

Контроллеры Marvell 88SE91xx и HDD > 2.2TB (3TB, 4TB).

29 авг. 2013 г.

Подключение Embedded SWI-Prolog в Гедымин

Есть два варианта подключения Пролога. Первый -- мы обращаемся к embedded SWI-Prolog из кода на VBScript через глобальный объект (назовем его PL). Второй -- алгоритм пишется непосредственно на Прологе, а доступ к функционалу платформы происходит через Foreign Predicates.

Обращение к Прологу через глобальный объект мы рассмотрим на сравнительном примере доступа к реляционным данным из макроса на Гедымине. Пусть данные находятся в двух таблицах: GD_CONTACT(ID, CITYKEY, NAME) и GD_PLACE(ID, NAME):

ID  CITYKEY  NAME
======================
1   1        Company A
2   1        Company B
3   2        Company C

ID  NAME
======================
1   Minsk
2   Berioza 
Для извлечения cписка компаний по заданному наименованию города мы пишем SQL запрос, который выполняем через объект класса TIBSQL:
...
Dim q
Set q = Creator.GetObject(nil, "TIBSQL", "")
Set q.Transaction = gdcBaseManager.ReadTransaction
q.SQL.Text = _
  "SELECT c.name " & _
  "FROM gd_contact c JOIN gd_place p " & _
  "  ON p.id = c.citykey " & _
  "WHERE p.name = 'Minsk' "
q.ExecQuery
While Not q.EOF 
  ...
  q.Next
WEnd 
...
Теперь изобразим тоже самое на Prolog.

Исходные данные в виде предикатов Prolog выглядят так:

gd_contact(1, 1, 'Company A').
gd_contact(2, 1, 'Company B').
gd_contact(3, 2, 'Company C').

gd_place(1, 'Minsk').
gd_place(2, 'Berioza').
Правило связи компании с городом через ключи:
bycity(City, Name) :- 
  gd_place(CityID, City),
  gd_contact(_, CityID, Name).
Тогда запрос на извлечение всех минских компаний будет выглядеть следующим образом:
? bycity('Minsk', Name).
Что мы видим из данного примера?

  1. Необходим класс для доступа к Прологу из макросов. Далее по тексту будем называть его PL. Экземпляр данного класса создается стандартным образом через глобальный объект Designer/Creator. Каждый экземпляр может иметь свое имя.
  2. PL должен иметь метод для формирования предикатов на основании заданной SQL выборки. Пример кода:
    ...
    Call PL.MakePredicates(_
      "SELECT id, citykey, name FROM gd_contact", _
      gdcBaseManager.ReadTransaction, _ 
      "gd_contact", "name")
    ...
    
    Последний параметр -- имя выборки, которое будет использоваться для формирования имени .pl файла в режиме отладки.

    Пусть это и не касается непосредственно сопряжения Пролога с Гедымином, но здесь стоит вспомнить об идее изоляции разработчика от работы с SQL запросами и инкапсуляции последних внутрь т.н. SQL объекта. SQL объект -- это заранее написанный, проверенный и оптимизированный SQL запрос, загружаемый на базу стандартным образом через настройки или пространства имен. Для выполнения, программист обращается к нужному SQL объекту по его РУИДу.

  3. PL должен иметь метод для формирования предикатов на основании бизнес-класса. На вход передается класс-подтип, подмножество, дополнительные условия выборки. Сразу следует договориться о стандартном механизме (способе) загрузки данных мастер-дитэйл (например, документ накладная с позициями).
    ...
    Call PL.MakePredicates2(_
      "TgdcCompany", "", "ByID", Array(777777), "", _
      gdcBaseManager.ReadTransaction, _ 
      "gd_contact", "name")
    ...
    
  4. PL должен иметь метод для формирования предикатов на основании существующего набора данных (дата-сета).
  5. PL должен иметь метод для ручного формирования произвольных предикатов.
  6. PL должен иметь метод для вычисления цели. Результат вычисления может быть как одиночное значение, так и выборка. Для работы с последней предусмотрены методы итерации (EOF, First, Next) и методы для обращения к параметрам по имени.
  7. С помощью соответствующих методов результат вычисления может быть напрямую помещен в указанную таблицу в базе, клиент-датасет в оперативной памяти, или на его основе могут быть созданы новые бизнес-объекты в БД.
  8. Предикаты, которые создает разработчик, должны храниться в базе данных аналогично тому, как сейчас хранится код VBScript.
  9. В дереве Проводника Редактора скрипт-объектов следует добавить корневой раздел для кода на Прологе. Внутри раздела пролог-скрипты могут размещаться в папках.
  10. Минимальная единица для загрузки в объект PL -- один пролог-скрипт. Каждый скрипт имеет уникальное имя и РУИД. Загрузка осуществляется по РУИДу. Внутри скрипта могут встречаться директивы %#INCLUDE для загрузки других пролог-скриптов (аналогично директиве '#INCLUDE для VBScript).
  11. Стандартные библиотеки SWI-Prolog, которые в дистрибутиве занимают 8 Мб в 377 файлах, будут храниться в базе данных точно так же, как и обычные пролог-скрипты.
  12. Отладка:
    1. Для отладки на компьютере должен быть установлен полный вариант SWI-Prolog и, возможно, SWI-Prolog Editor.
    2. Местоположение SWI-Prolog и каталога для временных файлов задается в параметрах платформы.
    3. Режим отладки активизируется в параметрах редактора скрипт-объектов для списка конкретных экземпляров PL, заданных их именами. Если список пуст, то режим активируется для всех PL объектов.
    4. Когда активирован режим дебаггера предикаты записываются в текстовые файлы .pl программ во временном каталоге. При этом файлы формируются следующим образом:
      • Для каждого пролог-скрипта отдельный файл.
      • Результаты вызова MakePredicatesX помещаются в файлы в соответствии с заданными именами.
    5. При вызове метода вычисления цели в режиме дебаггера загружается SWI-Prolog или SWI-Prolog Editor. В среду выполнения/отладки подгружаются созданные временные файлы.
    6. Гедымин ждет завершения работы процесса SWI-Prolog.
    7. После окончания отладки проверяются файлы для выгруженных пролог-скриптов. Если обнаружены изменения Гедымин предлагает загрузить их в базу данных.

17 авг. 2013 г.

В Редактор SQL добавлена вкладка Бизнес-классы:

Выбрав класс в списке можно перенести его SelectSQL в окно выполнения запроса или открыть форму просмотра.

PS: Знаю, знаю, фильтр не помешал бы. Но, и Вильня не сразу строилась.

16 авг. 2013 г.

Просмотр объекта по ссылке

Добавлено в Гедымин. Если в окне редактора SQL, в таблице с результатом выполнения запроса, установить курсор на поле-ссылку, то с помощью кнопок на панели инструментов (на рисунке ниже) можно: открыть объект на просмотр/изменение, удалить объект, открыть форму просмотра объекта.

15 авг. 2013 г.

Замечено на улицах Минска

Стэнсильная реклама Гедымина.
День сурка -- это 15 лет работы с молодыми программистами. Раз за разом приходится объяснять очевидные вещи. Например, что нельзя формировать SQL запрос из кусочков текста, используя функции преобразования DateToStr, FloatToStr и т.п. Указанные функции при форматировании результата используют локальные региональные установки, которые могут не совпадать с требованиями стандарта SQL. Так, Firebird понимает дату из строки вида 'dd.mm.yyyy', а на компьютере пользователя может быть установлен формат 'dd-mm-yyyy'. Хуже всего, когда на машине разработчика локальный формат удовлетворяет сервер, а на компьютере клиента -- нет.

С функциями конвертации типов понятно. А строки? Строки вставлять категорически запрещается. Во-первых, наличие одинарных кавычек во вставляемом значении приведет либо к синтаксической ошибке, либо к неверной выборке. Во-вторых, см. SQL Injection.

11 авг. 2013 г.

Вот почему у нас куча односимвольных типов объявлена как VARCHAR вместо CHAR? Ладно бы еще всякие там activity флажки в плане счетов, но признак дебет/кредит для записи проводки это никуда не годится. Десять миллионов проводок, двадцать миллионов записей в AC_ENTRY == сорок миллионов байт на хранение длины поля, которая всегда равна 1. Может в этом и был когда-то какой-то смысл, но я решительно ничего не могу вспомнить.

Пока поменяем в скриптах генерации эталона. Если ничего не вылезет можно будет апдейт сделать и для существующих баз.

10 авг. 2013 г.

Таки дождались: Delphi for Android в стадии бета теста.