Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Нужна критика :) - репликации в FB


Андрей Жук ©   (2005-09-12 18:04:00) 

Текущее состояние дел.
В БД в таблицах, в которых нужно делать репликацию, добавил поле LAST_UPDATED. Заполняется триггером.
Создал дополнительную таблицу APP_TABLES со следующей структурой
CREATE TABLE APP_TABLES (
   TABLE_ID      IDENTIFIER NOT NULL /* IDENTIFIER = INTEGER NOT NULL */,
   TABLE_NAME    NAME NOT NULL /* NAME = VARCHAR(82) DEFAULT 'unknown' NOT NULL */,
   TABLE_DESC    DESCRIPTION /* DESCRIPTION = VARCHAR(255) */,
   IS_LOGGED     BOOLEAN /* BOOLEAN = VARCHAR(1) DEFAULT 'U' NOT NULL CHECK (value in ('Y','N','U')) */,
   PRIMARY_KEY   NAME COLLATE WIN1251_UA /* NAME = VARCHAR(82) DEFAULT 'unknown' NOT NULL */,
   EXPORT_ORDER  NONIDENTIFIER /* NONIDENTIFIER = INTEGER */
);


Создана таблица точек сохранения

CREATE TABLE APP_SAVEPOINTS (
   SAVEPOINT_ID        IDENTIFIER NOT NULL /* IDENTIFIER = INTEGER NOT NULL */,
   SAVEPOINT_NAME      NAME NOT NULL /* NAME = VARCHAR(82) DEFAULT 'unknown' NOT NULL */,
   SAVEPOINT_DESC      DESCRIPTION /* DESCRIPTION = VARCHAR(255) */,
   SAVEPOINT_DATETIME  TIMESTAMP NOT NULL,
   SAVEPOINT_CREATOR   NAME COLLATE WIN1251_UA /* NAME = VARCHAR(82) DEFAULT 'unknown' NOT NULL */,
   IS_ACTIVE           BOOLEAN DEFAULT 'N' NOT NULL COLLATE WIN1251_UA /* BOOLEAN = VARCHAR(1) DEFAULT 'U' NOT NULL CHECK (value in ('Y','N','U')) */
);


Создана процедура, которая делает XML изменившихся параметров

CREATE PROCEDURE GET_UPDATES
RETURNS (
   RES VARCHAR(32000))
AS
DECLARE VARIABLE TMP VARCHAR(4096);
DECLARE VARIABLE TABLE_NAME CHAR(31);
DECLARE VARIABLE FIELD_NAME CHAR(31);
DECLARE VARIABLE XML VARCHAR(4096);
DECLARE VARIABLE TABLE_ID INTEGER;
DECLARE VARIABLE RECORD_ID INTEGER;
DECLARE VARIABLE FIELD_CHAR INTEGER;
DECLARE VARIABLE FIELD_NULL INTEGER;
DECLARE VARIABLE PK CHAR(31);
BEGIN
 TABLE_ID = 1;
 FOR
   SELECT RDB$RELATIONS.RDB$RELATION_NAME, APP_TABLES.primary_key
   FROM RDB$RELATIONS, APP_TABLES
   WHERE RDB$RELATIONS.RDB$SYSTEM_FLAG = 0 AND
         RDB$RELATIONS.RDB$RELATION_NAME = APP_TABLES.TABLE_NAME AND
         APP_TABLES.IS_LOGGED = 'Y'
   ORDER BY APP_TABLES.EXPORT_ORDER
   INTO :TABLE_NAME,:PK
 DO
 BEGIN
   RES = '<table id="'||:TABLE_ID||'">';
   SUSPEND;
   TABLE_ID = :TABLE_ID + 1;
   RES = '<table_name>'||rtrim(:TABLE_NAME)||'</table_name>';
   SUSPEND;
   RES = '<primary_key>'||rtrim(:PK)||'</primary_key>';
   SUSPEND;

   TMP = 'SELECT ';
   FOR SELECT RDB$RELATION_FIELDS.RDB$FIELD_NAME,
   coalesce(RDB$FIELDS.RDB$CHARACTER_LENGTH,-1),
   coalesce(RDB$RELATION_FIELDS.RDB$NULL_FLAG,0)
   FROM RDB$RELATION_FIELDS, RDB$FIELDS
   WHERE
   RDB$RELATION_FIELDS.RDB$FIELD_SOURCE = RDB$FIELDS.RDB$FIELD_NAME AND
   RDB$RELATION_FIELDS.RDB$RELATION_NAME = :TABLE_NAME
   ORDER BY RDB$RELATION_FIELDS.RDB$FIELD_POSITION
   INTO :FIELD_NAME, :FIELD_CHAR, :FIELD_NULL
   DO
    begin
     if (:FIELD_NULL=0) then
      BEGIN
        if (:FIELD_CHAR=-1) then
         TMP = TMP || '''<' || rtrim(:FIELD_NAME) || '>''||coalesce(cast(' || rtrim(:FIELD_NAME) || ' as varchar(32)),'''')||''</' || rtrim(:FIELD_NAME) || '>''||';
          else
          TMP = TMP || '''<' || rtrim(:FIELD_NAME) || '>''||coalesce(cast(' || rtrim(:FIELD_NAME) || ' as varchar('||:FIELD_CHAR||')),'''')||''</' || rtrim(:FIELD_NAME) || '>''||';
      END
       else
      TMP = TMP || '''<' || rtrim(:FIELD_NAME) || '>''||' || rtrim(:FIELD_NAME) || '||''</' || rtrim(:FIELD_NAME) || '>''||';
    end
    XML = TMP||''''' FROM '||rtrim(:TABLE_NAME) || ' WHERE LAST_UPDATED>=(SELECT COALESCE(MAX(SAVEPOINT_DATETIME),''22.11.2004'') FROM APP_SAVEPOINTS WHERE IS_ACTIVE=''Y'')';
    RECORD_ID = 1;
    FOR EXECUTE STATEMENT :XML INTO :RES DO
     begin
      RES = '<RECORD id="'||:RECORD_ID||'">'||RES||'</RECORD>';
      SUSPEND;
      RECORD_ID = :RECORD_ID + 1;
     end
    RES = '</table>';
    SUSPEND;
 END
END


Таким образом, мы получаем все изменения, произошедшие в нужных нам таблицах с последней точки сохранения.
Структура полученного XML-файла
<export>
 <table>
   <table_name>Имя таблицы</table_name>
   <primary_key>Первичный ключ таблицы</primary_key>
   <record>Запись. Поля заранее неизвестны</record>
   ... все остальные записи
 </table>
 ... все остальные таблицы
</export>


Полученный XML нужно распарсить (это на завтра задание) и сделать insert/update


size=20   (2005-09-12 19:29:00) [1]


> А как такое может быть?

ну если конечно это генератор


Андрей Жук   (2005-09-12 19:27:00) [2]


> этот ключ на одной точке 10, а на другой 33 хотя это
> одна и таже запись.

А как такое может быть?


Андрей Жук   (2005-09-12 19:26:00) [3]

Ну бэкапы-то само-собой.

> Тяжело в бинарный файл выгрузить?

Так структура же такого файла заранее неизвестна. Появятся новые поля - ничего менять не придется.

Нашел у себя ошибку - не учитываются удаления.


size=20   (2005-09-12 19:25:00) [4]


>    <primary_key>Первичный ключ таблицы</primary_key>

этот ключ на одной точке 10, а на другой 33 хотя это одна и таже запись. Как ты их найдешь?
что делаешь при удалении записи?


Соловьев   (2005-09-12 19:22:00) [5]

Ав чем прикол XML? Чтобы легче жилось? Тяжело в бинарный файл выгрузить?
Тот же TClientDataSet и FIBPlus...


pasha_golub   (2005-09-12 19:04:00) [6]

Э-э-э, а если диск с БД навернется? вместе с бекапом...


Наверх

Титульная страница Поиск, карта сайта Написать письмо